ü{"files":{"main.js":{"size":13021,"integrity":{"algorithm":"SHA256","hash":"a270461d30359f9e4d1f1a140fcec41540768bc5189d5625d60a9c8e50effacc","blockSize":4194304,"blocks":["a270461d30359f9e4d1f1a140fcec41540768bc5189d5625d60a9c8e50effacc"]},"offset":"0"},"package.json":{"size":357,"integrity":{"algorithm":"SHA256","hash":"12fc84c3aea14e44a957339afee73366c13082a00358676f0138f7ee4f7612a3","blockSize":4194304,"blocks":["12fc84c3aea14e44a957339afee73366c13082a00358676f0138f7ee4f7612a3"]},"offset":"13021"},"node_modules":{"files":{"@electron":{"files":{"remote":{"files":{"LICENSE":{"size":1070,"integrity":{"algorithm":"SHA256","hash":"fc9ae4f3237a307eb111ef8f55bef41d90857e8d1500e592feb4e48639de7a82","blockSize":4194304,"blocks":["fc9ae4f3237a307eb111ef8f55bef41d90857e8d1500e592feb4e48639de7a82"]},"offset":"13378"},"package.json":{"size":1007,"integrity":{"algorithm":"SHA256","hash":"d547919043bca58be7649f253454b0e85a8a26e99dcbdfa37abd2d67f7fff87d","blockSize":4194304,"blocks":["d547919043bca58be7649f253454b0e85a8a26e99dcbdfa37abd2d67f7fff87d"]},"offset":"14448"},"renderer":{"files":{"index.js":{"size":49,"integrity":{"algorithm":"SHA256","hash":"2d84fc7d883b14e0f88b9ab83ff28a162a8d10ccfa4f758f940184941d531b82","blockSize":4194304,"blocks":["2d84fc7d883b14e0f88b9ab83ff28a162a8d10ccfa4f758f940184941d531b82"]},"offset":"15455"}}},"main":{"files":{"index.js":{"size":45,"integrity":{"algorithm":"SHA256","hash":"289679196b4b9ea379488a1e810e108f697b7c7e4e4c3a303f403af35482eb87","blockSize":4194304,"blocks":["289679196b4b9ea379488a1e810e108f697b7c7e4e4c3a303f403af35482eb87"]},"offset":"15504"}}},"dist":{"files":{"src":{"files":{"renderer":{"files":{"callbacks-registry.js":{"size":2104,"integrity":{"algorithm":"SHA256","hash":"14db4469fabeed645433a21fabe124f07a7b46e115829b170e9bb16aa77d5992","blockSize":4194304,"blocks":["14db4469fabeed645433a21fabe124f07a7b46e115829b170e9bb16aa77d5992"]},"offset":"15549"},"index.js":{"size":793,"integrity":{"algorithm":"SHA256","hash":"f459072159108ef7cc53cb8ca2bb1ce32d752393808165df92ef3708cfe01f54","blockSize":4194304,"blocks":["f459072159108ef7cc53cb8ca2bb1ce32d752393808165df92ef3708cfe01f54"]},"offset":"17653"},"remote.js":{"size":15587,"integrity":{"algorithm":"SHA256","hash":"4a2f10a871c0cb846b92e9b07de395b4e2a22564c38a05b1edeabcd35bddda93","blockSize":4194304,"blocks":["4a2f10a871c0cb846b92e9b07de395b4e2a22564c38a05b1edeabcd35bddda93"]},"offset":"18446"}}},"main":{"files":{"index.js":{"size":387,"integrity":{"algorithm":"SHA256","hash":"985866af0eece256132d03f6afce441e280d2ae2b81316fd69f0640e6114249c","blockSize":4194304,"blocks":["985866af0eece256132d03f6afce441e280d2ae2b81316fd69f0640e6114249c"]},"offset":"34033"},"objects-registry.js":{"size":4442,"integrity":{"algorithm":"SHA256","hash":"0312d21bd8da83d0384deab4c87cf7d8f3bbfa8424cd65e07e259d3044afd8d9","blockSize":4194304,"blocks":["0312d21bd8da83d0384deab4c87cf7d8f3bbfa8424cd65e07e259d3044afd8d9"]},"offset":"34420"},"server.js":{"size":21253,"integrity":{"algorithm":"SHA256","hash":"7e5592e2118cc06bf59a40e536cd121f45cd7d95756f8f71f65f7d9261542555","blockSize":4194304,"blocks":["7e5592e2118cc06bf59a40e536cd121f45cd7d95756f8f71f65f7d9261542555"]},"offset":"38862"}}},"common":{"files":{"get-electron-binding.js":{"size":441,"integrity":{"algorithm":"SHA256","hash":"f857a19eec43c9f8d97736c86057064c5b71fc14f6e773d1d7b1c268598bd309","blockSize":4194304,"blocks":["f857a19eec43c9f8d97736c86057064c5b71fc14f6e773d1d7b1c268598bd309"]},"offset":"60115"},"ipc-messages.js":{"size":77,"integrity":{"algorithm":"SHA256","hash":"d43aa81f5bc89faa359e0f97c814ba25155591ff078fbb9bfd40f8c7c9683230","blockSize":4194304,"blocks":["d43aa81f5bc89faa359e0f97c814ba25155591ff078fbb9bfd40f8c7c9683230"]},"offset":"60556"},"module-names.js":{"size":1239,"integrity":{"algorithm":"SHA256","hash":"157e41a801f70b6d29c7111024ccb1e5a9b2d6e75ccb7583fea4e71e578c52ed","blockSize":4194304,"blocks":["157e41a801f70b6d29c7111024ccb1e5a9b2d6e75ccb7583fea4e71e578c52ed"]},"offset":"60633"},"type-utils.js":{"size":4050,"integrity":{"algorithm":"SHA256","hash":"4e4e7bda21b242e517b9b1b582a15a45e8135bc7f7b1f0e9b33e56181dea3ee8","blockSize":4194304,"blocks":["4e4e7bda21b242e517b9b1b582a15a45e8135bc7f7b1f0e9b33e56181dea3ee8"]},"offset":"61872"}}}}}}}}}}},"node-addon-api":{"files":{".clang-format":{"size":3187,"integrity":{"algorithm":"SHA256","hash":"b8d85ed6a6cf95984aa4414ff9cfb355327772d8c3911e273a957d624bb77a7b","blockSize":4194304,"blocks":["b8d85ed6a6cf95984aa4414ff9cfb355327772d8c3911e273a957d624bb77a7b"]},"offset":"65922"},".editorconfig":{"size":130,"integrity":{"algorithm":"SHA256","hash":"5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269","blockSize":4194304,"blocks":["5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269"]},"offset":"69109"},"CODE_OF_CONDUCT.md":{"size":159,"integrity":{"algorithm":"SHA256","hash":"4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84","blockSize":4194304,"blocks":["4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84"]},"offset":"69239"},"CONTRIBUTING.md":{"size":3212,"integrity":{"algorithm":"SHA256","hash":"7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2","blockSize":4194304,"blocks":["7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2"]},"offset":"69398"},"LICENSE.md":{"size":1245,"integrity":{"algorithm":"SHA256","hash":"4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352","blockSize":4194304,"blocks":["4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352"]},"offset":"72610"},"common.gypi":{"size":762,"integrity":{"algorithm":"SHA256","hash":"f15742e3019096b85ef3e8985e2fe66c4dda722908577e113a1b0264893ecca8","blockSize":4194304,"blocks":["f15742e3019096b85ef3e8985e2fe66c4dda722908577e113a1b0264893ecca8"]},"offset":"73855"},"except.gypi":{"size":381,"integrity":{"algorithm":"SHA256","hash":"da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808","blockSize":4194304,"blocks":["da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808"]},"offset":"74617"},"index.js":{"size":296,"integrity":{"algorithm":"SHA256","hash":"6528e924b31e091c3243132fe713ea0f1fa6362ffaa3c2dd09d12670db6b60dc","blockSize":4194304,"blocks":["6528e924b31e091c3243132fe713ea0f1fa6362ffaa3c2dd09d12670db6b60dc"]},"offset":"74998"},"napi-inl.deprecated.h":{"size":7251,"integrity":{"algorithm":"SHA256","hash":"a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7","blockSize":4194304,"blocks":["a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7"]},"offset":"75294"},"napi-inl.h":{"size":185902,"integrity":{"algorithm":"SHA256","hash":"1366259f0dd74dcef5ec093543152c8727c3cbaf4099c2c32a8f1db398c03999","blockSize":4194304,"blocks":["1366259f0dd74dcef5ec093543152c8727c3cbaf4099c2c32a8f1db398c03999"]},"offset":"82545"},"napi.h":{"size":109629,"integrity":{"algorithm":"SHA256","hash":"5e2811ab3d78fc3335bd9ae326bd8e43867953bd779bf757d7579e925df37518","blockSize":4194304,"blocks":["5e2811ab3d78fc3335bd9ae326bd8e43867953bd779bf757d7579e925df37518"]},"offset":"268447"},"node_api.gyp":{"size":132,"integrity":{"algorithm":"SHA256","hash":"3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499","blockSize":4194304,"blocks":["3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499"]},"offset":"378076"},"noexcept.gypi":{"size":386,"integrity":{"algorithm":"SHA256","hash":"780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0","blockSize":4194304,"blocks":["780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0"]},"offset":"378208"},"nothing.c":{"size":0,"integrity":{"algorithm":"SHA256","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","blockSize":4194304,"blocks":[]},"offset":"378594"},"package-support.json":{"size":467,"integrity":{"algorithm":"SHA256","hash":"b1cb7da23cca1681c7392a3c889eb0cc4916c53d2d7692d4b654ae751f3442f3","blockSize":4194304,"blocks":["b1cb7da23cca1681c7392a3c889eb0cc4916c53d2d7692d4b654ae751f3442f3"]},"offset":"378594"},"package.json":{"size":642,"integrity":{"algorithm":"SHA256","hash":"0b84d05fe07bbe3c08fefd6c16b2835e13c88c595ce4fa4de6d161250c013157","blockSize":4194304,"blocks":["0b84d05fe07bbe3c08fefd6c16b2835e13c88c595ce4fa4de6d161250c013157"]},"offset":"379061"},"tools":{"files":{"README.md":{"size":3217,"integrity":{"algorithm":"SHA256","hash":"65e9ea918538f453166b10a1d609cf44cec3d2d01f23fecb5265fb3a4bf303d5","blockSize":4194304,"blocks":["65e9ea918538f453166b10a1d609cf44cec3d2d01f23fecb5265fb3a4bf303d5"]},"offset":"379703"},"check-napi.js":{"size":3210,"integrity":{"algorithm":"SHA256","hash":"f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b","blockSize":4194304,"blocks":["f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b"]},"offset":"382920"},"clang-format.js":{"size":1517,"integrity":{"algorithm":"SHA256","hash":"a57217d6c9a4cbdc7bfa7ad09b237b257c1bce2959d1c2698263dc608645592d","blockSize":4194304,"blocks":["a57217d6c9a4cbdc7bfa7ad09b237b257c1bce2959d1c2698263dc608645592d"]},"offset":"386130"},"conversion.js":{"size":15275,"integrity":{"algorithm":"SHA256","hash":"df2f681bdb4a1dac5faf7fa70a60dace4dd12ce0b9964effcee56a43f693fc6c","blockSize":4194304,"blocks":["df2f681bdb4a1dac5faf7fa70a60dace4dd12ce0b9964effcee56a43f693fc6c"]},"offset":"387647"}}},"doc":{"files":{"addon.md":{"size":5982,"integrity":{"algorithm":"SHA256","hash":"a4d33696bd3bcdadde3ef3402b0227752543dbe3291b53e153c5d08a09c3c6fe","blockSize":4194304,"blocks":["a4d33696bd3bcdadde3ef3402b0227752543dbe3291b53e153c5d08a09c3c6fe"]},"offset":"402922"},"array.md":{"size":2696,"integrity":{"algorithm":"SHA256","hash":"8658c1c517233842bbe09312d1cf363be5a735fc7162de0fb877ed6f277ae51b","blockSize":4194304,"blocks":["8658c1c517233842bbe09312d1cf363be5a735fc7162de0fb877ed6f277ae51b"]},"offset":"408904"},"array_buffer.md":{"size":4590,"integrity":{"algorithm":"SHA256","hash":"a4d2a7085b1314a48fee0edab9c27d95da2cf469b7eeccdb275811b5f5b2fd49","blockSize":4194304,"blocks":["a4d2a7085b1314a48fee0edab9c27d95da2cf469b7eeccdb275811b5f5b2fd49"]},"offset":"411600"},"async_context.md":{"size":2595,"integrity":{"algorithm":"SHA256","hash":"cb3e391d3a5921e3d237527d5c3dddfbfcff08244655cae9604761a768fc4df3","blockSize":4194304,"blocks":["cb3e391d3a5921e3d237527d5c3dddfbfcff08244655cae9604761a768fc4df3"]},"offset":"416190"},"async_operations.md":{"size":1369,"integrity":{"algorithm":"SHA256","hash":"2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1","blockSize":4194304,"blocks":["2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1"]},"offset":"418785"},"async_worker.md":{"size":14637,"integrity":{"algorithm":"SHA256","hash":"ceb8fdea9a46029b1f7fde15babfd1aff7d3189cd6ba1bdb81efaa39ed3382cd","blockSize":4194304,"blocks":["ceb8fdea9a46029b1f7fde15babfd1aff7d3189cd6ba1bdb81efaa39ed3382cd"]},"offset":"420154"},"async_worker_variants.md":{"size":20584,"integrity":{"algorithm":"SHA256","hash":"770b6b90c7ebc9d96bc6aa7ac593d8a525d581f7da380ba004414b6a5e28ea9c","blockSize":4194304,"blocks":["770b6b90c7ebc9d96bc6aa7ac593d8a525d581f7da380ba004414b6a5e28ea9c"]},"offset":"434791"},"bigint.md":{"size":2720,"integrity":{"algorithm":"SHA256","hash":"ed272bca594d83b41b950e6485142c3095b620909322cbaf63a678073baae02e","blockSize":4194304,"blocks":["ed272bca594d83b41b950e6485142c3095b620909322cbaf63a678073baae02e"]},"offset":"455375"},"boolean.md":{"size":1597,"integrity":{"algorithm":"SHA256","hash":"aadcb80d5b8cc1b67135893044405cd60a7abbe275688df753fe5a63605a7468","blockSize":4194304,"blocks":["aadcb80d5b8cc1b67135893044405cd60a7abbe275688df753fe5a63605a7468"]},"offset":"458095"},"buffer.md":{"size":4400,"integrity":{"algorithm":"SHA256","hash":"dfa3594026de8ca8bf422378e38e85ae0adb71db1ef20196f6f1282f4c75a32e","blockSize":4194304,"blocks":["dfa3594026de8ca8bf422378e38e85ae0adb71db1ef20196f6f1282f4c75a32e"]},"offset":"459692"},"callback_scope.md":{"size":1327,"integrity":{"algorithm":"SHA256","hash":"80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66","blockSize":4194304,"blocks":["80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66"]},"offset":"464092"},"callbackinfo.md":{"size":2547,"integrity":{"algorithm":"SHA256","hash":"45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e","blockSize":4194304,"blocks":["45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e"]},"offset":"465419"},"checker-tool.md":{"size":1024,"integrity":{"algorithm":"SHA256","hash":"8bcd4c725b51d74fb03a55f14d7ac40e25523df8dab83c8b9bd2002a74a71807","blockSize":4194304,"blocks":["8bcd4c725b51d74fb03a55f14d7ac40e25523df8dab83c8b9bd2002a74a71807"]},"offset":"467966"},"class_property_descriptor.md":{"size":3342,"integrity":{"algorithm":"SHA256","hash":"6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22","blockSize":4194304,"blocks":["6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22"]},"offset":"468990"},"cmake-js.md":{"size":3038,"integrity":{"algorithm":"SHA256","hash":"d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db","blockSize":4194304,"blocks":["d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db"]},"offset":"472332"},"conversion-tool.md":{"size":643,"integrity":{"algorithm":"SHA256","hash":"cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77","blockSize":4194304,"blocks":["cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77"]},"offset":"475370"},"creating_a_release.md":{"size":2228,"integrity":{"algorithm":"SHA256","hash":"5d643b171f4933e2693075907a3be0acd989ea3ff964cc96e99563bfab1468d6","blockSize":4194304,"blocks":["5d643b171f4933e2693075907a3be0acd989ea3ff964cc96e99563bfab1468d6"]},"offset":"476013"},"dataview.md":{"size":6743,"integrity":{"algorithm":"SHA256","hash":"ba4ae9e4ef331636df3b34b9cb86558b61f3c7925aa1804188d122f348e9ec92","blockSize":4194304,"blocks":["ba4ae9e4ef331636df3b34b9cb86558b61f3c7925aa1804188d122f348e9ec92"]},"offset":"478241"},"date.md":{"size":1581,"integrity":{"algorithm":"SHA256","hash":"f625d2e88ccb90e4bc2e711f97a7600f3af30aa36c218feb76644f5b9f2ad506","blockSize":4194304,"blocks":["f625d2e88ccb90e4bc2e711f97a7600f3af30aa36c218feb76644f5b9f2ad506"]},"offset":"484984"},"env.md":{"size":3871,"integrity":{"algorithm":"SHA256","hash":"1eff44d974e28a93c395ad9b69a21f30582825d2b6a35cad1ba67a6f643a5d31","blockSize":4194304,"blocks":["1eff44d974e28a93c395ad9b69a21f30582825d2b6a35cad1ba67a6f643a5d31"]},"offset":"486565"},"error.md":{"size":3265,"integrity":{"algorithm":"SHA256","hash":"9b3dc5a9a5398e6c12a750076d8748d77c0fd67c40f8a718999f09a928409eaf","blockSize":4194304,"blocks":["9b3dc5a9a5398e6c12a750076d8748d77c0fd67c40f8a718999f09a928409eaf"]},"offset":"490436"},"error_handling.md":{"size":7199,"integrity":{"algorithm":"SHA256","hash":"38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64","blockSize":4194304,"blocks":["38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64"]},"offset":"493701"},"escapable_handle_scope.md":{"size":2626,"integrity":{"algorithm":"SHA256","hash":"9400988d7db9e4e7a03786881774864e50a07da926638e05dd29660b01000bae","blockSize":4194304,"blocks":["9400988d7db9e4e7a03786881774864e50a07da926638e05dd29660b01000bae"]},"offset":"500900"},"external.md":{"size":2403,"integrity":{"algorithm":"SHA256","hash":"b39abf983af138bfbec0b9c3f01ae1517586c4e634ca58384d8820ffb886eadf","blockSize":4194304,"blocks":["b39abf983af138bfbec0b9c3f01ae1517586c4e634ca58384d8820ffb886eadf"]},"offset":"503526"},"function.md":{"size":12965,"integrity":{"algorithm":"SHA256","hash":"6eb75211757387461a615c3237b5d20379da4dadf08938e37af83a1c5bbc76fe","blockSize":4194304,"blocks":["6eb75211757387461a615c3237b5d20379da4dadf08938e37af83a1c5bbc76fe"]},"offset":"505929"},"function_reference.md":{"size":8076,"integrity":{"algorithm":"SHA256","hash":"4fc5d469555e52891137e94d536ab75e29a9826e7966290eab3dd3c86aca57f1","blockSize":4194304,"blocks":["4fc5d469555e52891137e94d536ab75e29a9826e7966290eab3dd3c86aca57f1"]},"offset":"518894"},"generator.md":{"size":578,"integrity":{"algorithm":"SHA256","hash":"9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32","blockSize":4194304,"blocks":["9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32"]},"offset":"526970"},"handle_scope.md":{"size":1887,"integrity":{"algorithm":"SHA256","hash":"7e0957319a5afe474acb3f8f6b32cc75481df4bb8384128e6f6cfd76d242ae21","blockSize":4194304,"blocks":["7e0957319a5afe474acb3f8f6b32cc75481df4bb8384128e6f6cfd76d242ae21"]},"offset":"527548"},"hierarchy.md":{"size":3811,"integrity":{"algorithm":"SHA256","hash":"02cbdafaa934727bb3f0d165141eec85d806e65935b141edaf30574c550fd7a4","blockSize":4194304,"blocks":["02cbdafaa934727bb3f0d165141eec85d806e65935b141edaf30574c550fd7a4"]},"offset":"529435"},"instance_wrap.md":{"size":15183,"integrity":{"algorithm":"SHA256","hash":"213a42b10138b01d2b36daf51d030a06cfa015c17eaea7cbd9f563db3e93a0fc","blockSize":4194304,"blocks":["213a42b10138b01d2b36daf51d030a06cfa015c17eaea7cbd9f563db3e93a0fc"]},"offset":"533246"},"memory_management.md":{"size":1117,"integrity":{"algorithm":"SHA256","hash":"7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf","blockSize":4194304,"blocks":["7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf"]},"offset":"548429"},"name.md":{"size":657,"integrity":{"algorithm":"SHA256","hash":"fb33c4eac02fa5340900245d17f582997e5521c5ee4a07dbfd4f68dba8490fc6","blockSize":4194304,"blocks":["fb33c4eac02fa5340900245d17f582997e5521c5ee4a07dbfd4f68dba8490fc6"]},"offset":"549546"},"node-gyp.md":{"size":2990,"integrity":{"algorithm":"SHA256","hash":"076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d","blockSize":4194304,"blocks":["076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d"]},"offset":"550203"},"number.md":{"size":3648,"integrity":{"algorithm":"SHA256","hash":"9fb062f05f9de0b85216c115448b41a58594b5126fcb009a8137a4202d0450c0","blockSize":4194304,"blocks":["9fb062f05f9de0b85216c115448b41a58594b5126fcb009a8137a4202d0450c0"]},"offset":"553193"},"object.md":{"size":7784,"integrity":{"algorithm":"SHA256","hash":"eff201f284f0d435c74020e80008b7878d4d7471bc22d77e743ffa0ecb931122","blockSize":4194304,"blocks":["eff201f284f0d435c74020e80008b7878d4d7471bc22d77e743ffa0ecb931122"]},"offset":"556841"},"object_lifetime_management.md":{"size":3899,"integrity":{"algorithm":"SHA256","hash":"c86d7b24783f52650f0f2be94dd298d810e636d5a0f522af4d26e9bef3af6fa4","blockSize":4194304,"blocks":["c86d7b24783f52650f0f2be94dd298d810e636d5a0f522af4d26e9bef3af6fa4"]},"offset":"564625"},"object_reference.md":{"size":3414,"integrity":{"algorithm":"SHA256","hash":"86f53e9a5246bdacda8b8944e5409847b86823572a577950751b4066e13f7e7b","blockSize":4194304,"blocks":["86f53e9a5246bdacda8b8944e5409847b86823572a577950751b4066e13f7e7b"]},"offset":"568524"},"object_wrap.md":{"size":21120,"integrity":{"algorithm":"SHA256","hash":"1387bde68b24d9bbb91d7a58fe2d90d052e64e92b440f62c67321f5a220bd904","blockSize":4194304,"blocks":["1387bde68b24d9bbb91d7a58fe2d90d052e64e92b440f62c67321f5a220bd904"]},"offset":"571938"},"prebuild_tools.md":{"size":869,"integrity":{"algorithm":"SHA256","hash":"34eb25b25c27be0d5c61580d27165b89e61db22c2f2a7a9f6a8c30edd77fb8c4","blockSize":4194304,"blocks":["34eb25b25c27be0d5c61580d27165b89e61db22c2f2a7a9f6a8c30edd77fb8c4"]},"offset":"593058"},"promises.md":{"size":2121,"integrity":{"algorithm":"SHA256","hash":"0d5faec124f7ce914c35ec10733e4c0dd61230c7a7f1d98c5033a958f08f469e","blockSize":4194304,"blocks":["0d5faec124f7ce914c35ec10733e4c0dd61230c7a7f1d98c5033a958f08f469e"]},"offset":"593927"},"property_descriptor.md":{"size":9700,"integrity":{"algorithm":"SHA256","hash":"22063fe37cd544ab5099b504b6b3f9973230b82a22c8ace9158a0bd4ee6f4061","blockSize":4194304,"blocks":["22063fe37cd544ab5099b504b6b3f9973230b82a22c8ace9158a0bd4ee6f4061"]},"offset":"596048"},"range_error.md":{"size":1684,"integrity":{"algorithm":"SHA256","hash":"dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de","blockSize":4194304,"blocks":["dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de"]},"offset":"605748"},"reference.md":{"size":2971,"integrity":{"algorithm":"SHA256","hash":"b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9","blockSize":4194304,"blocks":["b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9"]},"offset":"607432"},"setup.md":{"size":2230,"integrity":{"algorithm":"SHA256","hash":"908471e593b7d4f300ac368d55797bd22aa8705ae23eedd997e3c573c81a9af6","blockSize":4194304,"blocks":["908471e593b7d4f300ac368d55797bd22aa8705ae23eedd997e3c573c81a9af6"]},"offset":"610403"},"string.md":{"size":2562,"integrity":{"algorithm":"SHA256","hash":"c5dc03fe2513b62cf08909d3303a31923dc62d3aa5d1a0ef115c6ed5e8554438","blockSize":4194304,"blocks":["c5dc03fe2513b62cf08909d3303a31923dc62d3aa5d1a0ef115c6ed5e8554438"]},"offset":"612633"},"symbol.md":{"size":1491,"integrity":{"algorithm":"SHA256","hash":"feb23a93a34a371c4b2b7671830dd1ea13d3a1d24243dfd1901a6c0827fdbb45","blockSize":4194304,"blocks":["feb23a93a34a371c4b2b7671830dd1ea13d3a1d24243dfd1901a6c0827fdbb45"]},"offset":"615195"},"threadsafe.md":{"size":6933,"integrity":{"algorithm":"SHA256","hash":"6f3b797582dd72eb3c4e5f2dd1d9208387d85f5d22bcf9488ed325d0fa9826f5","blockSize":4194304,"blocks":["6f3b797582dd72eb3c4e5f2dd1d9208387d85f5d22bcf9488ed325d0fa9826f5"]},"offset":"616686"},"threadsafe_function.md":{"size":10110,"integrity":{"algorithm":"SHA256","hash":"5901cfcdcccad1546676bb27638e7e6a8d9e2a06a847c60893d2b92aa5d907a6","blockSize":4194304,"blocks":["5901cfcdcccad1546676bb27638e7e6a8d9e2a06a847c60893d2b92aa5d907a6"]},"offset":"623619"},"type_error.md":{"size":1669,"integrity":{"algorithm":"SHA256","hash":"eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f","blockSize":4194304,"blocks":["eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f"]},"offset":"633729"},"typed_array.md":{"size":1487,"integrity":{"algorithm":"SHA256","hash":"9adc6f2442947fc51f83123c3442f7b248f916945a466fa301a7cd971a255b37","blockSize":4194304,"blocks":["9adc6f2442947fc51f83123c3442f7b248f916945a466fa301a7cd971a255b37"]},"offset":"635398"},"typed_array_of.md":{"size":3919,"integrity":{"algorithm":"SHA256","hash":"3fb4974cac0f5764277278d81fcd892bc95ad3cda29ca7acea91eb9c96ac9e28","blockSize":4194304,"blocks":["3fb4974cac0f5764277278d81fcd892bc95ad3cda29ca7acea91eb9c96ac9e28"]},"offset":"636885"},"typed_threadsafe_function.md":{"size":10817,"integrity":{"algorithm":"SHA256","hash":"43204255b79558d77592091aad3ae72b80cd89de49dd0ecbfaf65e44c897f81c","blockSize":4194304,"blocks":["43204255b79558d77592091aad3ae72b80cd89de49dd0ecbfaf65e44c897f81c"]},"offset":"640804"},"value.md":{"size":7662,"integrity":{"algorithm":"SHA256","hash":"b30a22d9302cd624c619acaa74aae6ce19a6178fb4fb235470a635fb5544287e","blockSize":4194304,"blocks":["b30a22d9302cd624c619acaa74aae6ce19a6178fb4fb235470a635fb5544287e"]},"offset":"651621"},"version_management.md":{"size":1154,"integrity":{"algorithm":"SHA256","hash":"42af08b2cd9fd604110ab5d167f9560d4893127b9ffdbb08cb954c4e82112219","blockSize":4194304,"blocks":["42af08b2cd9fd604110ab5d167f9560d4893127b9ffdbb08cb954c4e82112219"]},"offset":"659283"}}},"benchmark":{"files":{"README.md":{"size":1526,"integrity":{"algorithm":"SHA256","hash":"bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef","blockSize":4194304,"blocks":["bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef"]},"offset":"660437"},"function_args.js":{"size":2138,"integrity":{"algorithm":"SHA256","hash":"ead07f544bb2c5e1de2cabf7ab2c4bd4da00e31a5b89da2833c1d5d3806b3101","blockSize":4194304,"blocks":["ead07f544bb2c5e1de2cabf7ab2c4bd4da00e31a5b89da2833c1d5d3806b3101"]},"offset":"661963"},"index.js":{"size":971,"integrity":{"algorithm":"SHA256","hash":"34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e","blockSize":4194304,"blocks":["34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e"]},"offset":"664101"},"property_descriptor.js":{"size":1051,"integrity":{"algorithm":"SHA256","hash":"a40421341e2937a677504f365ad41da8d001b72b4988a49de2c773f273b175fd","blockSize":4194304,"blocks":["a40421341e2937a677504f365ad41da8d001b72b4988a49de2c773f273b175fd"]},"offset":"665072"}}},".github":{"files":{"workflows":{"files":{"ci.yml":{"size":1707,"integrity":{"algorithm":"SHA256","hash":"27e59c751fe17c2ca8e40b5571e929186228dca5098fa44b45fe74e51884f178","blockSize":4194304,"blocks":["27e59c751fe17c2ca8e40b5571e929186228dca5098fa44b45fe74e51884f178"]},"offset":"666123"},"linter.yml":{"size":571,"integrity":{"algorithm":"SHA256","hash":"164e4f5a2ece825780d5fa3180b35cb5a7684ba883dd72b6d2a7e282e64dd2a1","blockSize":4194304,"blocks":["164e4f5a2ece825780d5fa3180b35cb5a7684ba883dd72b6d2a7e282e64dd2a1"]},"offset":"667830"},"stale.yml":{"size":529,"integrity":{"algorithm":"SHA256","hash":"a2c79f281f051551472acb8923fb0155e1b295a3b5a528d51df3558ad65c02d9","blockSize":4194304,"blocks":["a2c79f281f051551472acb8923fb0155e1b295a3b5a528d51df3558ad65c02d9"]},"offset":"668401"}}}}}}},"btime":{"files":{"binding.node":{"size":121344,"integrity":{"algorithm":"SHA256","hash":"98c51303c38dc03faeeba13f26fa3c6645d0c1a502b8a5d28177ce015dacf35f","blockSize":4194304,"blocks":["98c51303c38dc03faeeba13f26fa3c6645d0c1a502b8a5d28177ce015dacf35f"]},"unpacked":true},"index.js":{"size":1792,"integrity":{"algorithm":"SHA256","hash":"ebe780273f9c6f7707f2e2dfc82ec7e6de8b4ecaa5216c5c35d08e0782d7ab40","blockSize":4194304,"blocks":["ebe780273f9c6f7707f2e2dfc82ec7e6de8b4ecaa5216c5c35d08e0782d7ab40"]},"offset":"668930"},"package.json":{"size":299,"integrity":{"algorithm":"SHA256","hash":"17245bcf072bfd493bbbc97e20084e53586298d9f24d13aebde04ad698440679","blockSize":4194304,"blocks":["17245bcf072bfd493bbbc97e20084e53586298d9f24d13aebde04ad698440679"]},"offset":"670722"},"node_modules":{"files":{"node-addon-api":{"files":{".editorconfig":{"size":130,"integrity":{"algorithm":"SHA256","hash":"5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269","blockSize":4194304,"blocks":["5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269"]},"offset":"673483"},"CODE_OF_CONDUCT.md":{"size":159,"integrity":{"algorithm":"SHA256","hash":"4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84","blockSize":4194304,"blocks":["4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84"]},"offset":"673613"},"CONTRIBUTING.md":{"size":3212,"integrity":{"algorithm":"SHA256","hash":"7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2","blockSize":4194304,"blocks":["7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2"]},"offset":"673772"},"LICENSE.md":{"size":1245,"integrity":{"algorithm":"SHA256","hash":"4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352","blockSize":4194304,"blocks":["4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352"]},"offset":"676984"},"common.gypi":{"size":759,"integrity":{"algorithm":"SHA256","hash":"4afdd3edf761e2e8fc437ef446a761e2eda230c694ce3ff11c98455a99b31545","blockSize":4194304,"blocks":["4afdd3edf761e2e8fc437ef446a761e2eda230c694ce3ff11c98455a99b31545"]},"offset":"678229"},"except.gypi":{"size":381,"integrity":{"algorithm":"SHA256","hash":"da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808","blockSize":4194304,"blocks":["da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808"]},"offset":"678988"},"index.js":{"size":180,"integrity":{"algorithm":"SHA256","hash":"6bead8bf429a500d09b9c730e6c1ad0bd548d80e4b906946ab842442fc639899","blockSize":4194304,"blocks":["6bead8bf429a500d09b9c730e6c1ad0bd548d80e4b906946ab842442fc639899"]},"offset":"679369"},"napi-inl.deprecated.h":{"size":7251,"integrity":{"algorithm":"SHA256","hash":"a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7","blockSize":4194304,"blocks":["a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7"]},"offset":"679549"},"napi-inl.h":{"size":163184,"integrity":{"algorithm":"SHA256","hash":"0caecc362536448e5e50165d25e5a9b662b8da270d50cf0ae8884b2dc23c6b9e","blockSize":4194304,"blocks":["0caecc362536448e5e50165d25e5a9b662b8da270d50cf0ae8884b2dc23c6b9e"]},"offset":"686800"},"napi.h":{"size":102676,"integrity":{"algorithm":"SHA256","hash":"b26b3d86d6a1aef2bf8e4aca6cf9aa06fe5cdf6246fc73e0bf8ee1e3c041302f","blockSize":4194304,"blocks":["b26b3d86d6a1aef2bf8e4aca6cf9aa06fe5cdf6246fc73e0bf8ee1e3c041302f"]},"offset":"849984"},"node_api.gyp":{"size":132,"integrity":{"algorithm":"SHA256","hash":"3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499","blockSize":4194304,"blocks":["3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499"]},"offset":"952660"},"noexcept.gypi":{"size":386,"integrity":{"algorithm":"SHA256","hash":"780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0","blockSize":4194304,"blocks":["780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0"]},"offset":"952792"},"nothing.c":{"size":0,"integrity":{"algorithm":"SHA256","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","blockSize":4194304,"blocks":[]},"offset":"953178"},"nothing.vcxproj":{"size":10841,"integrity":{"algorithm":"SHA256","hash":"735b6bd0ce027d91e51028fbda773116af72b3d532a7f52c6cc1650efce23932","blockSize":4194304,"blocks":["735b6bd0ce027d91e51028fbda773116af72b3d532a7f52c6cc1650efce23932"]},"offset":"953178"},"nothing.vcxproj.filters":{"size":1362,"integrity":{"algorithm":"SHA256","hash":"917ac1a062cb9099768c4f61caa1f5259b81fe259912cb4321bee4017bbdad25","blockSize":4194304,"blocks":["917ac1a062cb9099768c4f61caa1f5259b81fe259912cb4321bee4017bbdad25"]},"offset":"964019"},"package.json":{"size":489,"integrity":{"algorithm":"SHA256","hash":"c468676fdcb17605b523059d3a6ec11bcd45a860b1c9b5a8ae0443ed4e5c6212","blockSize":4194304,"blocks":["c468676fdcb17605b523059d3a6ec11bcd45a860b1c9b5a8ae0443ed4e5c6212"]},"offset":"965381"},"tools":{"files":{"README.md":{"size":3189,"integrity":{"algorithm":"SHA256","hash":"997216a451923f84cb4f837af1493d10970efe1cde11771e4c0d3304ed594d70","blockSize":4194304,"blocks":["997216a451923f84cb4f837af1493d10970efe1cde11771e4c0d3304ed594d70"]},"offset":"965870"},"check-napi.js":{"size":3210,"integrity":{"algorithm":"SHA256","hash":"f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b","blockSize":4194304,"blocks":["f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b"]},"offset":"969059"},"conversion.js":{"size":15263,"integrity":{"algorithm":"SHA256","hash":"8588ac5c45cca9215ce039e483831899dc2d06d8bc0569d53d6b81dd2baff06a","blockSize":4194304,"blocks":["8588ac5c45cca9215ce039e483831899dc2d06d8bc0569d53d6b81dd2baff06a"]},"offset":"972269"}}},"doc":{"files":{"Doxyfile":{"size":107062,"integrity":{"algorithm":"SHA256","hash":"00daa8fe238b66f78254d94764b2ad631bdd7738b4d09c4a4e6b7a9e2281c1b0","blockSize":4194304,"blocks":["00daa8fe238b66f78254d94764b2ad631bdd7738b4d09c4a4e6b7a9e2281c1b0"]},"offset":"987532"},"array_buffer.md":{"size":4230,"integrity":{"algorithm":"SHA256","hash":"6ea03468ac21e9d70846de85cc507621a3746bee10bfc4aed502659891151ec0","blockSize":4194304,"blocks":["6ea03468ac21e9d70846de85cc507621a3746bee10bfc4aed502659891151ec0"]},"offset":"1094594"},"async_context.md":{"size":2594,"integrity":{"algorithm":"SHA256","hash":"cbbfcbe8dffa0f9c74648e6e6b683abc2a25b09ee1e71d65f8c5f8251ae48ff8","blockSize":4194304,"blocks":["cbbfcbe8dffa0f9c74648e6e6b683abc2a25b09ee1e71d65f8c5f8251ae48ff8"]},"offset":"1098824"},"async_operations.md":{"size":1369,"integrity":{"algorithm":"SHA256","hash":"2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1","blockSize":4194304,"blocks":["2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1"]},"offset":"1101418"},"async_worker.md":{"size":14636,"integrity":{"algorithm":"SHA256","hash":"1c836f79358dca3e178b7393a12a786d3e479827a84af107d29e09b56605f35e","blockSize":4194304,"blocks":["1c836f79358dca3e178b7393a12a786d3e479827a84af107d29e09b56605f35e"]},"offset":"1102787"},"async_worker_variants.md":{"size":16873,"integrity":{"algorithm":"SHA256","hash":"50f5a4ddbbf60a660dbbdaf1794df996bc0f05c06675fee3d2ff1a49ce38ea70","blockSize":4194304,"blocks":["50f5a4ddbbf60a660dbbdaf1794df996bc0f05c06675fee3d2ff1a49ce38ea70"]},"offset":"1117423"},"basic_types.md":{"size":11548,"integrity":{"algorithm":"SHA256","hash":"34f789a82686fe3fdf74407b3f6c38e21e75b392244a5913e42a8478ddf9da77","blockSize":4194304,"blocks":["34f789a82686fe3fdf74407b3f6c38e21e75b392244a5913e42a8478ddf9da77"]},"offset":"1134296"},"bigint.md":{"size":2630,"integrity":{"algorithm":"SHA256","hash":"8c700300e13170556e2b2e3b6f6a2e3066e8e23a8b28c09bb7e6e7dd3334df48","blockSize":4194304,"blocks":["8c700300e13170556e2b2e3b6f6a2e3066e8e23a8b28c09bb7e6e7dd3334df48"]},"offset":"1145844"},"boolean.md":{"size":1505,"integrity":{"algorithm":"SHA256","hash":"29c855fbb12e24ab5b473d26210b66e771f75ac17a098c3af2d11ecc5513f639","blockSize":4194304,"blocks":["29c855fbb12e24ab5b473d26210b66e771f75ac17a098c3af2d11ecc5513f639"]},"offset":"1148474"},"buffer.md":{"size":4291,"integrity":{"algorithm":"SHA256","hash":"c2dcb410d7bfb2a8f1c24aae3941dca2b4a8bd81cce43818ca0fcd3542e1f751","blockSize":4194304,"blocks":["c2dcb410d7bfb2a8f1c24aae3941dca2b4a8bd81cce43818ca0fcd3542e1f751"]},"offset":"1149979"},"callback_scope.md":{"size":1327,"integrity":{"algorithm":"SHA256","hash":"80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66","blockSize":4194304,"blocks":["80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66"]},"offset":"1154270"},"callbackinfo.md":{"size":2547,"integrity":{"algorithm":"SHA256","hash":"45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e","blockSize":4194304,"blocks":["45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e"]},"offset":"1155597"},"checker-tool.md":{"size":1025,"integrity":{"algorithm":"SHA256","hash":"02d7e39a45b395da628484d2a721418763e9ec44e656ac745107aa633d0f9319","blockSize":4194304,"blocks":["02d7e39a45b395da628484d2a721418763e9ec44e656ac745107aa633d0f9319"]},"offset":"1158144"},"class_property_descriptor.md":{"size":3342,"integrity":{"algorithm":"SHA256","hash":"6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22","blockSize":4194304,"blocks":["6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22"]},"offset":"1159169"},"cmake-js.md":{"size":3038,"integrity":{"algorithm":"SHA256","hash":"d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db","blockSize":4194304,"blocks":["d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db"]},"offset":"1162511"},"conversion-tool.md":{"size":643,"integrity":{"algorithm":"SHA256","hash":"cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77","blockSize":4194304,"blocks":["cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77"]},"offset":"1165549"},"creating_a_release.md":{"size":2227,"integrity":{"algorithm":"SHA256","hash":"3d9f0e8d754664a8ade39b1579be1f0276fd7b2fa6b1507041a801ee5c4f3035","blockSize":4194304,"blocks":["3d9f0e8d754664a8ade39b1579be1f0276fd7b2fa6b1507041a801ee5c4f3035"]},"offset":"1166192"},"dataview.md":{"size":6648,"integrity":{"algorithm":"SHA256","hash":"a147987e3ca068605790ef75b7bbe518494e38219b4ad148149e3c296247242b","blockSize":4194304,"blocks":["a147987e3ca068605790ef75b7bbe518494e38219b4ad148149e3c296247242b"]},"offset":"1168419"},"date.md":{"size":1576,"integrity":{"algorithm":"SHA256","hash":"98bf821baa0c942fa980fc23c475019438d5dd28399b6c7a98488f06d5c0546a","blockSize":4194304,"blocks":["98bf821baa0c942fa980fc23c475019438d5dd28399b6c7a98488f06d5c0546a"]},"offset":"1175067"},"env.md":{"size":1607,"integrity":{"algorithm":"SHA256","hash":"6c1bc45ab92e80679a27af50b76e3a0b1eb0fbea4c41868b3c1efae190da32b2","blockSize":4194304,"blocks":["6c1bc45ab92e80679a27af50b76e3a0b1eb0fbea4c41868b3c1efae190da32b2"]},"offset":"1176643"},"error.md":{"size":3041,"integrity":{"algorithm":"SHA256","hash":"b1230fcfaa1576bb0bd1db18402d91c69016ce0dfcb1a48d0ef1a6043656e538","blockSize":4194304,"blocks":["b1230fcfaa1576bb0bd1db18402d91c69016ce0dfcb1a48d0ef1a6043656e538"]},"offset":"1178250"},"error_handling.md":{"size":7199,"integrity":{"algorithm":"SHA256","hash":"38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64","blockSize":4194304,"blocks":["38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64"]},"offset":"1181291"},"escapable_handle_scope.md":{"size":2627,"integrity":{"algorithm":"SHA256","hash":"db64799a3b615aff017c43eda021bb37a1377380b45f0f013bfbed3a705ccdbd","blockSize":4194304,"blocks":["db64799a3b615aff017c43eda021bb37a1377380b45f0f013bfbed3a705ccdbd"]},"offset":"1188490"},"external.md":{"size":2308,"integrity":{"algorithm":"SHA256","hash":"8df1508fd119b188782d3a10fcf933d75dee4105872edb00da571d5bd8a5a8e5","blockSize":4194304,"blocks":["8df1508fd119b188782d3a10fcf933d75dee4105872edb00da571d5bd8a5a8e5"]},"offset":"1191117"},"function.md":{"size":12945,"integrity":{"algorithm":"SHA256","hash":"79dbbbd25dcf395bf2b06b37724e8cbf636b80c9eef0ea3c741b5290b3f7cc46","blockSize":4194304,"blocks":["79dbbbd25dcf395bf2b06b37724e8cbf636b80c9eef0ea3c741b5290b3f7cc46"]},"offset":"1193425"},"function_reference.md":{"size":8075,"integrity":{"algorithm":"SHA256","hash":"5434c14c1b44902046d4850b0e48ddc5f62dfbdf3773f9bc5d1393a7aeabc509","blockSize":4194304,"blocks":["5434c14c1b44902046d4850b0e48ddc5f62dfbdf3773f9bc5d1393a7aeabc509"]},"offset":"1206370"},"generator.md":{"size":578,"integrity":{"algorithm":"SHA256","hash":"9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32","blockSize":4194304,"blocks":["9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32"]},"offset":"1214445"},"handle_scope.md":{"size":1888,"integrity":{"algorithm":"SHA256","hash":"d51565397599fffdbe1e2f521452084f7392bc313ae5e8c40cb6b9e69a466606","blockSize":4194304,"blocks":["d51565397599fffdbe1e2f521452084f7392bc313ae5e8c40cb6b9e69a466606"]},"offset":"1215023"},"memory_management.md":{"size":1117,"integrity":{"algorithm":"SHA256","hash":"7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf","blockSize":4194304,"blocks":["7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf"]},"offset":"1216911"},"node-gyp.md":{"size":2990,"integrity":{"algorithm":"SHA256","hash":"076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d","blockSize":4194304,"blocks":["076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d"]},"offset":"1218028"},"number.md":{"size":3647,"integrity":{"algorithm":"SHA256","hash":"9b55e63f7e694940d8ebe59b8dbf52b09d5587e12c726d5e808b54c0bd45b3cf","blockSize":4194304,"blocks":["9b55e63f7e694940d8ebe59b8dbf52b09d5587e12c726d5e808b54c0bd45b3cf"]},"offset":"1221018"},"object.md":{"size":7765,"integrity":{"algorithm":"SHA256","hash":"1074d5fb077684e72e26b65bc35e39569ae213719ddd8db8485e2ab98d131c33","blockSize":4194304,"blocks":["1074d5fb077684e72e26b65bc35e39569ae213719ddd8db8485e2ab98d131c33"]},"offset":"1224665"},"object_lifetime_management.md":{"size":3900,"integrity":{"algorithm":"SHA256","hash":"e7a498747f4af4e6afc7f3e95b8288788ecf93838025d4b52f07958edba5952f","blockSize":4194304,"blocks":["e7a498747f4af4e6afc7f3e95b8288788ecf93838025d4b52f07958edba5952f"]},"offset":"1232430"},"object_reference.md":{"size":3414,"integrity":{"algorithm":"SHA256","hash":"121bca9f7e2f11a1400d4c4f10f9baa8858d2ade917490603e2fc0fdfc97f2fc","blockSize":4194304,"blocks":["121bca9f7e2f11a1400d4c4f10f9baa8858d2ade917490603e2fc0fdfc97f2fc"]},"offset":"1236330"},"object_wrap.md":{"size":33620,"integrity":{"algorithm":"SHA256","hash":"49945c5ed9a53cdf5b8e6506cd78a77375e40f4f4948eeefe620d71892aca702","blockSize":4194304,"blocks":["49945c5ed9a53cdf5b8e6506cd78a77375e40f4f4948eeefe620d71892aca702"]},"offset":"1239744"},"prebuild_tools.md":{"size":868,"integrity":{"algorithm":"SHA256","hash":"83b58258f42058b4614cffeddec2e1377dcc1b91e30bbe6daa0eb0e288ac26fe","blockSize":4194304,"blocks":["83b58258f42058b4614cffeddec2e1377dcc1b91e30bbe6daa0eb0e288ac26fe"]},"offset":"1273364"},"promises.md":{"size":2026,"integrity":{"algorithm":"SHA256","hash":"5d7e6f4ebf701bed724ca19669ac5b6ea4c37453e48b3aafc4f2243d57bb62f9","blockSize":4194304,"blocks":["5d7e6f4ebf701bed724ca19669ac5b6ea4c37453e48b3aafc4f2243d57bb62f9"]},"offset":"1274232"},"property_descriptor.md":{"size":9699,"integrity":{"algorithm":"SHA256","hash":"5cc3cd685e09acc8ed23aa8f70f83c3fe397f7b808c5d461c0ca99d0a9aed62c","blockSize":4194304,"blocks":["5cc3cd685e09acc8ed23aa8f70f83c3fe397f7b808c5d461c0ca99d0a9aed62c"]},"offset":"1276258"},"range_error.md":{"size":1684,"integrity":{"algorithm":"SHA256","hash":"dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de","blockSize":4194304,"blocks":["dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de"]},"offset":"1285957"},"reference.md":{"size":2971,"integrity":{"algorithm":"SHA256","hash":"b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9","blockSize":4194304,"blocks":["b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9"]},"offset":"1287641"},"setup.md":{"size":2227,"integrity":{"algorithm":"SHA256","hash":"065b15b7bd6bb21b603bf4ab55491032fe43dbb6ae7005743d9ea562fa5edde1","blockSize":4194304,"blocks":["065b15b7bd6bb21b603bf4ab55491032fe43dbb6ae7005743d9ea562fa5edde1"]},"offset":"1290612"},"string.md":{"size":2475,"integrity":{"algorithm":"SHA256","hash":"1e257b02598494f13958322a60de1ae9155792c63016ae621a1cb39c84461eba","blockSize":4194304,"blocks":["1e257b02598494f13958322a60de1ae9155792c63016ae621a1cb39c84461eba"]},"offset":"1292839"},"symbol.md":{"size":1404,"integrity":{"algorithm":"SHA256","hash":"8f6f22459ed0ddd535422dac4eea07c7d4c927d40c0848b354a23410ae266cd2","blockSize":4194304,"blocks":["8f6f22459ed0ddd535422dac4eea07c7d4c927d40c0848b354a23410ae266cd2"]},"offset":"1295314"},"threadsafe_function.md":{"size":11960,"integrity":{"algorithm":"SHA256","hash":"46a53cbe8fae2fb8622433c751681647a459e0a75eea5bbf0e331aad22965aa7","blockSize":4194304,"blocks":["46a53cbe8fae2fb8622433c751681647a459e0a75eea5bbf0e331aad22965aa7"]},"offset":"1296718"},"type_error.md":{"size":1669,"integrity":{"algorithm":"SHA256","hash":"eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f","blockSize":4194304,"blocks":["eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f"]},"offset":"1308678"},"typed_array.md":{"size":1390,"integrity":{"algorithm":"SHA256","hash":"cac21e9c039b38fcc165c2d190547fadcf3997bac7bfd5f2b011a73d642ec5a8","blockSize":4194304,"blocks":["cac21e9c039b38fcc165c2d190547fadcf3997bac7bfd5f2b011a73d642ec5a8"]},"offset":"1310347"},"typed_array_of.md":{"size":3804,"integrity":{"algorithm":"SHA256","hash":"991996c3ba6a895b27859864ec8ca288f4947f899429ce42ffe1511ca43f33c7","blockSize":4194304,"blocks":["991996c3ba6a895b27859864ec8ca288f4947f899429ce42ffe1511ca43f33c7"]},"offset":"1311737"},"value.md":{"size":6156,"integrity":{"algorithm":"SHA256","hash":"d25880763a004012680a29ed2f43e77c635fec909eb200b5a70487bec3d11c2e","blockSize":4194304,"blocks":["d25880763a004012680a29ed2f43e77c635fec909eb200b5a70487bec3d11c2e"]},"offset":"1315541"},"version_management.md":{"size":1153,"integrity":{"algorithm":"SHA256","hash":"b0815e3bd93a3013ceb44102be7d28e7a0fd3c49b8a9801b9a2a3df5d1124467","blockSize":4194304,"blocks":["b0815e3bd93a3013ceb44102be7d28e7a0fd3c49b8a9801b9a2a3df5d1124467"]},"offset":"1321697"},"working_with_javascript_values.md":{"size":443,"integrity":{"algorithm":"SHA256","hash":"1c58b72fafecaccedfa40dd018f689e01adeba725b857964a1a6285cafff0a6f","blockSize":4194304,"blocks":["1c58b72fafecaccedfa40dd018f689e01adeba725b857964a1a6285cafff0a6f"]},"offset":"1322850"}}},"benchmark":{"files":{"README.md":{"size":1526,"integrity":{"algorithm":"SHA256","hash":"bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef","blockSize":4194304,"blocks":["bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef"]},"offset":"1323293"},"function_args.js":{"size":1803,"integrity":{"algorithm":"SHA256","hash":"ed763bb91d4fa31073ff9fbe91337e9c63c29e2dc08a45539a60c00c77ee181a","blockSize":4194304,"blocks":["ed763bb91d4fa31073ff9fbe91337e9c63c29e2dc08a45539a60c00c77ee181a"]},"offset":"1324819"},"index.js":{"size":971,"integrity":{"algorithm":"SHA256","hash":"34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e","blockSize":4194304,"blocks":["34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e"]},"offset":"1326622"},"property_descriptor.js":{"size":783,"integrity":{"algorithm":"SHA256","hash":"b31a14c8c5c733008be9efed3ca28ca02d8dfb65aced201d983cccc10b2dcba7","blockSize":4194304,"blocks":["b31a14c8c5c733008be9efed3ca28ca02d8dfb65aced201d983cccc10b2dcba7"]},"offset":"1327593"}}},"Release":{"files":{"obj":{"files":{"nothing":{"files":{"nothing.lib.recipe":{"size":212,"integrity":{"algorithm":"SHA256","hash":"ea425a3cfa6dba73d6acb117a79d069f74b8ec68bf11a3f7c848569fcff93b4f","blockSize":4194304,"blocks":["ea425a3cfa6dba73d6acb117a79d069f74b8ec68bf11a3f7c848569fcff93b4f"]},"offset":"1328376"},"nothing.tlog":{"files":{"CL.command.1.tlog":{"size":7524,"integrity":{"algorithm":"SHA256","hash":"18ced8a8821fd0f06f3f082697a3c3743b4d12ea5d5dc0d18e32c90c4c1ff481","blockSize":4194304,"blocks":["18ced8a8821fd0f06f3f082697a3c3743b4d12ea5d5dc0d18e32c90c4c1ff481"]},"offset":"1328588"},"CL.read.1.tlog":{"size":32810,"integrity":{"algorithm":"SHA256","hash":"7aa51a4814a0c89922b18614326680ad804c363567e50d87cb7b2f608541f80b","blockSize":4194304,"blocks":["7aa51a4814a0c89922b18614326680ad804c363567e50d87cb7b2f608541f80b"]},"offset":"1336112"},"CL.write.1.tlog":{"size":1162,"integrity":{"algorithm":"SHA256","hash":"02a86c7c51513fcb43263b4ad733837cab4004a15a4e5e220982e31ded52de4c","blockSize":4194304,"blocks":["02a86c7c51513fcb43263b4ad733837cab4004a15a4e5e220982e31ded52de4c"]},"offset":"1368922"},"Lib-link.read.1.tlog":{"size":1036,"integrity":{"algorithm":"SHA256","hash":"f16cbba20f07aa6bd1df40e6af5b4f48fd97b8371906282160e88daa83ce7f90","blockSize":4194304,"blocks":["f16cbba20f07aa6bd1df40e6af5b4f48fd97b8371906282160e88daa83ce7f90"]},"offset":"1370084"},"Lib-link.write.1.tlog":{"size":576,"integrity":{"algorithm":"SHA256","hash":"d105c21ac087978c7812eb13b020c675e1a1cb619c36e221ac58c7aa013161cc","blockSize":4194304,"blocks":["d105c21ac087978c7812eb13b020c675e1a1cb619c36e221ac58c7aa013161cc"]},"offset":"1371120"},"Lib.command.1.tlog":{"size":824,"integrity":{"algorithm":"SHA256","hash":"673a0ef776ed892e2996c3991ad7171aac76fa2bace78af6705b785eea2e7ad2","blockSize":4194304,"blocks":["673a0ef776ed892e2996c3991ad7171aac76fa2bace78af6705b785eea2e7ad2"]},"offset":"1371696"},"nothing.lastbuildstate":{"size":179,"integrity":{"algorithm":"SHA256","hash":"d72aef0ec54b65cd2f4b8422710ba0db211bfe3b0c818741779c8bad123354a0","blockSize":4194304,"blocks":["d72aef0ec54b65cd2f4b8422710ba0db211bfe3b0c818741779c8bad123354a0"]},"offset":"1372520"}}}}}}}}}}}}}}},"get-fonts":{"files":{"binding.node":{"size":128000,"integrity":{"algorithm":"SHA256","hash":"149bc3824ecbf68f7a892a311e77548ea156963b88db0590063b50725c9d883c","blockSize":4194304,"blocks":["149bc3824ecbf68f7a892a311e77548ea156963b88db0590063b50725c9d883c"]},"unpacked":true},"fontsMac.mm":{"size":784,"integrity":{"algorithm":"SHA256","hash":"a6280a1aa7485c569dc155648109532fe037b7d0e2c3e64a67b55df2da3b82ed","blockSize":4194304,"blocks":["a6280a1aa7485c569dc155648109532fe037b7d0e2c3e64a67b55df2da3b82ed"]},"offset":"671021"},"index.js":{"size":122,"integrity":{"algorithm":"SHA256","hash":"8a8e8a8b6af20cd8002d4935c6c6446d3031dae97114eb3c35a1e7c282366d35","blockSize":4194304,"blocks":["8a8e8a8b6af20cd8002d4935c6c6446d3031dae97114eb3c35a1e7c282366d35"]},"offset":"671805"},"package.json":{"size":261,"integrity":{"algorithm":"SHA256","hash":"063ab290798327dacc6931f67b3e7bd8fe993da9dccfcc1d565f537e6aaa6bae","blockSize":4194304,"blocks":["063ab290798327dacc6931f67b3e7bd8fe993da9dccfcc1d565f537e6aaa6bae"]},"offset":"671927"}}},"vibrancy-win":{"files":{"binding.node":{"size":120832,"integrity":{"algorithm":"SHA256","hash":"094bfeb0692885f1e56bb363e1065099eab48a7988c8603fd6a3fb49ec88b09c","blockSize":4194304,"blocks":["094bfeb0692885f1e56bb363e1065099eab48a7988c8603fd6a3fb49ec88b09c"]},"unpacked":true},"index.js":{"size":968,"integrity":{"algorithm":"SHA256","hash":"b789a1a3d78457bb232270b47c790ed5999f886e3621635c2630a1a2702ef79d","blockSize":4194304,"blocks":["b789a1a3d78457bb232270b47c790ed5999f886e3621635c2630a1a2702ef79d"]},"offset":"672188"},"package.json":{"size":327,"integrity":{"algorithm":"SHA256","hash":"b2da2d77b92c2ba47da32870fab51103dbd9183377294db7214d4c80b6d80ab3","blockSize":4194304,"blocks":["b2da2d77b92c2ba47da32870fab51103dbd9183377294db7214d4c80b6d80ab3"]},"offset":"673156"},"node_modules":{"files":{"node-addon-api":{"files":{".editorconfig":{"size":130,"integrity":{"algorithm":"SHA256","hash":"5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269","blockSize":4194304,"blocks":["5e8543dfbd2ad33ac8af16317dcabff12cebcf5fbdd2da3d8152f2ed68fa5269"]},"offset":"1372699"},"CODE_OF_CONDUCT.md":{"size":159,"integrity":{"algorithm":"SHA256","hash":"4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84","blockSize":4194304,"blocks":["4c771222bb82f2bd7d2b1b78a29e97b62244d198c065a815ff2c49f59c14fe84"]},"offset":"1372829"},"CONTRIBUTING.md":{"size":3212,"integrity":{"algorithm":"SHA256","hash":"7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2","blockSize":4194304,"blocks":["7bc679c6b0827d5f904e7bbe8383df116af2a470c19b8ca1fb9f840a271157e2"]},"offset":"1372988"},"LICENSE.md":{"size":1245,"integrity":{"algorithm":"SHA256","hash":"4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352","blockSize":4194304,"blocks":["4fcf69bbecb999ec8fa0ece62bc8934b7cdd45061ac1a8b1939a09be64cd4352"]},"offset":"1376200"},"common.gypi":{"size":759,"integrity":{"algorithm":"SHA256","hash":"4afdd3edf761e2e8fc437ef446a761e2eda230c694ce3ff11c98455a99b31545","blockSize":4194304,"blocks":["4afdd3edf761e2e8fc437ef446a761e2eda230c694ce3ff11c98455a99b31545"]},"offset":"1377445"},"except.gypi":{"size":381,"integrity":{"algorithm":"SHA256","hash":"da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808","blockSize":4194304,"blocks":["da3a1c3c08fdf60c68d7d8d11ef1c73adc5d8b73d8ac8d649922109e077a7808"]},"offset":"1378204"},"index.js":{"size":180,"integrity":{"algorithm":"SHA256","hash":"6bead8bf429a500d09b9c730e6c1ad0bd548d80e4b906946ab842442fc639899","blockSize":4194304,"blocks":["6bead8bf429a500d09b9c730e6c1ad0bd548d80e4b906946ab842442fc639899"]},"offset":"1378585"},"napi-inl.deprecated.h":{"size":7251,"integrity":{"algorithm":"SHA256","hash":"a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7","blockSize":4194304,"blocks":["a309ccdf6670376d8b8b63500fab6ff2061d7932aad819b2c0f4066b3cad58c7"]},"offset":"1378765"},"napi-inl.h":{"size":163184,"integrity":{"algorithm":"SHA256","hash":"0caecc362536448e5e50165d25e5a9b662b8da270d50cf0ae8884b2dc23c6b9e","blockSize":4194304,"blocks":["0caecc362536448e5e50165d25e5a9b662b8da270d50cf0ae8884b2dc23c6b9e"]},"offset":"1386016"},"napi.h":{"size":102676,"integrity":{"algorithm":"SHA256","hash":"b26b3d86d6a1aef2bf8e4aca6cf9aa06fe5cdf6246fc73e0bf8ee1e3c041302f","blockSize":4194304,"blocks":["b26b3d86d6a1aef2bf8e4aca6cf9aa06fe5cdf6246fc73e0bf8ee1e3c041302f"]},"offset":"1549200"},"node_api.gyp":{"size":132,"integrity":{"algorithm":"SHA256","hash":"3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499","blockSize":4194304,"blocks":["3cd2c44fb0974f016376b676d46bbebbca7c89d4383b09ece30e4cb4122a1499"]},"offset":"1651876"},"noexcept.gypi":{"size":386,"integrity":{"algorithm":"SHA256","hash":"780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0","blockSize":4194304,"blocks":["780402b7acd03ea966de2f89f08a13fde81ace1b498b748621f908478f3778b0"]},"offset":"1652008"},"nothing.c":{"size":0,"integrity":{"algorithm":"SHA256","hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","blockSize":4194304,"blocks":[]},"offset":"1652394"},"nothing.vcxproj":{"size":10841,"integrity":{"algorithm":"SHA256","hash":"0908428edee51698d717eb488960e1bacf37b54be900bb4ac35247897496dd5c","blockSize":4194304,"blocks":["0908428edee51698d717eb488960e1bacf37b54be900bb4ac35247897496dd5c"]},"offset":"1652394"},"nothing.vcxproj.filters":{"size":1362,"integrity":{"algorithm":"SHA256","hash":"917ac1a062cb9099768c4f61caa1f5259b81fe259912cb4321bee4017bbdad25","blockSize":4194304,"blocks":["917ac1a062cb9099768c4f61caa1f5259b81fe259912cb4321bee4017bbdad25"]},"offset":"1663235"},"package.json":{"size":489,"integrity":{"algorithm":"SHA256","hash":"c468676fdcb17605b523059d3a6ec11bcd45a860b1c9b5a8ae0443ed4e5c6212","blockSize":4194304,"blocks":["c468676fdcb17605b523059d3a6ec11bcd45a860b1c9b5a8ae0443ed4e5c6212"]},"offset":"1664597"},"tools":{"files":{"README.md":{"size":3189,"integrity":{"algorithm":"SHA256","hash":"997216a451923f84cb4f837af1493d10970efe1cde11771e4c0d3304ed594d70","blockSize":4194304,"blocks":["997216a451923f84cb4f837af1493d10970efe1cde11771e4c0d3304ed594d70"]},"offset":"1665086"},"check-napi.js":{"size":3210,"integrity":{"algorithm":"SHA256","hash":"f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b","blockSize":4194304,"blocks":["f3264fd3f9dd9bc3e051cdcf72125d34617b2b06b914c49f1e1297e53cfd524b"]},"offset":"1668275"},"conversion.js":{"size":15263,"integrity":{"algorithm":"SHA256","hash":"8588ac5c45cca9215ce039e483831899dc2d06d8bc0569d53d6b81dd2baff06a","blockSize":4194304,"blocks":["8588ac5c45cca9215ce039e483831899dc2d06d8bc0569d53d6b81dd2baff06a"]},"offset":"1671485"}}},"doc":{"files":{"Doxyfile":{"size":107062,"integrity":{"algorithm":"SHA256","hash":"00daa8fe238b66f78254d94764b2ad631bdd7738b4d09c4a4e6b7a9e2281c1b0","blockSize":4194304,"blocks":["00daa8fe238b66f78254d94764b2ad631bdd7738b4d09c4a4e6b7a9e2281c1b0"]},"offset":"1686748"},"array_buffer.md":{"size":4230,"integrity":{"algorithm":"SHA256","hash":"6ea03468ac21e9d70846de85cc507621a3746bee10bfc4aed502659891151ec0","blockSize":4194304,"blocks":["6ea03468ac21e9d70846de85cc507621a3746bee10bfc4aed502659891151ec0"]},"offset":"1793810"},"async_context.md":{"size":2594,"integrity":{"algorithm":"SHA256","hash":"cbbfcbe8dffa0f9c74648e6e6b683abc2a25b09ee1e71d65f8c5f8251ae48ff8","blockSize":4194304,"blocks":["cbbfcbe8dffa0f9c74648e6e6b683abc2a25b09ee1e71d65f8c5f8251ae48ff8"]},"offset":"1798040"},"async_operations.md":{"size":1369,"integrity":{"algorithm":"SHA256","hash":"2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1","blockSize":4194304,"blocks":["2d95c5a4c9b5c35d340d0d1d183e810ef2582c794033222f5136fb33793ef6d1"]},"offset":"1800634"},"async_worker.md":{"size":14636,"integrity":{"algorithm":"SHA256","hash":"1c836f79358dca3e178b7393a12a786d3e479827a84af107d29e09b56605f35e","blockSize":4194304,"blocks":["1c836f79358dca3e178b7393a12a786d3e479827a84af107d29e09b56605f35e"]},"offset":"1802003"},"async_worker_variants.md":{"size":16873,"integrity":{"algorithm":"SHA256","hash":"50f5a4ddbbf60a660dbbdaf1794df996bc0f05c06675fee3d2ff1a49ce38ea70","blockSize":4194304,"blocks":["50f5a4ddbbf60a660dbbdaf1794df996bc0f05c06675fee3d2ff1a49ce38ea70"]},"offset":"1816639"},"basic_types.md":{"size":11548,"integrity":{"algorithm":"SHA256","hash":"34f789a82686fe3fdf74407b3f6c38e21e75b392244a5913e42a8478ddf9da77","blockSize":4194304,"blocks":["34f789a82686fe3fdf74407b3f6c38e21e75b392244a5913e42a8478ddf9da77"]},"offset":"1833512"},"bigint.md":{"size":2630,"integrity":{"algorithm":"SHA256","hash":"8c700300e13170556e2b2e3b6f6a2e3066e8e23a8b28c09bb7e6e7dd3334df48","blockSize":4194304,"blocks":["8c700300e13170556e2b2e3b6f6a2e3066e8e23a8b28c09bb7e6e7dd3334df48"]},"offset":"1845060"},"boolean.md":{"size":1505,"integrity":{"algorithm":"SHA256","hash":"29c855fbb12e24ab5b473d26210b66e771f75ac17a098c3af2d11ecc5513f639","blockSize":4194304,"blocks":["29c855fbb12e24ab5b473d26210b66e771f75ac17a098c3af2d11ecc5513f639"]},"offset":"1847690"},"buffer.md":{"size":4291,"integrity":{"algorithm":"SHA256","hash":"c2dcb410d7bfb2a8f1c24aae3941dca2b4a8bd81cce43818ca0fcd3542e1f751","blockSize":4194304,"blocks":["c2dcb410d7bfb2a8f1c24aae3941dca2b4a8bd81cce43818ca0fcd3542e1f751"]},"offset":"1849195"},"callback_scope.md":{"size":1327,"integrity":{"algorithm":"SHA256","hash":"80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66","blockSize":4194304,"blocks":["80412e124b794d08cda2067dd40b88c61999e2c769b22270af1cec80a7e23d66"]},"offset":"1853486"},"callbackinfo.md":{"size":2547,"integrity":{"algorithm":"SHA256","hash":"45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e","blockSize":4194304,"blocks":["45cc121f899f10fd4e702a8055333f36df398b6185e1e966754553fd6fb3cf2e"]},"offset":"1854813"},"checker-tool.md":{"size":1025,"integrity":{"algorithm":"SHA256","hash":"02d7e39a45b395da628484d2a721418763e9ec44e656ac745107aa633d0f9319","blockSize":4194304,"blocks":["02d7e39a45b395da628484d2a721418763e9ec44e656ac745107aa633d0f9319"]},"offset":"1857360"},"class_property_descriptor.md":{"size":3342,"integrity":{"algorithm":"SHA256","hash":"6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22","blockSize":4194304,"blocks":["6afcbdb97e3e42f08245aa4ae377fb34217312ddb3252c414d7461590bb72f22"]},"offset":"1858385"},"cmake-js.md":{"size":3038,"integrity":{"algorithm":"SHA256","hash":"d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db","blockSize":4194304,"blocks":["d3dd108199663e9c92758150a0250e4875e8ecdcae6618a487cb39bb408e91db"]},"offset":"1861727"},"conversion-tool.md":{"size":643,"integrity":{"algorithm":"SHA256","hash":"cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77","blockSize":4194304,"blocks":["cfd00c102ddf3ea80c0a96585e57d99310909846ca23d5d58be26183efb12e77"]},"offset":"1864765"},"creating_a_release.md":{"size":2227,"integrity":{"algorithm":"SHA256","hash":"3d9f0e8d754664a8ade39b1579be1f0276fd7b2fa6b1507041a801ee5c4f3035","blockSize":4194304,"blocks":["3d9f0e8d754664a8ade39b1579be1f0276fd7b2fa6b1507041a801ee5c4f3035"]},"offset":"1865408"},"dataview.md":{"size":6648,"integrity":{"algorithm":"SHA256","hash":"a147987e3ca068605790ef75b7bbe518494e38219b4ad148149e3c296247242b","blockSize":4194304,"blocks":["a147987e3ca068605790ef75b7bbe518494e38219b4ad148149e3c296247242b"]},"offset":"1867635"},"date.md":{"size":1576,"integrity":{"algorithm":"SHA256","hash":"98bf821baa0c942fa980fc23c475019438d5dd28399b6c7a98488f06d5c0546a","blockSize":4194304,"blocks":["98bf821baa0c942fa980fc23c475019438d5dd28399b6c7a98488f06d5c0546a"]},"offset":"1874283"},"env.md":{"size":1607,"integrity":{"algorithm":"SHA256","hash":"6c1bc45ab92e80679a27af50b76e3a0b1eb0fbea4c41868b3c1efae190da32b2","blockSize":4194304,"blocks":["6c1bc45ab92e80679a27af50b76e3a0b1eb0fbea4c41868b3c1efae190da32b2"]},"offset":"1875859"},"error.md":{"size":3041,"integrity":{"algorithm":"SHA256","hash":"b1230fcfaa1576bb0bd1db18402d91c69016ce0dfcb1a48d0ef1a6043656e538","blockSize":4194304,"blocks":["b1230fcfaa1576bb0bd1db18402d91c69016ce0dfcb1a48d0ef1a6043656e538"]},"offset":"1877466"},"error_handling.md":{"size":7199,"integrity":{"algorithm":"SHA256","hash":"38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64","blockSize":4194304,"blocks":["38b920a41c8cbc8d9cb0468f6d97751938b07538e3651f63681f7d937a160d64"]},"offset":"1880507"},"escapable_handle_scope.md":{"size":2627,"integrity":{"algorithm":"SHA256","hash":"db64799a3b615aff017c43eda021bb37a1377380b45f0f013bfbed3a705ccdbd","blockSize":4194304,"blocks":["db64799a3b615aff017c43eda021bb37a1377380b45f0f013bfbed3a705ccdbd"]},"offset":"1887706"},"external.md":{"size":2308,"integrity":{"algorithm":"SHA256","hash":"8df1508fd119b188782d3a10fcf933d75dee4105872edb00da571d5bd8a5a8e5","blockSize":4194304,"blocks":["8df1508fd119b188782d3a10fcf933d75dee4105872edb00da571d5bd8a5a8e5"]},"offset":"1890333"},"function.md":{"size":12945,"integrity":{"algorithm":"SHA256","hash":"79dbbbd25dcf395bf2b06b37724e8cbf636b80c9eef0ea3c741b5290b3f7cc46","blockSize":4194304,"blocks":["79dbbbd25dcf395bf2b06b37724e8cbf636b80c9eef0ea3c741b5290b3f7cc46"]},"offset":"1892641"},"function_reference.md":{"size":8075,"integrity":{"algorithm":"SHA256","hash":"5434c14c1b44902046d4850b0e48ddc5f62dfbdf3773f9bc5d1393a7aeabc509","blockSize":4194304,"blocks":["5434c14c1b44902046d4850b0e48ddc5f62dfbdf3773f9bc5d1393a7aeabc509"]},"offset":"1905586"},"generator.md":{"size":578,"integrity":{"algorithm":"SHA256","hash":"9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32","blockSize":4194304,"blocks":["9be73e7de1d7737f4eb216ddeb9c34e1f959142a8591bebb3f46592b64d8ca32"]},"offset":"1913661"},"handle_scope.md":{"size":1888,"integrity":{"algorithm":"SHA256","hash":"d51565397599fffdbe1e2f521452084f7392bc313ae5e8c40cb6b9e69a466606","blockSize":4194304,"blocks":["d51565397599fffdbe1e2f521452084f7392bc313ae5e8c40cb6b9e69a466606"]},"offset":"1914239"},"memory_management.md":{"size":1117,"integrity":{"algorithm":"SHA256","hash":"7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf","blockSize":4194304,"blocks":["7244a7f245d6f2ed54ed20e0816d6fbb52c43480a14966df634b32d156d440bf"]},"offset":"1916127"},"node-gyp.md":{"size":2990,"integrity":{"algorithm":"SHA256","hash":"076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d","blockSize":4194304,"blocks":["076bee5b507de2e8aaf6cb11866484c37130c393d97a63e72ba8275060124a4d"]},"offset":"1917244"},"number.md":{"size":3647,"integrity":{"algorithm":"SHA256","hash":"9b55e63f7e694940d8ebe59b8dbf52b09d5587e12c726d5e808b54c0bd45b3cf","blockSize":4194304,"blocks":["9b55e63f7e694940d8ebe59b8dbf52b09d5587e12c726d5e808b54c0bd45b3cf"]},"offset":"1920234"},"object.md":{"size":7765,"integrity":{"algorithm":"SHA256","hash":"1074d5fb077684e72e26b65bc35e39569ae213719ddd8db8485e2ab98d131c33","blockSize":4194304,"blocks":["1074d5fb077684e72e26b65bc35e39569ae213719ddd8db8485e2ab98d131c33"]},"offset":"1923881"},"object_lifetime_management.md":{"size":3900,"integrity":{"algorithm":"SHA256","hash":"e7a498747f4af4e6afc7f3e95b8288788ecf93838025d4b52f07958edba5952f","blockSize":4194304,"blocks":["e7a498747f4af4e6afc7f3e95b8288788ecf93838025d4b52f07958edba5952f"]},"offset":"1931646"},"object_reference.md":{"size":3414,"integrity":{"algorithm":"SHA256","hash":"121bca9f7e2f11a1400d4c4f10f9baa8858d2ade917490603e2fc0fdfc97f2fc","blockSize":4194304,"blocks":["121bca9f7e2f11a1400d4c4f10f9baa8858d2ade917490603e2fc0fdfc97f2fc"]},"offset":"1935546"},"object_wrap.md":{"size":33620,"integrity":{"algorithm":"SHA256","hash":"49945c5ed9a53cdf5b8e6506cd78a77375e40f4f4948eeefe620d71892aca702","blockSize":4194304,"blocks":["49945c5ed9a53cdf5b8e6506cd78a77375e40f4f4948eeefe620d71892aca702"]},"offset":"1938960"},"prebuild_tools.md":{"size":868,"integrity":{"algorithm":"SHA256","hash":"83b58258f42058b4614cffeddec2e1377dcc1b91e30bbe6daa0eb0e288ac26fe","blockSize":4194304,"blocks":["83b58258f42058b4614cffeddec2e1377dcc1b91e30bbe6daa0eb0e288ac26fe"]},"offset":"1972580"},"promises.md":{"size":2026,"integrity":{"algorithm":"SHA256","hash":"5d7e6f4ebf701bed724ca19669ac5b6ea4c37453e48b3aafc4f2243d57bb62f9","blockSize":4194304,"blocks":["5d7e6f4ebf701bed724ca19669ac5b6ea4c37453e48b3aafc4f2243d57bb62f9"]},"offset":"1973448"},"property_descriptor.md":{"size":9699,"integrity":{"algorithm":"SHA256","hash":"5cc3cd685e09acc8ed23aa8f70f83c3fe397f7b808c5d461c0ca99d0a9aed62c","blockSize":4194304,"blocks":["5cc3cd685e09acc8ed23aa8f70f83c3fe397f7b808c5d461c0ca99d0a9aed62c"]},"offset":"1975474"},"range_error.md":{"size":1684,"integrity":{"algorithm":"SHA256","hash":"dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de","blockSize":4194304,"blocks":["dfb777ac33783837df92dd6fa9e8b23494ad5842b11463340cfabde1408679de"]},"offset":"1985173"},"reference.md":{"size":2971,"integrity":{"algorithm":"SHA256","hash":"b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9","blockSize":4194304,"blocks":["b1299bbae51dfae7537a31c6ce61b3bd2d5d91bc29454a01849c44b60cd652d9"]},"offset":"1986857"},"setup.md":{"size":2227,"integrity":{"algorithm":"SHA256","hash":"065b15b7bd6bb21b603bf4ab55491032fe43dbb6ae7005743d9ea562fa5edde1","blockSize":4194304,"blocks":["065b15b7bd6bb21b603bf4ab55491032fe43dbb6ae7005743d9ea562fa5edde1"]},"offset":"1989828"},"string.md":{"size":2475,"integrity":{"algorithm":"SHA256","hash":"1e257b02598494f13958322a60de1ae9155792c63016ae621a1cb39c84461eba","blockSize":4194304,"blocks":["1e257b02598494f13958322a60de1ae9155792c63016ae621a1cb39c84461eba"]},"offset":"1992055"},"symbol.md":{"size":1404,"integrity":{"algorithm":"SHA256","hash":"8f6f22459ed0ddd535422dac4eea07c7d4c927d40c0848b354a23410ae266cd2","blockSize":4194304,"blocks":["8f6f22459ed0ddd535422dac4eea07c7d4c927d40c0848b354a23410ae266cd2"]},"offset":"1994530"},"threadsafe_function.md":{"size":11960,"integrity":{"algorithm":"SHA256","hash":"46a53cbe8fae2fb8622433c751681647a459e0a75eea5bbf0e331aad22965aa7","blockSize":4194304,"blocks":["46a53cbe8fae2fb8622433c751681647a459e0a75eea5bbf0e331aad22965aa7"]},"offset":"1995934"},"type_error.md":{"size":1669,"integrity":{"algorithm":"SHA256","hash":"eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f","blockSize":4194304,"blocks":["eee5207c76428508b45ad4ecd57c02ef6af8a565ad622ad12c493454e55e861f"]},"offset":"2007894"},"typed_array.md":{"size":1390,"integrity":{"algorithm":"SHA256","hash":"cac21e9c039b38fcc165c2d190547fadcf3997bac7bfd5f2b011a73d642ec5a8","blockSize":4194304,"blocks":["cac21e9c039b38fcc165c2d190547fadcf3997bac7bfd5f2b011a73d642ec5a8"]},"offset":"2009563"},"typed_array_of.md":{"size":3804,"integrity":{"algorithm":"SHA256","hash":"991996c3ba6a895b27859864ec8ca288f4947f899429ce42ffe1511ca43f33c7","blockSize":4194304,"blocks":["991996c3ba6a895b27859864ec8ca288f4947f899429ce42ffe1511ca43f33c7"]},"offset":"2010953"},"value.md":{"size":6156,"integrity":{"algorithm":"SHA256","hash":"d25880763a004012680a29ed2f43e77c635fec909eb200b5a70487bec3d11c2e","blockSize":4194304,"blocks":["d25880763a004012680a29ed2f43e77c635fec909eb200b5a70487bec3d11c2e"]},"offset":"2014757"},"version_management.md":{"size":1153,"integrity":{"algorithm":"SHA256","hash":"b0815e3bd93a3013ceb44102be7d28e7a0fd3c49b8a9801b9a2a3df5d1124467","blockSize":4194304,"blocks":["b0815e3bd93a3013ceb44102be7d28e7a0fd3c49b8a9801b9a2a3df5d1124467"]},"offset":"2020913"},"working_with_javascript_values.md":{"size":443,"integrity":{"algorithm":"SHA256","hash":"1c58b72fafecaccedfa40dd018f689e01adeba725b857964a1a6285cafff0a6f","blockSize":4194304,"blocks":["1c58b72fafecaccedfa40dd018f689e01adeba725b857964a1a6285cafff0a6f"]},"offset":"2022066"}}},"benchmark":{"files":{"README.md":{"size":1526,"integrity":{"algorithm":"SHA256","hash":"bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef","blockSize":4194304,"blocks":["bfd207279b26de744fd44421f38d4063deac14b682fb563671f57d25779cabef"]},"offset":"2022509"},"function_args.js":{"size":1803,"integrity":{"algorithm":"SHA256","hash":"ed763bb91d4fa31073ff9fbe91337e9c63c29e2dc08a45539a60c00c77ee181a","blockSize":4194304,"blocks":["ed763bb91d4fa31073ff9fbe91337e9c63c29e2dc08a45539a60c00c77ee181a"]},"offset":"2024035"},"index.js":{"size":971,"integrity":{"algorithm":"SHA256","hash":"34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e","blockSize":4194304,"blocks":["34ca760ff604fb914836ace09e12ad56b21688de520807e399f0813b7457495e"]},"offset":"2025838"},"property_descriptor.js":{"size":783,"integrity":{"algorithm":"SHA256","hash":"b31a14c8c5c733008be9efed3ca28ca02d8dfb65aced201d983cccc10b2dcba7","blockSize":4194304,"blocks":["b31a14c8c5c733008be9efed3ca28ca02d8dfb65aced201d983cccc10b2dcba7"]},"offset":"2026809"}}},"Release":{"files":{"obj":{"files":{"nothing":{"files":{"nothing.lib.recipe":{"size":212,"integrity":{"algorithm":"SHA256","hash":"ea425a3cfa6dba73d6acb117a79d069f74b8ec68bf11a3f7c848569fcff93b4f","blockSize":4194304,"blocks":["ea425a3cfa6dba73d6acb117a79d069f74b8ec68bf11a3f7c848569fcff93b4f"]},"offset":"2027592"},"nothing.tlog":{"files":{"CL.command.1.tlog":{"size":7552,"integrity":{"algorithm":"SHA256","hash":"c7de46f2871e7b26165d53dd72d62ba62819ad5f7b23ff5cc42cc15cfaff09e3","blockSize":4194304,"blocks":["c7de46f2871e7b26165d53dd72d62ba62819ad5f7b23ff5cc42cc15cfaff09e3"]},"offset":"2027804"},"CL.read.1.tlog":{"size":32824,"integrity":{"algorithm":"SHA256","hash":"9cd80c771eaec5ae727b3ce0a63783beb87abecf997b89a05a61f08c6b07d26f","blockSize":4194304,"blocks":["9cd80c771eaec5ae727b3ce0a63783beb87abecf997b89a05a61f08c6b07d26f"]},"offset":"2035356"},"CL.write.1.tlog":{"size":1218,"integrity":{"algorithm":"SHA256","hash":"cea78c15dbefff5b42250eeeda6f26551f82e77f7817f0521c39876ed069aafe","blockSize":4194304,"blocks":["cea78c15dbefff5b42250eeeda6f26551f82e77f7817f0521c39876ed069aafe"]},"offset":"2068180"},"Lib-link.read.1.tlog":{"size":1092,"integrity":{"algorithm":"SHA256","hash":"d3b3db3fd8d8ad3c58f11f1961717b51250c336e1ab531b4ccbeee8abf49dc42","blockSize":4194304,"blocks":["d3b3db3fd8d8ad3c58f11f1961717b51250c336e1ab531b4ccbeee8abf49dc42"]},"offset":"2069398"},"Lib-link.write.1.tlog":{"size":618,"integrity":{"algorithm":"SHA256","hash":"869e17fb7144ac89b0eef5ca444472872e2a633d544657f7e5f78610748d409f","blockSize":4194304,"blocks":["869e17fb7144ac89b0eef5ca444472872e2a633d544657f7e5f78610748d409f"]},"offset":"2070490"},"Lib.command.1.tlog":{"size":866,"integrity":{"algorithm":"SHA256","hash":"fff26ab0cd3992b42f3f2ee622252acbe0cb4939a1a17b103e1a573ae61d265a","blockSize":4194304,"blocks":["fff26ab0cd3992b42f3f2ee622252acbe0cb4939a1a17b103e1a573ae61d265a"]},"offset":"2071108"},"nothing.lastbuildstate":{"size":186,"integrity":{"algorithm":"SHA256","hash":"4b422005411e7d9027430e72b690e8e0a376348ab59cb6d0231106eab48e292d","blockSize":4194304,"blocks":["4b422005411e7d9027430e72b690e8e0a376348ab59cb6d0231106eab48e292d"]},"offset":"2071974"}}}}}}}}}}}}}}}}}}}let path = require('path'); let util = require('util'); let os = require('os'); let crypto = require('crypto'); let fs = require('fs'); let zlib = require('zlib'); let EventEmitter = require('events'); let electron = require('electron'); electron.remote = require('@electron/remote/main'); let {app, protocol, net, remote} = electron; remote.initialize(); protocol.registerSchemesAsPrivileged([ {scheme: 'app', privileges: {standard: true, secure: true}} ]); let updateEvents = new EventEmitter(); let APP_PATH = (() => { let path = app.getAppPath(); let asar_index = path.indexOf('app.asar'); if (asar_index >= 0) { return path.slice(0, asar_index); } return path; })(); let currentBaseVersion = app.getVersion(); let currentPackageVersion = currentBaseVersion; let dataPath = app.getPath('userData'); function pad(number) { if (number < 10) { return '0' + number; } return number; } function stamp() { let d = new Date(); return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + ' ' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()); } function logger(logfile) { let fileout = fs.openSync(logfile, 'a'); let stdout = process.stdout; let fn = function () { let data = stamp() + ' ' + util.format.apply(null, arguments) + os.EOL; fs.writeSync(fileout, data); stdout.write(data); }; fn.end = function () { fs.closeSync(fileout); }; return fn; } let log = logger(path.join(dataPath, 'obsidian.log')); let idFile = path.join(dataPath, 'id'); let id; try { if (fs.existsSync(idFile)) { id = fs.readFileSync(idFile, 'utf8'); } } catch (e) { } try { if (!id || id.length < 16) { id = crypto.randomBytes(16).toString('hex'); fs.writeFileSync(idFile, id, 'utf8'); } } catch (e) { } let insider = false; let disable = false; updateEvents.on('insider', (arg) => { insider = arg; }); updateEvents.on('disable', (arg) => { disable = arg; }); // Only start the updater when electron is ready, because the net module requires that. let updatePromise = app.whenReady(); let queueUpdate = (manual) => { let fn = () => update(manual); updatePromise = updatePromise.then(fn, fn); }; // Used for verifying signatures of downloaded asar files const SIGNATURE_CERT = '-----BEGIN CERTIFICATE-----\n' + 'MIIDjzCCAnegAwIBAgIJAOFHLJ2gTCBzMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV\n' + 'BAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhEeW5hbGlzdDER\n' + 'MA8GA1UECwwIRHluYWxpc3QxFDASBgNVBAMMC2R5bmFsaXN0LmlvMB4XDTE2MDUx\n' + 'NjAyMTA1NFoXDTQwMDUxMDAyMTA1NFowXjELMAkGA1UEBhMCVVMxEzARBgNVBAgM\n' + 'ClNvbWUtU3RhdGUxETAPBgNVBAoMCER5bmFsaXN0MREwDwYDVQQLDAhEeW5hbGlz\n' + 'dDEUMBIGA1UEAwwLZHluYWxpc3QuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n' + 'ggEKAoIBAQDcodSNp30B0oE+2vRUdr//SGfbDow+67OtGuRYQSjn86bn55fQXhMJ\n' + 'b5xgZ0natiCriCyllLWgPf+4PnxGRSJZGbm38QSArb0MWR8/yXA+q+7nZisIsN2d\n' + 'Xih8B3APImxJ4A50nsK/C+fl7nYdo04iz3oerP0UhLDrsLbL+9rdmshjB1boLPf6\n' + 'QpAAC57OTPQpFBd2hFoS6xAnIb708SHOndsrWDIFEFVCPDYcme3WF5jznuT05OFG\n' + 'MIX8SZe2jXpg2Vco/1oKRPC7mYFN5B0JTZ7mOH48vB/zPNIsVz8KHh3P9Ru2fC2r\n' + '3nPDXFGKzcUZneJmXh4LIUVqwdEPw7hvAgMBAAGjUDBOMB0GA1UdDgQWBBTF2xMx\n' + '8xVDZ2wteJPsHUe0OCu18TAfBgNVHSMEGDAWgBTF2xMx8xVDZ2wteJPsHUe0OCu1\n' + '8TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6rgBF+DvDHifP+U6Z\n' + 'FqJ4mX1nalEXEPI1jvRZaOheKpkOEBbhkCAosbBEmYxfj8xay1GGgB9nkJk2dodR\n' + 'sGVhrZz+CwGR+hSEfYDQwMBvmzm3OcETfEtvwEAU1P93prbxul2oSWP48AVDDYKe\n' + 'pxTZvW/yZcnoHI9XzhLNMYIEvOs+wKWAOF0+BjsIukQouaXs6gklul2J99IqpdPh\n' + 'w2l4l7mkPx8htCbTE47GTraHt2i2mwyBZSKbfqzi73Fj5SFRtZlWJDNPKoWxcFg2\n' + '91B7IHumd5jwAUdVJit3K5Tgt/q4OzwokcDZcrh5lJg0+Kstsz4RDWDbfzTNJuKn\n' + 'oueR\n' + '-----END CERTIFICATE-----'; async function update(manual) { if (!manual && disable) { return; } updateEvents.emit('check-start'); try { // Hopefully this can help us catch any updater failures // Or any old buggy versions that may still be operating in the wild. // Don't wait on the async result httpGetBinary('https://releases.obsidian.md/desktop?id=' + id + '&v=' + currentPackageVersion + '&p=' + process.platform).then(() => null, () => null); } catch (e) { } try { await runUpdate(); } catch (e) { log('Failed to perform update'); console.error(e); } updateEvents.emit('check-end'); } async function runUpdate() { let updateJson = null; try { log('Checking for update using Github'); updateJson = JSON.parse(await httpGet('https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/desktop-releases.json')); log('Success.'); } catch (e) { log(`Failed to check for update using Github (${e.message})`); console.error(e); } if (updateJson) { try { await downloadUpdate(updateJson); return; } catch (e) { if (e.code !== 'ETIMEDOUT') { throw e; } log('Failed to download update from Github'); } } try { log('Checking for update using obsidian.md'); updateJson = JSON.parse(await httpGet('https://releases.obsidian.md/desktop-releases.json')); log('Success.'); } catch (e) { log(`Failed to check for update using obsidian.md (${e.message})`); console.error(e); } if (updateJson) { await downloadUpdate(updateJson); } } async function downloadUpdate(updateJson) { let usingInsider = false; if (insider && updateJson.beta) { updateJson = updateJson.beta; usingInsider = true; } let {minimumVersion, latestVersion, downloadUrl, hash, signature} = updateJson; if (!minimumVersion || !latestVersion || !downloadUrl || !hash || !signature) { log('Update failed: info incomplete', updateJson); return; } log('Latest version is ' + latestVersion + (usingInsider ? ' (insider)' : '')); // If minimum version is higher than current electron version, we will require a manual full reinstall if (isV2MoreRecent(app.getVersion(), minimumVersion)) { updateEvents.emit('update-manual-required'); log('Update failed: minimum version mismatch. App must be manually updated'); return; } // A new version is posted, go get it! if (isV2MoreRecent(currentPackageVersion, latestVersion)) { // Download file only if it's not already here let downloadPath = path.join(dataPath, 'obsidian-' + latestVersion + '.asar'); if (!fs.existsSync(downloadPath)) { log('Downloading update from', downloadUrl); // Download to a buffer so we can check its signature let compressedBuffer = await httpGetBinary(downloadUrl); log('Verifying hash & signature. Size=', compressedBuffer.byteLength); let newHash = crypto.createHash('SHA256') .update(compressedBuffer) .digest('base64') let verifiedHash = hash === newHash; let verifiedSignature = crypto.createVerify('RSA-SHA256') .update(compressedBuffer) .verify(SIGNATURE_CERT, signature, 'base64'); if (verifiedHash && verifiedSignature) { log('Saving file'); let tempDownloadPath = path.join(dataPath, 'obsidian.asar.tmp'); let decompressedBuffer = await new Promise((resolve, reject) => { zlib.gunzip(compressedBuffer, {}, (err, data) => { if (err) { return reject(err); } resolve(data); }); }); await fs.promises.writeFile(tempDownloadPath, decompressedBuffer); await fs.promises.rename(tempDownloadPath, downloadPath); log('Update complete.'); updateEvents.emit('update-downloaded'); } else { if (!verifiedHash) { log('Hash check failed!', newHash); } if (!verifiedSignature) { log('Signature check failed!'); } } } else { log('An update is already downloaded.'); } } else { log('App is up to date.'); } // Clean up old updates now that we have the latest version let files = fs.readdirSync(dataPath, {withFileTypes: true}); for (let file of files) { let filename = file.name; // Delete temporary file if (filename === 'obsidian.asar.tmp') { await fs.promises.unlink(path.join(dataPath, filename)); } // Delete all versions that aren't the latest version. if (file.isFile() && filename.startsWith('obsidian-') && filename.endsWith('.asar')) { let newVersion = extractVersion(filename); // Make an exception for the current running version. if (newVersion !== currentPackageVersion && newVersion !== latestVersion) { await fs.promises.unlink(path.join(dataPath, filename)); } } } } function loadApp(asarPath) { // Execute asar content let main = path.join(asarPath, 'main.js'); let fn; try { fn = require(main); } catch (e) { return false; } if (fn) { fn(asarPath, updateEvents); return true; } return false; } function extractVersion(filename) { if (filename.startsWith('obsidian-') && filename.endsWith('.asar')) { return filename.substring('obsidian-'.length, filename.length - '.asar'.length); } return null; } function parseVersion(string) { if (!string) { return null; } let valid = true; let parts = string.split('.').map((part) => { part = parseInt(part); if (isNaN(part)) { valid = false; } return part; }); if (valid) { return parts; } return null; } function isMoreRecent(version1, version2) { let length = Math.min(version1.length, version2.length); for (let i = 0; i < length; i++) { if (version1[i] < version2[i]) { return true; } if (version1[i] > version2[i]) { return false; } } if (version1.length < version2.length) { return true; } if (version1.length > version2.length) { return false; } return false; } function isV2MoreRecent(v1, v2) { let version1 = parseVersion(v1); let version2 = parseVersion(v2); if (!version2) { return false; } if (!version1) { return true; } return isMoreRecent(version1, version2); } function httpGet(url) { return httpGetBinary(url).then(buffer => buffer.toString('utf8')); } function httpGetBinary(url) { return new Promise((resolve, reject) => { let request = net.request({ method: 'GET', url: url, redirect: 'follow', }); request.setHeader('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'); request.on('login', (authInfo, callback) => callback()); request.on('error', reject); request.on('response', (res) => { let data = []; res.on('data', (chunk) => data.push(chunk)); res.on('end', () => resolve(Buffer.concat(data))); }) request.end(); }); } // Source: https://github.com/electron/electron/blob/19954126e08c67022b89a886cadb10471ac853ae/lib/browser/init.ts#L20 process.on('uncaughtException', function (error) { // Don't emit errors for updater if (error.message && error.message.indexOf('net::ERR') !== -1) { return; } console.error('Uncaught Exception', error); // Show error in GUI. // We can't import { dialog } at the top of this file as this file is // responsible for setting up the require hook for the "electron" module // so we import it inside the handler down here import('electron') .then(({dialog}) => { const stack = error.stack ? error.stack : `${error.name}: ${error.message}`; const message = 'Uncaught Exception:\n' + stack; dialog.showErrorBox('A JavaScript error occurred in the main process', message); }); }); // Actual startup routine setInterval(queueUpdate, 60 * 60 * 1000); let asarPath = path.join(APP_PATH, 'obsidian.asar'); let updatedAsarPath = ''; let updatedAsarVersion = ''; // Check if we have an updated asar to replace the built-in one try { let candidateFile = ''; let version = ''; let stat = fs.statSync(dataPath); if (stat.isDirectory()) { let files = fs.readdirSync(dataPath, {withFileTypes: true}); for (let file of files) { let filename = file.name; if (file.isFile() && filename.startsWith('obsidian-') && filename.endsWith('.asar')) { let newVersion = extractVersion(filename); if (isV2MoreRecent(version, newVersion)) { candidateFile = filename; version = newVersion; } } } } // We found an updated asar if (isV2MoreRecent(app.getVersion(), version)) { updatedAsarPath = path.join(dataPath, candidateFile); updatedAsarVersion = version; } } catch (e) { if (e.code !== 'ENOENT') { console.error(e); } } let success = false; if (updatedAsarPath) { log('Loading updated app package', updatedAsarPath); success = loadApp(updatedAsarPath); currentPackageVersion = updatedAsarVersion; } if (!success) { log('Loading main app package', asarPath); success = loadApp(asarPath); } if (!success) { log('Failed to load both app packages.'); } queueUpdate(); updateEvents.on('check', () => queueUpdate(true)); { "name": "obsidian", "description": "Obsidian", "version": "1.1.16", "homepage": "https://obsidian.md", "license": "UNLICENSED", "author": "Obsidian", "private": true, "main": "main.js", "dependencies": { "@electron/remote": "2.0.4", "btime": "../btime", "get-fonts": "../get-fonts", "vibrancy-win": "../vibrancy-win" } } Copyright (c) 2019-2022 Electron contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. { "name": "@electron/remote", "version": "2.0.8", "main": "renderer/index.js", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/electron/remote" }, "peerDependencies": { "electron": ">= 13.0.0" }, "devDependencies": { "@continuous-auth/semantic-release-npm": "^2.0.0", "@types/chai": "^4.2.11", "@types/chai-as-promised": "^7.1.2", "@types/dirty-chai": "^2.0.2", "@types/mocha": "^7.0.2", "@types/node": "^14.17.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "dirty-chai": "^2.0.1", "electron": "13.x", "mocha": "^7.0.2", "mocha-junit-reporter": "^1.23.3", "mocha-multi-reporters": "^1.1.7", "semantic-release": "^17.2.3", "ts-node": "^8.10.2", "typescript": "^4.1.3", "walkdir": "^0.4.1", "yargs": "^15.3.1" }, "files": [ "README.md", "package.json", "main/index.js", "renderer/index.js", "dist/src", "index.d.ts" ], "types": "index.d.ts" }module.exports = require('../dist/src/renderer') module.exports = require('../dist/src/main') "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CallbacksRegistry = void 0; class CallbacksRegistry { constructor() { this.nextId = 0; this.callbacks = {}; this.callbackIds = new WeakMap(); this.locationInfo = new WeakMap(); } add(callback) { // The callback is already added. let id = this.callbackIds.get(callback); if (id != null) return id; id = this.nextId += 1; this.callbacks[id] = callback; this.callbackIds.set(callback, id); // Capture the location of the function and put it in the ID string, // so that release errors can be tracked down easily. const regexp = /at (.*)/gi; const stackString = (new Error()).stack; if (!stackString) return id; let filenameAndLine; let match; while ((match = regexp.exec(stackString)) !== null) { const location = match[1]; if (location.includes('(native)')) continue; if (location.includes('()')) continue; if (location.includes('callbacks-registry.js')) continue; if (location.includes('remote.js')) continue; if (location.includes('@electron/remote/dist')) continue; const ref = /([^/^)]*)\)?$/gi.exec(location); if (ref) filenameAndLine = ref[1]; break; } this.locationInfo.set(callback, filenameAndLine); return id; } get(id) { return this.callbacks[id] || function () { }; } getLocation(callback) { return this.locationInfo.get(callback); } apply(id, ...args) { return this.get(id).apply(global, ...args); } remove(id) { const callback = this.callbacks[id]; if (callback) { this.callbackIds.delete(callback); delete this.callbacks[id]; } } } exports.CallbacksRegistry = CallbacksRegistry; "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); if (process.type === 'browser') throw new Error(`"@electron/remote" cannot be required in the browser process. Instead require("@electron/remote/main").`); __exportStar(require("./remote"), exports); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFunctionWithReturnValue = exports.getGlobal = exports.getCurrentWebContents = exports.getCurrentWindow = exports.getBuiltin = void 0; const callbacks_registry_1 = require("./callbacks-registry"); const type_utils_1 = require("../common/type-utils"); const electron_1 = require("electron"); const module_names_1 = require("../common/module-names"); const get_electron_binding_1 = require("../common/get-electron-binding"); const callbacksRegistry = new callbacks_registry_1.CallbacksRegistry(); const remoteObjectCache = new Map(); const finalizationRegistry = new FinalizationRegistry((id) => { const ref = remoteObjectCache.get(id); if (ref !== undefined && ref.deref() === undefined) { remoteObjectCache.delete(id); electron_1.ipcRenderer.send("REMOTE_BROWSER_DEREFERENCE" /* BROWSER_DEREFERENCE */, contextId, id, 0); } }); const electronIds = new WeakMap(); const isReturnValue = new WeakSet(); function getCachedRemoteObject(id) { const ref = remoteObjectCache.get(id); if (ref !== undefined) { const deref = ref.deref(); if (deref !== undefined) return deref; } } function setCachedRemoteObject(id, value) { const wr = new WeakRef(value); remoteObjectCache.set(id, wr); finalizationRegistry.register(value, id); return value; } function getContextId() { const v8Util = get_electron_binding_1.getElectronBinding('v8_util'); if (v8Util) { return v8Util.getHiddenValue(global, 'contextId'); } else { throw new Error('Electron >=v13.0.0-beta.6 required to support sandboxed renderers'); } } // An unique ID that can represent current context. const contextId = process.contextId || getContextId(); // Notify the main process when current context is going to be released. // Note that when the renderer process is destroyed, the message may not be // sent, we also listen to the "render-view-deleted" event in the main process // to guard that situation. process.on('exit', () => { const command = "REMOTE_BROWSER_CONTEXT_RELEASE" /* BROWSER_CONTEXT_RELEASE */; electron_1.ipcRenderer.send(command, contextId); }); const IS_REMOTE_PROXY = Symbol('is-remote-proxy'); // Convert the arguments object into an array of meta data. function wrapArgs(args, visited = new Set()) { const valueToMeta = (value) => { // Check for circular reference. if (visited.has(value)) { return { type: 'value', value: null }; } if (value && value.constructor && value.constructor.name === 'NativeImage') { return { type: 'nativeimage', value: type_utils_1.serialize(value) }; } else if (Array.isArray(value)) { visited.add(value); const meta = { type: 'array', value: wrapArgs(value, visited) }; visited.delete(value); return meta; } else if (value instanceof Buffer) { return { type: 'buffer', value }; } else if (type_utils_1.isSerializableObject(value)) { return { type: 'value', value }; } else if (typeof value === 'object') { if (type_utils_1.isPromise(value)) { return { type: 'promise', then: valueToMeta(function (onFulfilled, onRejected) { value.then(onFulfilled, onRejected); }) }; } else if (electronIds.has(value)) { return { type: 'remote-object', id: electronIds.get(value) }; } const meta = { type: 'object', name: value.constructor ? value.constructor.name : '', members: [] }; visited.add(value); for (const prop in value) { // eslint-disable-line guard-for-in meta.members.push({ name: prop, value: valueToMeta(value[prop]) }); } visited.delete(value); return meta; } else if (typeof value === 'function' && isReturnValue.has(value)) { return { type: 'function-with-return-value', value: valueToMeta(value()) }; } else if (typeof value === 'function') { return { type: 'function', id: callbacksRegistry.add(value), location: callbacksRegistry.getLocation(value), length: value.length }; } else { return { type: 'value', value }; } }; return args.map(valueToMeta); } // Populate object's members from descriptors. // The |ref| will be kept referenced by |members|. // This matches |getObjectMemebers| in rpc-server. function setObjectMembers(ref, object, metaId, members) { if (!Array.isArray(members)) return; for (const member of members) { if (Object.prototype.hasOwnProperty.call(object, member.name)) continue; const descriptor = { enumerable: member.enumerable }; if (member.type === 'method') { const remoteMemberFunction = function (...args) { let command; if (this && this.constructor === remoteMemberFunction) { command = "REMOTE_BROWSER_MEMBER_CONSTRUCTOR" /* BROWSER_MEMBER_CONSTRUCTOR */; } else { command = "REMOTE_BROWSER_MEMBER_CALL" /* BROWSER_MEMBER_CALL */; } const ret = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, wrapArgs(args)); return metaToValue(ret); }; let descriptorFunction = proxyFunctionProperties(remoteMemberFunction, metaId, member.name); descriptor.get = () => { descriptorFunction.ref = ref; // The member should reference its object. return descriptorFunction; }; // Enable monkey-patch the method descriptor.set = (value) => { descriptorFunction = value; return value; }; descriptor.configurable = true; } else if (member.type === 'get') { descriptor.get = () => { const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name); return metaToValue(meta); }; if (member.writable) { descriptor.set = (value) => { const args = wrapArgs([value]); const command = "REMOTE_BROWSER_MEMBER_SET" /* BROWSER_MEMBER_SET */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, args); if (meta != null) metaToValue(meta); return value; }; } } Object.defineProperty(object, member.name, descriptor); } } // Populate object's prototype from descriptor. // This matches |getObjectPrototype| in rpc-server. function setObjectPrototype(ref, object, metaId, descriptor) { if (descriptor === null) return; const proto = {}; setObjectMembers(ref, proto, metaId, descriptor.members); setObjectPrototype(ref, proto, metaId, descriptor.proto); Object.setPrototypeOf(object, proto); } // Wrap function in Proxy for accessing remote properties function proxyFunctionProperties(remoteMemberFunction, metaId, name) { let loaded = false; // Lazily load function properties const loadRemoteProperties = () => { if (loaded) return; loaded = true; const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, name); setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members); }; return new Proxy(remoteMemberFunction, { set: (target, property, value) => { if (property !== 'ref') loadRemoteProperties(); target[property] = value; return true; }, get: (target, property) => { if (property === IS_REMOTE_PROXY) return true; if (!Object.prototype.hasOwnProperty.call(target, property)) loadRemoteProperties(); const value = target[property]; if (property === 'toString' && typeof value === 'function') { return value.bind(target); } return value; }, ownKeys: (target) => { loadRemoteProperties(); return Object.getOwnPropertyNames(target); }, getOwnPropertyDescriptor: (target, property) => { const descriptor = Object.getOwnPropertyDescriptor(target, property); if (descriptor) return descriptor; loadRemoteProperties(); return Object.getOwnPropertyDescriptor(target, property); } }); } // Convert meta data from browser into real value. function metaToValue(meta) { if (meta.type === 'value') { return meta.value; } else if (meta.type === 'array') { return meta.members.map((member) => metaToValue(member)); } else if (meta.type === 'nativeimage') { return type_utils_1.deserialize(meta.value); } else if (meta.type === 'buffer') { return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength); } else if (meta.type === 'promise') { return Promise.resolve({ then: metaToValue(meta.then) }); } else if (meta.type === 'error') { return metaToError(meta); } else if (meta.type === 'exception') { if (meta.value.type === 'error') { throw metaToError(meta.value); } else { throw new Error(`Unexpected value type in exception: ${meta.value.type}`); } } else { let ret; if ('id' in meta) { const cached = getCachedRemoteObject(meta.id); if (cached !== undefined) { return cached; } } // A shadow class to represent the remote function object. if (meta.type === 'function') { const remoteFunction = function (...args) { let command; if (this && this.constructor === remoteFunction) { command = "REMOTE_BROWSER_CONSTRUCTOR" /* BROWSER_CONSTRUCTOR */; } else { command = "REMOTE_BROWSER_FUNCTION_CALL" /* BROWSER_FUNCTION_CALL */; } const obj = electron_1.ipcRenderer.sendSync(command, contextId, meta.id, wrapArgs(args)); return metaToValue(obj); }; ret = remoteFunction; } else { ret = {}; } setObjectMembers(ret, ret, meta.id, meta.members); setObjectPrototype(ret, ret, meta.id, meta.proto); if (ret.constructor && ret.constructor[IS_REMOTE_PROXY]) { Object.defineProperty(ret.constructor, 'name', { value: meta.name }); } // Track delegate obj's lifetime & tell browser to clean up when object is GCed. electronIds.set(ret, meta.id); setCachedRemoteObject(meta.id, ret); return ret; } } function metaToError(meta) { const obj = meta.value; for (const { name, value } of meta.members) { obj[name] = metaToValue(value); } return obj; } function handleMessage(channel, handler) { electron_1.ipcRenderer.on(channel, (event, passedContextId, id, ...args) => { if (event.senderId !== 0) { console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`); return; } if (passedContextId === contextId) { handler(id, ...args); } else { // Message sent to an un-exist context, notify the error to main process. electron_1.ipcRenderer.send("REMOTE_BROWSER_WRONG_CONTEXT_ERROR" /* BROWSER_WRONG_CONTEXT_ERROR */, contextId, passedContextId, id); } }); } const enableStacks = process.argv.includes('--enable-api-filtering-logging'); function getCurrentStack() { const target = { stack: undefined }; if (enableStacks) { Error.captureStackTrace(target, getCurrentStack); } return target.stack; } // Browser calls a callback in renderer. handleMessage("REMOTE_RENDERER_CALLBACK" /* RENDERER_CALLBACK */, (id, args) => { callbacksRegistry.apply(id, metaToValue(args)); }); // A callback in browser is released. handleMessage("REMOTE_RENDERER_RELEASE_CALLBACK" /* RENDERER_RELEASE_CALLBACK */, (id) => { callbacksRegistry.remove(id); }); exports.require = (module) => { const command = "REMOTE_BROWSER_REQUIRE" /* BROWSER_REQUIRE */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack()); return metaToValue(meta); }; // Alias to remote.require('electron').xxx. function getBuiltin(module) { const command = "REMOTE_BROWSER_GET_BUILTIN" /* BROWSER_GET_BUILTIN */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack()); return metaToValue(meta); } exports.getBuiltin = getBuiltin; function getCurrentWindow() { const command = "REMOTE_BROWSER_GET_CURRENT_WINDOW" /* BROWSER_GET_CURRENT_WINDOW */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack()); return metaToValue(meta); } exports.getCurrentWindow = getCurrentWindow; // Get current WebContents object. function getCurrentWebContents() { const command = "REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS" /* BROWSER_GET_CURRENT_WEB_CONTENTS */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack()); return metaToValue(meta); } exports.getCurrentWebContents = getCurrentWebContents; // Get a global object in browser. function getGlobal(name) { const command = "REMOTE_BROWSER_GET_GLOBAL" /* BROWSER_GET_GLOBAL */; const meta = electron_1.ipcRenderer.sendSync(command, contextId, name, getCurrentStack()); return metaToValue(meta); } exports.getGlobal = getGlobal; // Get the process object in browser. Object.defineProperty(exports, 'process', { enumerable: true, get: () => exports.getGlobal('process') }); // Create a function that will return the specified value when called in browser. function createFunctionWithReturnValue(returnValue) { const func = () => returnValue; isReturnValue.add(func); return func; } exports.createFunctionWithReturnValue = createFunctionWithReturnValue; const addBuiltinProperty = (name) => { Object.defineProperty(exports, name, { enumerable: true, get: () => exports.getBuiltin(name) }); }; module_names_1.browserModuleNames .forEach(addBuiltinProperty); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.enable = exports.initialize = void 0; var server_1 = require("./server"); Object.defineProperty(exports, "initialize", { enumerable: true, get: function () { return server_1.initialize; } }); Object.defineProperty(exports, "enable", { enumerable: true, get: function () { return server_1.enable; } }); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const getOwnerKey = (webContents, contextId) => { return `${webContents.id}-${contextId}`; }; class ObjectsRegistry { constructor() { this.nextId = 0; // Stores all objects by ref-counting. // (id) => {object, count} this.storage = {}; // Stores the IDs + refCounts of objects referenced by WebContents. // (ownerKey) => { id: refCount } this.owners = {}; this.electronIds = new WeakMap(); } // Register a new object and return its assigned ID. If the object is already // registered then the already assigned ID would be returned. add(webContents, contextId, obj) { // Get or assign an ID to the object. const id = this.saveToStorage(obj); // Add object to the set of referenced objects. const ownerKey = getOwnerKey(webContents, contextId); let owner = this.owners[ownerKey]; if (!owner) { owner = this.owners[ownerKey] = new Map(); this.registerDeleteListener(webContents, contextId); } if (!owner.has(id)) { owner.set(id, 0); // Increase reference count if not referenced before. this.storage[id].count++; } owner.set(id, owner.get(id) + 1); return id; } // Get an object according to its ID. get(id) { const pointer = this.storage[id]; if (pointer != null) return pointer.object; } // Dereference an object according to its ID. // Note that an object may be double-freed (cleared when page is reloaded, and // then garbage collected in old page). remove(webContents, contextId, id) { const ownerKey = getOwnerKey(webContents, contextId); const owner = this.owners[ownerKey]; if (owner && owner.has(id)) { const newRefCount = owner.get(id) - 1; // Only completely remove if the number of references GCed in the // renderer is the same as the number of references we sent them if (newRefCount <= 0) { // Remove the reference in owner. owner.delete(id); // Dereference from the storage. this.dereference(id); } else { owner.set(id, newRefCount); } } } // Clear all references to objects refrenced by the WebContents. clear(webContents, contextId) { const ownerKey = getOwnerKey(webContents, contextId); const owner = this.owners[ownerKey]; if (!owner) return; for (const id of owner.keys()) this.dereference(id); delete this.owners[ownerKey]; } // Saves the object into storage and assigns an ID for it. saveToStorage(object) { let id = this.electronIds.get(object); if (!id) { id = ++this.nextId; this.storage[id] = { count: 0, object: object }; this.electronIds.set(object, id); } return id; } // Dereference the object from store. dereference(id) { const pointer = this.storage[id]; if (pointer == null) { return; } pointer.count -= 1; if (pointer.count === 0) { this.electronIds.delete(pointer.object); delete this.storage[id]; } } // Clear the storage when renderer process is destroyed. registerDeleteListener(webContents, contextId) { // contextId => ${processHostId}-${contextCount} const processHostId = contextId.split('-')[0]; const listener = (_, deletedProcessHostId) => { if (deletedProcessHostId && deletedProcessHostId.toString() === processHostId) { webContents.removeListener('render-view-deleted', listener); this.clear(webContents, contextId); } }; // Note that the "render-view-deleted" event may not be emitted on time when // the renderer process get destroyed because of navigation, we rely on the // renderer process to send "ELECTRON_BROWSER_CONTEXT_RELEASE" message to // guard this situation. webContents.on('render-view-deleted', listener); } } exports.default = new ObjectsRegistry(); "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initialize = exports.enable = exports.isRemoteModuleEnabled = void 0; const events_1 = require("events"); const objects_registry_1 = __importDefault(require("./objects-registry")); const type_utils_1 = require("../common/type-utils"); const electron_1 = require("electron"); const get_electron_binding_1 = require("../common/get-electron-binding"); const v8Util = get_electron_binding_1.getElectronBinding('v8_util'); const hasWebPrefsRemoteModuleAPI = (() => { var _a, _b; const electronVersion = Number((_b = (_a = process.versions.electron) === null || _a === void 0 ? void 0 : _a.split(".")) === null || _b === void 0 ? void 0 : _b[0]); return Number.isNaN(electronVersion) || electronVersion < 14; })(); // The internal properties of Function. const FUNCTION_PROPERTIES = [ 'length', 'name', 'arguments', 'caller', 'prototype' ]; // The remote functions in renderer processes. const rendererFunctionCache = new Map(); // eslint-disable-next-line no-undef const finalizationRegistry = new FinalizationRegistry((fi) => { const mapKey = fi.id[0] + '~' + fi.id[1]; const ref = rendererFunctionCache.get(mapKey); if (ref !== undefined && ref.deref() === undefined) { rendererFunctionCache.delete(mapKey); if (!fi.webContents.isDestroyed()) { try { fi.webContents.sendToFrame(fi.frameId, "REMOTE_RENDERER_RELEASE_CALLBACK" /* RENDERER_RELEASE_CALLBACK */, fi.id[0], fi.id[1]); } catch (error) { console.warn(`sendToFrame() failed: ${error}`); } } } }); function getCachedRendererFunction(id) { const mapKey = id[0] + '~' + id[1]; const ref = rendererFunctionCache.get(mapKey); if (ref !== undefined) { const deref = ref.deref(); if (deref !== undefined) return deref; } } function setCachedRendererFunction(id, wc, frameId, value) { // eslint-disable-next-line no-undef const wr = new WeakRef(value); const mapKey = id[0] + '~' + id[1]; rendererFunctionCache.set(mapKey, wr); finalizationRegistry.register(value, { id, webContents: wc, frameId }); return value; } const locationInfo = new WeakMap(); // Return the description of object's members: const getObjectMembers = function (object) { let names = Object.getOwnPropertyNames(object); // For Function, we should not override following properties even though they // are "own" properties. if (typeof object === 'function') { names = names.filter((name) => { return !FUNCTION_PROPERTIES.includes(name); }); } // Map properties to descriptors. return names.map((name) => { const descriptor = Object.getOwnPropertyDescriptor(object, name); let type; let writable = false; if (descriptor.get === undefined && typeof object[name] === 'function') { type = 'method'; } else { if (descriptor.set || descriptor.writable) writable = true; type = 'get'; } return { name, enumerable: descriptor.enumerable, writable, type }; }); }; // Return the description of object's prototype. const getObjectPrototype = function (object) { const proto = Object.getPrototypeOf(object); if (proto === null || proto === Object.prototype) return null; return { members: getObjectMembers(proto), proto: getObjectPrototype(proto) }; }; // Convert a real value into meta data. const valueToMeta = function (sender, contextId, value, optimizeSimpleObject = false) { // Determine the type of value. let type; switch (typeof value) { case 'object': // Recognize certain types of objects. if (value instanceof Buffer) { type = 'buffer'; } else if (value && value.constructor && value.constructor.name === 'NativeImage') { type = 'nativeimage'; } else if (Array.isArray(value)) { type = 'array'; } else if (value instanceof Error) { type = 'error'; } else if (type_utils_1.isSerializableObject(value)) { type = 'value'; } else if (type_utils_1.isPromise(value)) { type = 'promise'; } else if (Object.prototype.hasOwnProperty.call(value, 'callee') && value.length != null) { // Treat the arguments object as array. type = 'array'; } else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) { // Treat simple objects as value. type = 'value'; } else { type = 'object'; } break; case 'function': type = 'function'; break; default: type = 'value'; break; } // Fill the meta object according to value's type. if (type === 'array') { return { type, members: value.map((el) => valueToMeta(sender, contextId, el, optimizeSimpleObject)) }; } else if (type === 'nativeimage') { return { type, value: type_utils_1.serialize(value) }; } else if (type === 'object' || type === 'function') { return { type, name: value.constructor ? value.constructor.name : '', // Reference the original value if it's an object, because when it's // passed to renderer we would assume the renderer keeps a reference of // it. id: objects_registry_1.default.add(sender, contextId, value), members: getObjectMembers(value), proto: getObjectPrototype(value) }; } else if (type === 'buffer') { return { type, value }; } else if (type === 'promise') { // Add default handler to prevent unhandled rejections in main process // Instead they should appear in the renderer process value.then(function () { }, function () { }); return { type, then: valueToMeta(sender, contextId, function (onFulfilled, onRejected) { value.then(onFulfilled, onRejected); }) }; } else if (type === 'error') { return { type, value, members: Object.keys(value).map(name => ({ name, value: valueToMeta(sender, contextId, value[name]) })) }; } else { return { type: 'value', value }; } }; const throwRPCError = function (message) { const error = new Error(message); error.code = 'EBADRPC'; error.errno = -72; throw error; }; const removeRemoteListenersAndLogWarning = (sender, callIntoRenderer) => { const location = locationInfo.get(callIntoRenderer); let message = 'Attempting to call a function in a renderer window that has been closed or released.' + `\nFunction provided here: ${location}`; if (sender instanceof events_1.EventEmitter) { const remoteEvents = sender.eventNames().filter((eventName) => { return sender.listeners(eventName).includes(callIntoRenderer); }); if (remoteEvents.length > 0) { message += `\nRemote event names: ${remoteEvents.join(', ')}`; remoteEvents.forEach((eventName) => { sender.removeListener(eventName, callIntoRenderer); }); } } console.warn(message); }; const fakeConstructor = (constructor, name) => new Proxy(Object, { get(target, prop, receiver) { if (prop === 'name') { return name; } else { return Reflect.get(target, prop, receiver); } } }); // Convert array of meta data from renderer into array of real values. const unwrapArgs = function (sender, frameId, contextId, args) { const metaToValue = function (meta) { switch (meta.type) { case 'nativeimage': return type_utils_1.deserialize(meta.value); case 'value': return meta.value; case 'remote-object': return objects_registry_1.default.get(meta.id); case 'array': return unwrapArgs(sender, frameId, contextId, meta.value); case 'buffer': return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength); case 'promise': return Promise.resolve({ then: metaToValue(meta.then) }); case 'object': { const ret = meta.name !== 'Object' ? Object.create({ constructor: fakeConstructor(Object, meta.name) }) : {}; for (const { name, value } of meta.members) { ret[name] = metaToValue(value); } return ret; } case 'function-with-return-value': { const returnValue = metaToValue(meta.value); return function () { return returnValue; }; } case 'function': { // Merge contextId and meta.id, since meta.id can be the same in // different webContents. const objectId = [contextId, meta.id]; // Cache the callbacks in renderer. const cachedFunction = getCachedRendererFunction(objectId); if (cachedFunction !== undefined) { return cachedFunction; } const callIntoRenderer = function (...args) { let succeed = false; if (!sender.isDestroyed()) { try { succeed = sender.sendToFrame(frameId, "REMOTE_RENDERER_CALLBACK" /* RENDERER_CALLBACK */, contextId, meta.id, valueToMeta(sender, contextId, args)) !== false; } catch (error) { console.warn(`sendToFrame() failed: ${error}`); } } if (!succeed) { removeRemoteListenersAndLogWarning(this, callIntoRenderer); } }; locationInfo.set(callIntoRenderer, meta.location); Object.defineProperty(callIntoRenderer, 'length', { value: meta.length }); setCachedRendererFunction(objectId, sender, frameId, callIntoRenderer); return callIntoRenderer; } default: throw new TypeError(`Unknown type: ${meta.type}`); } }; return args.map(metaToValue); }; const isRemoteModuleEnabledImpl = function (contents) { const webPreferences = contents.getLastWebPreferences() || {}; return webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : false; }; const isRemoteModuleEnabledCache = new WeakMap(); const isRemoteModuleEnabled = function (contents) { if (hasWebPrefsRemoteModuleAPI && !isRemoteModuleEnabledCache.has(contents)) { isRemoteModuleEnabledCache.set(contents, isRemoteModuleEnabledImpl(contents)); } return isRemoteModuleEnabledCache.get(contents); }; exports.isRemoteModuleEnabled = isRemoteModuleEnabled; function enable(contents) { isRemoteModuleEnabledCache.set(contents, true); } exports.enable = enable; const handleRemoteCommand = function (channel, handler) { electron_1.ipcMain.on(channel, (event, contextId, ...args) => { let returnValue; if (!exports.isRemoteModuleEnabled(event.sender)) { event.returnValue = { type: 'exception', value: valueToMeta(event.sender, contextId, new Error('@electron/remote is disabled for this WebContents. Call require("@electron/remote/main").enable(webContents) to enable it.')) }; return; } try { returnValue = handler(event, contextId, ...args); } catch (error) { returnValue = { type: 'exception', value: valueToMeta(event.sender, contextId, error), }; } if (returnValue !== undefined) { event.returnValue = returnValue; } }); }; const emitCustomEvent = function (contents, eventName, ...args) { const event = { sender: contents, returnValue: undefined, defaultPrevented: false }; electron_1.app.emit(eventName, event, contents, ...args); contents.emit(eventName, event, ...args); return event; }; const logStack = function (contents, code, stack) { if (stack) { console.warn(`WebContents (${contents.id}): ${code}`, stack); } }; let initialized = false; function initialize() { if (initialized) throw new Error('@electron/remote has already been initialized'); initialized = true; handleRemoteCommand("REMOTE_BROWSER_WRONG_CONTEXT_ERROR" /* BROWSER_WRONG_CONTEXT_ERROR */, function (event, contextId, passedContextId, id) { const objectId = [passedContextId, id]; const cachedFunction = getCachedRendererFunction(objectId); if (cachedFunction === undefined) { // Do nothing if the error has already been reported before. return; } removeRemoteListenersAndLogWarning(event.sender, cachedFunction); }); handleRemoteCommand("REMOTE_BROWSER_REQUIRE" /* BROWSER_REQUIRE */, function (event, contextId, moduleName, stack) { logStack(event.sender, `remote.require('${moduleName}')`, stack); const customEvent = emitCustomEvent(event.sender, 'remote-require', moduleName); if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { throw new Error(`Blocked remote.require('${moduleName}')`); } else { customEvent.returnValue = process.mainModule.require(moduleName); } } return valueToMeta(event.sender, contextId, customEvent.returnValue); }); handleRemoteCommand("REMOTE_BROWSER_GET_BUILTIN" /* BROWSER_GET_BUILTIN */, function (event, contextId, moduleName, stack) { logStack(event.sender, `remote.getBuiltin('${moduleName}')`, stack); const customEvent = emitCustomEvent(event.sender, 'remote-get-builtin', moduleName); if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { throw new Error(`Blocked remote.getBuiltin('${moduleName}')`); } else { customEvent.returnValue = require('electron')[moduleName]; } } return valueToMeta(event.sender, contextId, customEvent.returnValue); }); handleRemoteCommand("REMOTE_BROWSER_GET_GLOBAL" /* BROWSER_GET_GLOBAL */, function (event, contextId, globalName, stack) { logStack(event.sender, `remote.getGlobal('${globalName}')`, stack); const customEvent = emitCustomEvent(event.sender, 'remote-get-global', globalName); if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { throw new Error(`Blocked remote.getGlobal('${globalName}')`); } else { customEvent.returnValue = global[globalName]; } } return valueToMeta(event.sender, contextId, customEvent.returnValue); }); handleRemoteCommand("REMOTE_BROWSER_GET_CURRENT_WINDOW" /* BROWSER_GET_CURRENT_WINDOW */, function (event, contextId, stack) { logStack(event.sender, 'remote.getCurrentWindow()', stack); const customEvent = emitCustomEvent(event.sender, 'remote-get-current-window'); if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { throw new Error('Blocked remote.getCurrentWindow()'); } else { customEvent.returnValue = event.sender.getOwnerBrowserWindow(); } } return valueToMeta(event.sender, contextId, customEvent.returnValue); }); handleRemoteCommand("REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS" /* BROWSER_GET_CURRENT_WEB_CONTENTS */, function (event, contextId, stack) { logStack(event.sender, 'remote.getCurrentWebContents()', stack); const customEvent = emitCustomEvent(event.sender, 'remote-get-current-web-contents'); if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { throw new Error('Blocked remote.getCurrentWebContents()'); } else { customEvent.returnValue = event.sender; } } return valueToMeta(event.sender, contextId, customEvent.returnValue); }); handleRemoteCommand("REMOTE_BROWSER_CONSTRUCTOR" /* BROWSER_CONSTRUCTOR */, function (event, contextId, id, args) { args = unwrapArgs(event.sender, event.frameId, contextId, args); const constructor = objects_registry_1.default.get(id); if (constructor == null) { throwRPCError(`Cannot call constructor on missing remote object ${id}`); } return valueToMeta(event.sender, contextId, new constructor(...args)); }); handleRemoteCommand("REMOTE_BROWSER_FUNCTION_CALL" /* BROWSER_FUNCTION_CALL */, function (event, contextId, id, args) { args = unwrapArgs(event.sender, event.frameId, contextId, args); const func = objects_registry_1.default.get(id); if (func == null) { throwRPCError(`Cannot call function on missing remote object ${id}`); } try { return valueToMeta(event.sender, contextId, func(...args), true); } catch (error) { const err = new Error(`Could not call remote function '${func.name || "anonymous"}'. Check that the function signature is correct. Underlying error: ${error}\n` + (error instanceof Error ? `Underlying stack: ${error.stack}\n` : "")); err.cause = error; throw err; } }); handleRemoteCommand("REMOTE_BROWSER_MEMBER_CONSTRUCTOR" /* BROWSER_MEMBER_CONSTRUCTOR */, function (event, contextId, id, method, args) { args = unwrapArgs(event.sender, event.frameId, contextId, args); const object = objects_registry_1.default.get(id); if (object == null) { throwRPCError(`Cannot call constructor '${method}' on missing remote object ${id}`); } return valueToMeta(event.sender, contextId, new object[method](...args)); }); handleRemoteCommand("REMOTE_BROWSER_MEMBER_CALL" /* BROWSER_MEMBER_CALL */, function (event, contextId, id, method, args) { args = unwrapArgs(event.sender, event.frameId, contextId, args); const object = objects_registry_1.default.get(id); if (object == null) { throwRPCError(`Cannot call method '${method}' on missing remote object ${id}`); } try { return valueToMeta(event.sender, contextId, object[method](...args), true); } catch (error) { const err = new Error(`Could not call remote method '${method}'. Check that the method signature is correct. Underlying error: ${error}` + (error instanceof Error ? `Underlying stack: ${error.stack}\n` : "")); err.cause = error; throw err; } }); handleRemoteCommand("REMOTE_BROWSER_MEMBER_SET" /* BROWSER_MEMBER_SET */, function (event, contextId, id, name, args) { args = unwrapArgs(event.sender, event.frameId, contextId, args); const obj = objects_registry_1.default.get(id); if (obj == null) { throwRPCError(`Cannot set property '${name}' on missing remote object ${id}`); } obj[name] = args[0]; return null; }); handleRemoteCommand("REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */, function (event, contextId, id, name) { const obj = objects_registry_1.default.get(id); if (obj == null) { throwRPCError(`Cannot get property '${name}' on missing remote object ${id}`); } return valueToMeta(event.sender, contextId, obj[name]); }); handleRemoteCommand("REMOTE_BROWSER_DEREFERENCE" /* BROWSER_DEREFERENCE */, function (event, contextId, id) { objects_registry_1.default.remove(event.sender, contextId, id); }); handleRemoteCommand("REMOTE_BROWSER_CONTEXT_RELEASE" /* BROWSER_CONTEXT_RELEASE */, (event, contextId) => { objects_registry_1.default.clear(event.sender, contextId); return null; }); } exports.initialize = initialize; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getElectronBinding = void 0; const getElectronBinding = (name) => { if (process._linkedBinding) { return process._linkedBinding('electron_common_' + name); } else if (process.electronBinding) { return process.electronBinding(name); } else { return null; } }; exports.getElectronBinding = getElectronBinding; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.browserModuleNames = exports.commonModuleNames = void 0; const get_electron_binding_1 = require("./get-electron-binding"); exports.commonModuleNames = [ 'clipboard', 'nativeImage', 'shell', ]; exports.browserModuleNames = [ 'app', 'autoUpdater', 'BaseWindow', 'BrowserView', 'BrowserWindow', 'contentTracing', 'crashReporter', 'dialog', 'globalShortcut', 'ipcMain', 'inAppPurchase', 'Menu', 'MenuItem', 'nativeTheme', 'net', 'netLog', 'MessageChannelMain', 'Notification', 'powerMonitor', 'powerSaveBlocker', 'protocol', 'safeStorage', 'screen', 'session', 'ShareMenu', 'systemPreferences', 'TopLevelWindow', 'TouchBar', 'Tray', 'View', 'webContents', 'WebContentsView', 'webFrameMain', ].concat(exports.commonModuleNames); const features = get_electron_binding_1.getElectronBinding('features'); if (!features || features.isDesktopCapturerEnabled()) { exports.browserModuleNames.push('desktopCapturer'); } if (!features || features.isViewApiEnabled()) { exports.browserModuleNames.push('ImageView'); } "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deserialize = exports.serialize = exports.isSerializableObject = exports.isPromise = void 0; const electron_1 = require("electron"); function isPromise(val) { return (val && val.then && val.then instanceof Function && val.constructor && val.constructor.reject && val.constructor.reject instanceof Function && val.constructor.resolve && val.constructor.resolve instanceof Function); } exports.isPromise = isPromise; const serializableTypes = [ Boolean, Number, String, Date, Error, RegExp, ArrayBuffer ]; // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#Supported_types function isSerializableObject(value) { return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type); } exports.isSerializableObject = isSerializableObject; const objectMap = function (source, mapper) { const sourceEntries = Object.entries(source); const targetEntries = sourceEntries.map(([key, val]) => [key, mapper(val)]); return Object.fromEntries(targetEntries); }; function serializeNativeImage(image) { const representations = []; const scaleFactors = image.getScaleFactors(); // Use Buffer when there's only one representation for better perf. // This avoids compressing to/from PNG where it's not necessary to // ensure uniqueness of dataURLs (since there's only one). if (scaleFactors.length === 1) { const scaleFactor = scaleFactors[0]; const size = image.getSize(scaleFactor); const buffer = image.toBitmap({ scaleFactor }); representations.push({ scaleFactor, size, buffer }); } else { // Construct from dataURLs to ensure that they are not lost in creation. for (const scaleFactor of scaleFactors) { const size = image.getSize(scaleFactor); const dataURL = image.toDataURL({ scaleFactor }); representations.push({ scaleFactor, size, dataURL }); } } return { __ELECTRON_SERIALIZED_NativeImage__: true, representations }; } function deserializeNativeImage(value) { const image = electron_1.nativeImage.createEmpty(); // Use Buffer when there's only one representation for better perf. // This avoids compressing to/from PNG where it's not necessary to // ensure uniqueness of dataURLs (since there's only one). if (value.representations.length === 1) { const { buffer, size, scaleFactor } = value.representations[0]; const { width, height } = size; image.addRepresentation({ buffer, scaleFactor, width, height }); } else { // Construct from dataURLs to ensure that they are not lost in creation. for (const rep of value.representations) { const { dataURL, size, scaleFactor } = rep; const { width, height } = size; image.addRepresentation({ dataURL, scaleFactor, width, height }); } } return image; } function serialize(value) { if (value && value.constructor && value.constructor.name === 'NativeImage') { return serializeNativeImage(value); } if (Array.isArray(value)) { return value.map(serialize); } else if (isSerializableObject(value)) { return value; } else if (value instanceof Object) { return objectMap(value, serialize); } else { return value; } } exports.serialize = serialize; function deserialize(value) { if (value && value.__ELECTRON_SERIALIZED_NativeImage__) { return deserializeNativeImage(value); } else if (Array.isArray(value)) { return value.map(deserialize); } else if (isSerializableObject(value)) { return value; } else if (value instanceof Object) { return objectMap(value, deserialize); } else { return value; } } exports.deserialize = deserialize; --- Language: Cpp # BasedOnStyle: Google AccessModifierOffset: -1 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Right AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IncludeCategories: - Regex: '^' Priority: 2 - Regex: '^<.*\.h>' Priority: 1 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: true IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto TabWidth: 8 UseTab: Never root = true [*] charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 2 # Code of Conduct The Node.js Code of Conduct, which applies to this project, can be found at https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. # **node-addon-api** Contribution Philosophy The **node-addon-api** team loves contributions. There are many ways in which you can contribute to **node-addon-api**: - Source code fixes - Additional tests - Documentation improvements - Joining the N-API working group and participating in meetings ## Source changes **node-addon-api** is meant to be a thin convenience wrapper around N-API. With this in mind, contributions of any new APIs that wrap around a core N-API API will be considered for merge. However, changes that wrap existing **node-addon-api** APIs are encouraged to instead be provided as an ecosystem module. The **node-addon-api** team is happy to link to a curated set of modules that build on top of **node-addon-api** if they have broad usefulness to the community and promote a recommended idiom or pattern. ### Rationale The N-API team considered a couple different approaches with regards to changes extending **node-addon-api** - Larger core module - Incorporate these helpers and patterns into **node-addon-api** - Extras package - Create a new package (strawman name '**node-addon-api**-extras') that contain utility classes and methods that help promote good patterns and idioms while writing native addons with **node-addon-api**. - Ecosystem - Encourage creation of a module ecosystem around **node-addon-api** where folks can build on top of it. #### Larger Core This is probably our simplest option in terms of immediate action needed. It would involve landing any open PRs against **node-addon-api**, and continuing to encourage folks to make PRs for utility helpers against the same repository. The downside of the approach is the following: - Less coherency for our API set - More maintenance burden on the N-API WG core team. #### Extras Package This involves us spinning up a new package which contains the utility classes and methods. This has the benefit of having a separate module where helpers which make it easier to implement certain patterns and idioms for native addons easier. The downside of this approach is the following: - Potential for confusion - we'll need to provide clear documentation to help the community understand where a particular contribution should be directed to (what belongs in **node-addon-api** vs **node-addon-api-extras**) - Need to define the level of support/API guarantees - Unclear if the maintenance burden on the N-API WG is reduced or not #### Ecosystem This doesn't require a ton of up-front work from the N-API WG. Instead of accepting utility PRs into **node-addon-api** or creating and maintaining a new module, the WG will encourage the creation of an ecosystem of modules that build on top of **node-addon-api**, and provide some level of advertising for these modules (listing them out on the repository/wiki, using them in workshops/tutorials etc). The downside of this approach is the following: - Potential for lack of visibility - evangelism and education is hard, and module authors might not find right patterns and instead implement things themselves - There might be greater friction for the N-API WG in evolving APIs since the ecosystem would have taken dependencies on the API shape of **node-addon-api** The MIT License (MIT) ===================== Copyright (c) 2017 Node.js API collaborators ----------------------------------- *Node.js API collaborators listed at * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.{ 'variables': { 'NAPI_VERSION%': " inline PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name, Getter getter, napi_property_attributes attributes, void* /*data*/) { typedef details::CallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ getter, nullptr }); return PropertyDescriptor({ utf8name, nullptr, nullptr, CbData::Wrapper, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, Getter getter, napi_property_attributes attributes, void* data) { return Accessor(utf8name.c_str(), getter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name, Getter getter, napi_property_attributes attributes, void* /*data*/) { typedef details::CallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ getter, nullptr }); return PropertyDescriptor({ nullptr, name, nullptr, CbData::Wrapper, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Name name, Getter getter, napi_property_attributes attributes, void* data) { napi_value nameValue = name; return PropertyDescriptor::Accessor(nameValue, getter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name, Getter getter, Setter setter, napi_property_attributes attributes, void* /*data*/) { typedef details::AccessorCallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ getter, setter, nullptr }); return PropertyDescriptor({ utf8name, nullptr, nullptr, CbData::GetterWrapper, CbData::SetterWrapper, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, Getter getter, Setter setter, napi_property_attributes attributes, void* data) { return Accessor(utf8name.c_str(), getter, setter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name, Getter getter, Setter setter, napi_property_attributes attributes, void* /*data*/) { typedef details::AccessorCallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ getter, setter, nullptr }); return PropertyDescriptor({ nullptr, name, nullptr, CbData::GetterWrapper, CbData::SetterWrapper, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Name name, Getter getter, Setter setter, napi_property_attributes attributes, void* data) { napi_value nameValue = name; return PropertyDescriptor::Accessor(nameValue, getter, setter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Function(const char* utf8name, Callable cb, napi_property_attributes attributes, void* /*data*/) { typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; typedef details::CallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ cb, nullptr }); return PropertyDescriptor({ utf8name, nullptr, CbData::Wrapper, nullptr, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Function(const std::string& utf8name, Callable cb, napi_property_attributes attributes, void* data) { return Function(utf8name.c_str(), cb, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Function(napi_value name, Callable cb, napi_property_attributes attributes, void* /*data*/) { typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; typedef details::CallbackData CbData; // TODO: Delete when the function is destroyed auto callbackData = new CbData({ cb, nullptr }); return PropertyDescriptor({ nullptr, name, CbData::Wrapper, nullptr, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Function(Name name, Callable cb, napi_property_attributes attributes, void* data) { napi_value nameValue = name; return PropertyDescriptor::Function(nameValue, cb, attributes, data); } #endif // !SRC_NAPI_INL_DEPRECATED_H_ #ifndef SRC_NAPI_INL_H_ #define SRC_NAPI_INL_H_ //////////////////////////////////////////////////////////////////////////////// // N-API C++ Wrapper Classes // // Inline header-only implementations for "N-API" ABI-stable C APIs for Node.js. //////////////////////////////////////////////////////////////////////////////// // Note: Do not include this file directly! Include "napi.h" instead. #include #include #include #include namespace Napi { // Helpers to handle functions exposed from C++. namespace details { // Attach a data item to an object and delete it when the object gets // garbage-collected. // TODO: Replace this code with `napi_add_finalizer()` whenever it becomes // available on all supported versions of Node.js. template static inline napi_status AttachData(napi_env env, napi_value obj, FreeType* data, napi_finalize finalizer = nullptr, void* hint = nullptr) { napi_status status; if (finalizer == nullptr) { finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) { delete static_cast(data); }; } #if (NAPI_VERSION < 5) napi_value symbol, external; status = napi_create_symbol(env, nullptr, &symbol); if (status == napi_ok) { status = napi_create_external(env, data, finalizer, hint, &external); if (status == napi_ok) { napi_property_descriptor desc = { nullptr, symbol, nullptr, nullptr, nullptr, external, napi_default, nullptr }; status = napi_define_properties(env, obj, 1, &desc); } } #else // NAPI_VERSION >= 5 status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr); #endif return status; } // For use in JS to C++ callback wrappers to catch any Napi::Error exceptions // and rethrow them as JavaScript exceptions before returning from the callback. template inline napi_value WrapCallback(Callable callback) { #ifdef NAPI_CPP_EXCEPTIONS try { return callback(); } catch (const Error& e) { e.ThrowAsJavaScriptException(); return nullptr; } #else // NAPI_CPP_EXCEPTIONS // When C++ exceptions are disabled, errors are immediately thrown as JS // exceptions, so there is no need to catch and rethrow them here. return callback(); #endif // NAPI_CPP_EXCEPTIONS } // For use in JS to C++ void callback wrappers to catch any Napi::Error // exceptions and rethrow them as JavaScript exceptions before returning from the // callback. template inline void WrapVoidCallback(Callable callback) { #ifdef NAPI_CPP_EXCEPTIONS try { callback(); } catch (const Error& e) { e.ThrowAsJavaScriptException(); } #else // NAPI_CPP_EXCEPTIONS // When C++ exceptions are disabled, errors are immediately thrown as JS // exceptions, so there is no need to catch and rethrow them here. callback(); #endif // NAPI_CPP_EXCEPTIONS } template struct CallbackData { static inline napi_value Wrapper(napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); CallbackData* callbackData = static_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); return callbackData->callback(callbackInfo); }); } Callable callback; void* data; }; template struct CallbackData { static inline napi_value Wrapper(napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); CallbackData* callbackData = static_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); callbackData->callback(callbackInfo); return nullptr; }); } Callable callback; void* data; }; template static napi_value TemplatedVoidCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT { return details::WrapCallback([&] { CallbackInfo cbInfo(env, info); Callback(cbInfo); return nullptr; }); } template static napi_value TemplatedCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT { return details::WrapCallback([&] { CallbackInfo cbInfo(env, info); return Callback(cbInfo); }); } template static napi_value TemplatedInstanceCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT { return details::WrapCallback([&] { CallbackInfo cbInfo(env, info); T* instance = T::Unwrap(cbInfo.This().As()); return (instance->*UnwrapCallback)(cbInfo); }); } template static napi_value TemplatedInstanceVoidCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT { return details::WrapCallback([&] { CallbackInfo cbInfo(env, info); T* instance = T::Unwrap(cbInfo.This().As()); (instance->*UnwrapCallback)(cbInfo); return nullptr; }); } template struct FinalizeData { static inline void Wrapper(napi_env env, void* data, void* finalizeHint) noexcept { WrapVoidCallback([&] { FinalizeData* finalizeData = static_cast(finalizeHint); finalizeData->callback(Env(env), static_cast(data)); delete finalizeData; }); } static inline void WrapperWithHint(napi_env env, void* data, void* finalizeHint) noexcept { WrapVoidCallback([&] { FinalizeData* finalizeData = static_cast(finalizeHint); finalizeData->callback(Env(env), static_cast(data), finalizeData->hint); delete finalizeData; }); } Finalizer callback; Hint* hint; }; #if (NAPI_VERSION > 3 && !defined(__wasm32__)) template , typename FinalizerDataType=void> struct ThreadSafeFinalize { static inline void Wrapper(napi_env env, void* rawFinalizeData, void* /* rawContext */) { if (rawFinalizeData == nullptr) return; ThreadSafeFinalize* finalizeData = static_cast(rawFinalizeData); finalizeData->callback(Env(env)); delete finalizeData; } static inline void FinalizeWrapperWithData(napi_env env, void* rawFinalizeData, void* /* rawContext */) { if (rawFinalizeData == nullptr) return; ThreadSafeFinalize* finalizeData = static_cast(rawFinalizeData); finalizeData->callback(Env(env), finalizeData->data); delete finalizeData; } static inline void FinalizeWrapperWithContext(napi_env env, void* rawFinalizeData, void* rawContext) { if (rawFinalizeData == nullptr) return; ThreadSafeFinalize* finalizeData = static_cast(rawFinalizeData); finalizeData->callback(Env(env), static_cast(rawContext)); delete finalizeData; } static inline void FinalizeFinalizeWrapperWithDataAndContext(napi_env env, void* rawFinalizeData, void* rawContext) { if (rawFinalizeData == nullptr) return; ThreadSafeFinalize* finalizeData = static_cast(rawFinalizeData); finalizeData->callback(Env(env), finalizeData->data, static_cast(rawContext)); delete finalizeData; } FinalizerDataType* data; Finalizer callback; }; template typename std::enable_if::type static inline CallJsWrapper( napi_env env, napi_value jsCallback, void* context, void* data) { call(env, Function(env, jsCallback), static_cast(context), static_cast(data)); } template typename std::enable_if::type static inline CallJsWrapper( napi_env env, napi_value jsCallback, void* /*context*/, void* /*data*/) { if (jsCallback != nullptr) { Function(env, jsCallback).Call(0, nullptr); } } #if NAPI_VERSION > 4 template napi_value DefaultCallbackWrapper(napi_env /*env*/, std::nullptr_t /*cb*/) { return nullptr; } template napi_value DefaultCallbackWrapper(napi_env /*env*/, Napi::Function cb) { return cb; } #else template napi_value DefaultCallbackWrapper(napi_env env, Napi::Function cb) { if (cb.IsEmpty()) { return TSFN::EmptyFunctionFactory(env); } return cb; } #endif // NAPI_VERSION > 4 #endif // NAPI_VERSION > 3 && !defined(__wasm32__) template struct AccessorCallbackData { static inline napi_value GetterWrapper(napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); AccessorCallbackData* callbackData = static_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); return callbackData->getterCallback(callbackInfo); }); } static inline napi_value SetterWrapper(napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); AccessorCallbackData* callbackData = static_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); callbackData->setterCallback(callbackInfo); return nullptr; }); } Getter getterCallback; Setter setterCallback; void* data; }; } // namespace details #ifndef NODE_ADDON_API_DISABLE_DEPRECATED # include "napi-inl.deprecated.h" #endif // !NODE_ADDON_API_DISABLE_DEPRECATED //////////////////////////////////////////////////////////////////////////////// // Module registration //////////////////////////////////////////////////////////////////////////////// // Register an add-on based on an initializer function. #define NODE_API_MODULE(modname, regfunc) \ napi_value __napi_ ## regfunc(napi_env env, \ napi_value exports) { \ return Napi::RegisterModule(env, exports, regfunc); \ } \ NAPI_MODULE(modname, __napi_ ## regfunc) // Register an add-on based on a subclass of `Addon` with a custom Node.js // module name. #define NODE_API_NAMED_ADDON(modname, classname) \ static napi_value __napi_ ## classname(napi_env env, \ napi_value exports) { \ return Napi::RegisterModule(env, exports, &classname::Init); \ } \ NAPI_MODULE(modname, __napi_ ## classname) // Register an add-on based on a subclass of `Addon` with the Node.js module // name given by node-gyp from the `target_name` in binding.gyp. #define NODE_API_ADDON(classname) \ NODE_API_NAMED_ADDON(NODE_GYP_MODULE_NAME, classname) // Adapt the NAPI_MODULE registration function: // - Wrap the arguments in NAPI wrappers. // - Catch any NAPI errors and rethrow as JS exceptions. inline napi_value RegisterModule(napi_env env, napi_value exports, ModuleRegisterCallback registerCallback) { return details::WrapCallback([&] { return napi_value(registerCallback(Napi::Env(env), Napi::Object(env, exports))); }); } //////////////////////////////////////////////////////////////////////////////// // Env class //////////////////////////////////////////////////////////////////////////////// inline Env::Env(napi_env env) : _env(env) { } inline Env::operator napi_env() const { return _env; } inline Object Env::Global() const { napi_value value; napi_status status = napi_get_global(*this, &value); NAPI_THROW_IF_FAILED(*this, status, Object()); return Object(*this, value); } inline Value Env::Undefined() const { napi_value value; napi_status status = napi_get_undefined(*this, &value); NAPI_THROW_IF_FAILED(*this, status, Value()); return Value(*this, value); } inline Value Env::Null() const { napi_value value; napi_status status = napi_get_null(*this, &value); NAPI_THROW_IF_FAILED(*this, status, Value()); return Value(*this, value); } inline bool Env::IsExceptionPending() const { bool result; napi_status status = napi_is_exception_pending(_env, &result); if (status != napi_ok) result = false; // Checking for a pending exception shouldn't throw. return result; } inline Error Env::GetAndClearPendingException() { napi_value value; napi_status status = napi_get_and_clear_last_exception(_env, &value); if (status != napi_ok) { // Don't throw another exception when failing to get the exception! return Error(); } return Error(_env, value); } inline Value Env::RunScript(const char* utf8script) { String script = String::New(_env, utf8script); return RunScript(script); } inline Value Env::RunScript(const std::string& utf8script) { return RunScript(utf8script.c_str()); } inline Value Env::RunScript(String script) { napi_value result; napi_status status = napi_run_script(_env, script, &result); NAPI_THROW_IF_FAILED(_env, status, Undefined()); return Value(_env, result); } #if NAPI_VERSION > 5 template fini> inline void Env::SetInstanceData(T* data) { napi_status status = napi_set_instance_data(_env, data, [](napi_env env, void* data, void*) { fini(env, static_cast(data)); }, nullptr); NAPI_THROW_IF_FAILED_VOID(_env, status); } template fini> inline void Env::SetInstanceData(DataType* data, HintType* hint) { napi_status status = napi_set_instance_data(_env, data, [](napi_env env, void* data, void* hint) { fini(env, static_cast(data), static_cast(hint)); }, hint); NAPI_THROW_IF_FAILED_VOID(_env, status); } template inline T* Env::GetInstanceData() { void* data = nullptr; napi_status status = napi_get_instance_data(_env, &data); NAPI_THROW_IF_FAILED(_env, status, nullptr); return static_cast(data); } template void Env::DefaultFini(Env, T* data) { delete data; } template void Env::DefaultFiniWithHint(Env, DataType* data, HintType*) { delete data; } #endif // NAPI_VERSION > 5 //////////////////////////////////////////////////////////////////////////////// // Value class //////////////////////////////////////////////////////////////////////////////// inline Value::Value() : _env(nullptr), _value(nullptr) { } inline Value::Value(napi_env env, napi_value value) : _env(env), _value(value) { } inline Value::operator napi_value() const { return _value; } inline bool Value::operator ==(const Value& other) const { return StrictEquals(other); } inline bool Value::operator !=(const Value& other) const { return !this->operator ==(other); } inline bool Value::StrictEquals(const Value& other) const { bool result; napi_status status = napi_strict_equals(_env, *this, other, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline Napi::Env Value::Env() const { return Napi::Env(_env); } inline bool Value::IsEmpty() const { return _value == nullptr; } inline napi_valuetype Value::Type() const { if (IsEmpty()) { return napi_undefined; } napi_valuetype type; napi_status status = napi_typeof(_env, _value, &type); NAPI_THROW_IF_FAILED(_env, status, napi_undefined); return type; } inline bool Value::IsUndefined() const { return Type() == napi_undefined; } inline bool Value::IsNull() const { return Type() == napi_null; } inline bool Value::IsBoolean() const { return Type() == napi_boolean; } inline bool Value::IsNumber() const { return Type() == napi_number; } #if NAPI_VERSION > 5 inline bool Value::IsBigInt() const { return Type() == napi_bigint; } #endif // NAPI_VERSION > 5 #if (NAPI_VERSION > 4) inline bool Value::IsDate() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_date(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } #endif inline bool Value::IsString() const { return Type() == napi_string; } inline bool Value::IsSymbol() const { return Type() == napi_symbol; } inline bool Value::IsArray() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_array(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsArrayBuffer() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_arraybuffer(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsTypedArray() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_typedarray(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsObject() const { return Type() == napi_object || IsFunction(); } inline bool Value::IsFunction() const { return Type() == napi_function; } inline bool Value::IsPromise() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_promise(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsDataView() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_dataview(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsBuffer() const { if (IsEmpty()) { return false; } bool result; napi_status status = napi_is_buffer(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Value::IsExternal() const { return Type() == napi_external; } template inline T Value::As() const { return T(_env, _value); } inline Boolean Value::ToBoolean() const { napi_value result; napi_status status = napi_coerce_to_bool(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, Boolean()); return Boolean(_env, result); } inline Number Value::ToNumber() const { napi_value result; napi_status status = napi_coerce_to_number(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, Number()); return Number(_env, result); } inline String Value::ToString() const { napi_value result; napi_status status = napi_coerce_to_string(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, String()); return String(_env, result); } inline Object Value::ToObject() const { napi_value result; napi_status status = napi_coerce_to_object(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, Object()); return Object(_env, result); } //////////////////////////////////////////////////////////////////////////////// // Boolean class //////////////////////////////////////////////////////////////////////////////// inline Boolean Boolean::New(napi_env env, bool val) { napi_value value; napi_status status = napi_get_boolean(env, val, &value); NAPI_THROW_IF_FAILED(env, status, Boolean()); return Boolean(env, value); } inline Boolean::Boolean() : Napi::Value() { } inline Boolean::Boolean(napi_env env, napi_value value) : Napi::Value(env, value) { } inline Boolean::operator bool() const { return Value(); } inline bool Boolean::Value() const { bool result; napi_status status = napi_get_value_bool(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } //////////////////////////////////////////////////////////////////////////////// // Number class //////////////////////////////////////////////////////////////////////////////// inline Number Number::New(napi_env env, double val) { napi_value value; napi_status status = napi_create_double(env, val, &value); NAPI_THROW_IF_FAILED(env, status, Number()); return Number(env, value); } inline Number::Number() : Value() { } inline Number::Number(napi_env env, napi_value value) : Value(env, value) { } inline Number::operator int32_t() const { return Int32Value(); } inline Number::operator uint32_t() const { return Uint32Value(); } inline Number::operator int64_t() const { return Int64Value(); } inline Number::operator float() const { return FloatValue(); } inline Number::operator double() const { return DoubleValue(); } inline int32_t Number::Int32Value() const { int32_t result; napi_status status = napi_get_value_int32(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } inline uint32_t Number::Uint32Value() const { uint32_t result; napi_status status = napi_get_value_uint32(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } inline int64_t Number::Int64Value() const { int64_t result; napi_status status = napi_get_value_int64(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } inline float Number::FloatValue() const { return static_cast(DoubleValue()); } inline double Number::DoubleValue() const { double result; napi_status status = napi_get_value_double(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } #if NAPI_VERSION > 5 //////////////////////////////////////////////////////////////////////////////// // BigInt Class //////////////////////////////////////////////////////////////////////////////// inline BigInt BigInt::New(napi_env env, int64_t val) { napi_value value; napi_status status = napi_create_bigint_int64(env, val, &value); NAPI_THROW_IF_FAILED(env, status, BigInt()); return BigInt(env, value); } inline BigInt BigInt::New(napi_env env, uint64_t val) { napi_value value; napi_status status = napi_create_bigint_uint64(env, val, &value); NAPI_THROW_IF_FAILED(env, status, BigInt()); return BigInt(env, value); } inline BigInt BigInt::New(napi_env env, int sign_bit, size_t word_count, const uint64_t* words) { napi_value value; napi_status status = napi_create_bigint_words(env, sign_bit, word_count, words, &value); NAPI_THROW_IF_FAILED(env, status, BigInt()); return BigInt(env, value); } inline BigInt::BigInt() : Value() { } inline BigInt::BigInt(napi_env env, napi_value value) : Value(env, value) { } inline int64_t BigInt::Int64Value(bool* lossless) const { int64_t result; napi_status status = napi_get_value_bigint_int64( _env, _value, &result, lossless); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } inline uint64_t BigInt::Uint64Value(bool* lossless) const { uint64_t result; napi_status status = napi_get_value_bigint_uint64( _env, _value, &result, lossless); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } inline size_t BigInt::WordCount() const { size_t word_count; napi_status status = napi_get_value_bigint_words( _env, _value, nullptr, &word_count, nullptr); NAPI_THROW_IF_FAILED(_env, status, 0); return word_count; } inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words) { napi_status status = napi_get_value_bigint_words( _env, _value, sign_bit, word_count, words); NAPI_THROW_IF_FAILED_VOID(_env, status); } #endif // NAPI_VERSION > 5 #if (NAPI_VERSION > 4) //////////////////////////////////////////////////////////////////////////////// // Date Class //////////////////////////////////////////////////////////////////////////////// inline Date Date::New(napi_env env, double val) { napi_value value; napi_status status = napi_create_date(env, val, &value); NAPI_THROW_IF_FAILED(env, status, Date()); return Date(env, value); } inline Date::Date() : Value() { } inline Date::Date(napi_env env, napi_value value) : Value(env, value) { } inline Date::operator double() const { return ValueOf(); } inline double Date::ValueOf() const { double result; napi_status status = napi_get_date_value( _env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } #endif //////////////////////////////////////////////////////////////////////////////// // Name class //////////////////////////////////////////////////////////////////////////////// inline Name::Name() : Value() { } inline Name::Name(napi_env env, napi_value value) : Value(env, value) { } //////////////////////////////////////////////////////////////////////////////// // String class //////////////////////////////////////////////////////////////////////////////// inline String String::New(napi_env env, const std::string& val) { return String::New(env, val.c_str(), val.size()); } inline String String::New(napi_env env, const std::u16string& val) { return String::New(env, val.c_str(), val.size()); } inline String String::New(napi_env env, const char* val) { napi_value value; napi_status status = napi_create_string_utf8(env, val, std::strlen(val), &value); NAPI_THROW_IF_FAILED(env, status, String()); return String(env, value); } inline String String::New(napi_env env, const char16_t* val) { napi_value value; napi_status status = napi_create_string_utf16(env, val, std::u16string(val).size(), &value); NAPI_THROW_IF_FAILED(env, status, String()); return String(env, value); } inline String String::New(napi_env env, const char* val, size_t length) { napi_value value; napi_status status = napi_create_string_utf8(env, val, length, &value); NAPI_THROW_IF_FAILED(env, status, String()); return String(env, value); } inline String String::New(napi_env env, const char16_t* val, size_t length) { napi_value value; napi_status status = napi_create_string_utf16(env, val, length, &value); NAPI_THROW_IF_FAILED(env, status, String()); return String(env, value); } inline String::String() : Name() { } inline String::String(napi_env env, napi_value value) : Name(env, value) { } inline String::operator std::string() const { return Utf8Value(); } inline String::operator std::u16string() const { return Utf16Value(); } inline std::string String::Utf8Value() const { size_t length; napi_status status = napi_get_value_string_utf8(_env, _value, nullptr, 0, &length); NAPI_THROW_IF_FAILED(_env, status, ""); std::string value; value.reserve(length + 1); value.resize(length); status = napi_get_value_string_utf8(_env, _value, &value[0], value.capacity(), nullptr); NAPI_THROW_IF_FAILED(_env, status, ""); return value; } inline std::u16string String::Utf16Value() const { size_t length; napi_status status = napi_get_value_string_utf16(_env, _value, nullptr, 0, &length); NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); std::u16string value; value.reserve(length + 1); value.resize(length); status = napi_get_value_string_utf16(_env, _value, &value[0], value.capacity(), nullptr); NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); return value; } //////////////////////////////////////////////////////////////////////////////// // Symbol class //////////////////////////////////////////////////////////////////////////////// inline Symbol Symbol::New(napi_env env, const char* description) { napi_value descriptionValue = description != nullptr ? String::New(env, description) : static_cast(nullptr); return Symbol::New(env, descriptionValue); } inline Symbol Symbol::New(napi_env env, const std::string& description) { napi_value descriptionValue = String::New(env, description); return Symbol::New(env, descriptionValue); } inline Symbol Symbol::New(napi_env env, String description) { napi_value descriptionValue = description; return Symbol::New(env, descriptionValue); } inline Symbol Symbol::New(napi_env env, napi_value description) { napi_value value; napi_status status = napi_create_symbol(env, description, &value); NAPI_THROW_IF_FAILED(env, status, Symbol()); return Symbol(env, value); } inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) { return Napi::Env(env).Global().Get("Symbol").As().Get(name).As(); } inline Symbol::Symbol() : Name() { } inline Symbol::Symbol(napi_env env, napi_value value) : Name(env, value) { } //////////////////////////////////////////////////////////////////////////////// // Automagic value creation //////////////////////////////////////////////////////////////////////////////// namespace details { template struct vf_number { static Number From(napi_env env, T value) { return Number::New(env, static_cast(value)); } }; template<> struct vf_number { static Boolean From(napi_env env, bool value) { return Boolean::New(env, value); } }; struct vf_utf8_charp { static String From(napi_env env, const char* value) { return String::New(env, value); } }; struct vf_utf16_charp { static String From(napi_env env, const char16_t* value) { return String::New(env, value); } }; struct vf_utf8_string { static String From(napi_env env, const std::string& value) { return String::New(env, value); } }; struct vf_utf16_string { static String From(napi_env env, const std::u16string& value) { return String::New(env, value); } }; template struct vf_fallback { static Value From(napi_env env, const T& value) { return Value(env, value); } }; template struct disjunction : std::false_type {}; template struct disjunction : B {}; template struct disjunction : std::conditional>::type {}; template struct can_make_string : disjunction::type, typename std::is_convertible::type, typename std::is_convertible::type, typename std::is_convertible::type> {}; } template Value Value::From(napi_env env, const T& value) { using Helper = typename std::conditional< std::is_integral::value || std::is_floating_point::value, details::vf_number, typename std::conditional< details::can_make_string::value, String, details::vf_fallback >::type >::type; return Helper::From(env, value); } template String String::From(napi_env env, const T& value) { struct Dummy {}; using Helper = typename std::conditional< std::is_convertible::value, details::vf_utf8_charp, typename std::conditional< std::is_convertible::value, details::vf_utf16_charp, typename std::conditional< std::is_convertible::value, details::vf_utf8_string, typename std::conditional< std::is_convertible::value, details::vf_utf16_string, Dummy >::type >::type >::type >::type; return Helper::From(env, value); } //////////////////////////////////////////////////////////////////////////////// // Object class //////////////////////////////////////////////////////////////////////////////// template inline Object::PropertyLValue::operator Value() const { return Object(_env, _object).Get(_key); } template template inline Object::PropertyLValue& Object::PropertyLValue::operator =(ValueType value) { Object(_env, _object).Set(_key, value); return *this; } template inline Object::PropertyLValue::PropertyLValue(Object object, Key key) : _env(object.Env()), _object(object), _key(key) {} inline Object Object::New(napi_env env) { napi_value value; napi_status status = napi_create_object(env, &value); NAPI_THROW_IF_FAILED(env, status, Object()); return Object(env, value); } inline Object::Object() : Value() { } inline Object::Object(napi_env env, napi_value value) : Value(env, value) { } inline Object::PropertyLValue Object::operator [](const char* utf8name) { return PropertyLValue(*this, utf8name); } inline Object::PropertyLValue Object::operator [](const std::string& utf8name) { return PropertyLValue(*this, utf8name); } inline Object::PropertyLValue Object::operator [](uint32_t index) { return PropertyLValue(*this, index); } inline Value Object::operator [](const char* utf8name) const { return Get(utf8name); } inline Value Object::operator [](const std::string& utf8name) const { return Get(utf8name); } inline Value Object::operator [](uint32_t index) const { return Get(index); } inline bool Object::Has(napi_value key) const { bool result; napi_status status = napi_has_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::Has(Value key) const { bool result; napi_status status = napi_has_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::Has(const char* utf8name) const { bool result; napi_status status = napi_has_named_property(_env, _value, utf8name, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::Has(const std::string& utf8name) const { return Has(utf8name.c_str()); } inline bool Object::HasOwnProperty(napi_value key) const { bool result; napi_status status = napi_has_own_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::HasOwnProperty(Value key) const { bool result; napi_status status = napi_has_own_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::HasOwnProperty(const char* utf8name) const { napi_value key; napi_status status = napi_create_string_utf8(_env, utf8name, std::strlen(utf8name), &key); NAPI_THROW_IF_FAILED(_env, status, false); return HasOwnProperty(key); } inline bool Object::HasOwnProperty(const std::string& utf8name) const { return HasOwnProperty(utf8name.c_str()); } inline Value Object::Get(napi_value key) const { napi_value result; napi_status status = napi_get_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } inline Value Object::Get(Value key) const { napi_value result; napi_status status = napi_get_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } inline Value Object::Get(const char* utf8name) const { napi_value result; napi_status status = napi_get_named_property(_env, _value, utf8name, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } inline Value Object::Get(const std::string& utf8name) const { return Get(utf8name.c_str()); } template inline void Object::Set(napi_value key, const ValueType& value) { napi_status status = napi_set_property(_env, _value, key, Value::From(_env, value)); NAPI_THROW_IF_FAILED_VOID(_env, status); } template inline void Object::Set(Value key, const ValueType& value) { napi_status status = napi_set_property(_env, _value, key, Value::From(_env, value)); NAPI_THROW_IF_FAILED_VOID(_env, status); } template inline void Object::Set(const char* utf8name, const ValueType& value) { napi_status status = napi_set_named_property(_env, _value, utf8name, Value::From(_env, value)); NAPI_THROW_IF_FAILED_VOID(_env, status); } template inline void Object::Set(const std::string& utf8name, const ValueType& value) { Set(utf8name.c_str(), value); } inline bool Object::Delete(napi_value key) { bool result; napi_status status = napi_delete_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::Delete(Value key) { bool result; napi_status status = napi_delete_property(_env, _value, key, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline bool Object::Delete(const char* utf8name) { return Delete(String::New(_env, utf8name)); } inline bool Object::Delete(const std::string& utf8name) { return Delete(String::New(_env, utf8name)); } inline bool Object::Has(uint32_t index) const { bool result; napi_status status = napi_has_element(_env, _value, index, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline Value Object::Get(uint32_t index) const { napi_value value; napi_status status = napi_get_element(_env, _value, index, &value); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, value); } template inline void Object::Set(uint32_t index, const ValueType& value) { napi_status status = napi_set_element(_env, _value, index, Value::From(_env, value)); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline bool Object::Delete(uint32_t index) { bool result; napi_status status = napi_delete_element(_env, _value, index, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } inline Array Object::GetPropertyNames() const { napi_value result; napi_status status = napi_get_property_names(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, Array()); return Array(_env, result); } inline void Object::DefineProperty(const PropertyDescriptor& property) { napi_status status = napi_define_properties(_env, _value, 1, reinterpret_cast(&property)); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline void Object::DefineProperties(const std::initializer_list& properties) { napi_status status = napi_define_properties(_env, _value, properties.size(), reinterpret_cast(properties.begin())); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline void Object::DefineProperties(const std::vector& properties) { napi_status status = napi_define_properties(_env, _value, properties.size(), reinterpret_cast(properties.data())); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline bool Object::InstanceOf(const Function& constructor) const { bool result; napi_status status = napi_instanceof(_env, _value, constructor, &result); NAPI_THROW_IF_FAILED(_env, status, false); return result; } template inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) { details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, nullptr }); napi_status status = details::AttachData(_env, *this, data, details::FinalizeData::Wrapper, finalizeData); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED_VOID(_env, status); } } template inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data, Hint* finalizeHint) { details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, finalizeHint }); napi_status status = details::AttachData(_env, *this, data, details::FinalizeData::WrapperWithHint, finalizeData); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED_VOID(_env, status); } } //////////////////////////////////////////////////////////////////////////////// // External class //////////////////////////////////////////////////////////////////////////////// template inline External External::New(napi_env env, T* data) { napi_value value; napi_status status = napi_create_external(env, data, nullptr, nullptr, &value); NAPI_THROW_IF_FAILED(env, status, External()); return External(env, value); } template template inline External External::New(napi_env env, T* data, Finalizer finalizeCallback) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, nullptr }); napi_status status = napi_create_external( env, data, details::FinalizeData::Wrapper, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, External()); } return External(env, value); } template template inline External External::New(napi_env env, T* data, Finalizer finalizeCallback, Hint* finalizeHint) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, finalizeHint }); napi_status status = napi_create_external( env, data, details::FinalizeData::WrapperWithHint, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, External()); } return External(env, value); } template inline External::External() : Value() { } template inline External::External(napi_env env, napi_value value) : Value(env, value) { } template inline T* External::Data() const { void* data; napi_status status = napi_get_value_external(_env, _value, &data); NAPI_THROW_IF_FAILED(_env, status, nullptr); return reinterpret_cast(data); } //////////////////////////////////////////////////////////////////////////////// // Array class //////////////////////////////////////////////////////////////////////////////// inline Array Array::New(napi_env env) { napi_value value; napi_status status = napi_create_array(env, &value); NAPI_THROW_IF_FAILED(env, status, Array()); return Array(env, value); } inline Array Array::New(napi_env env, size_t length) { napi_value value; napi_status status = napi_create_array_with_length(env, length, &value); NAPI_THROW_IF_FAILED(env, status, Array()); return Array(env, value); } inline Array::Array() : Object() { } inline Array::Array(napi_env env, napi_value value) : Object(env, value) { } inline uint32_t Array::Length() const { uint32_t result; napi_status status = napi_get_array_length(_env, _value, &result); NAPI_THROW_IF_FAILED(_env, status, 0); return result; } //////////////////////////////////////////////////////////////////////////////// // ArrayBuffer class //////////////////////////////////////////////////////////////////////////////// inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) { napi_value value; void* data; napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value); NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); return ArrayBuffer(env, value); } inline ArrayBuffer ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength) { napi_value value; napi_status status = napi_create_external_arraybuffer( env, externalData, byteLength, nullptr, nullptr, &value); NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); return ArrayBuffer(env, value); } template inline ArrayBuffer ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength, Finalizer finalizeCallback) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, nullptr }); napi_status status = napi_create_external_arraybuffer( env, externalData, byteLength, details::FinalizeData::Wrapper, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); } return ArrayBuffer(env, value); } template inline ArrayBuffer ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength, Finalizer finalizeCallback, Hint* finalizeHint) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, finalizeHint }); napi_status status = napi_create_external_arraybuffer( env, externalData, byteLength, details::FinalizeData::WrapperWithHint, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); } return ArrayBuffer(env, value); } inline ArrayBuffer::ArrayBuffer() : Object() { } inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value) : Object(env, value) { } inline void* ArrayBuffer::Data() { void* data; napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr); NAPI_THROW_IF_FAILED(_env, status, nullptr); return data; } inline size_t ArrayBuffer::ByteLength() { size_t length; napi_status status = napi_get_arraybuffer_info(_env, _value, nullptr, &length); NAPI_THROW_IF_FAILED(_env, status, 0); return length; } #if NAPI_VERSION >= 7 inline bool ArrayBuffer::IsDetached() const { bool detached; napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached); NAPI_THROW_IF_FAILED(_env, status, false); return detached; } inline void ArrayBuffer::Detach() { napi_status status = napi_detach_arraybuffer(_env, _value); NAPI_THROW_IF_FAILED_VOID(_env, status); } #endif // NAPI_VERSION >= 7 //////////////////////////////////////////////////////////////////////////////// // DataView class //////////////////////////////////////////////////////////////////////////////// inline DataView DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer) { return New(env, arrayBuffer, 0, arrayBuffer.ByteLength()); } inline DataView DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset) { if (byteOffset > arrayBuffer.ByteLength()) { NAPI_THROW(RangeError::New(env, "Start offset is outside the bounds of the buffer"), DataView()); } return New(env, arrayBuffer, byteOffset, arrayBuffer.ByteLength() - byteOffset); } inline DataView DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset, size_t byteLength) { if (byteOffset + byteLength > arrayBuffer.ByteLength()) { NAPI_THROW(RangeError::New(env, "Invalid DataView length"), DataView()); } napi_value value; napi_status status = napi_create_dataview( env, byteLength, arrayBuffer, byteOffset, &value); NAPI_THROW_IF_FAILED(env, status, DataView()); return DataView(env, value); } inline DataView::DataView() : Object() { } inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) { napi_status status = napi_get_dataview_info( _env, _value /* dataView */, &_length /* byteLength */, &_data /* data */, nullptr /* arrayBuffer */, nullptr /* byteOffset */); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline Napi::ArrayBuffer DataView::ArrayBuffer() const { napi_value arrayBuffer; napi_status status = napi_get_dataview_info( _env, _value /* dataView */, nullptr /* byteLength */, nullptr /* data */, &arrayBuffer /* arrayBuffer */, nullptr /* byteOffset */); NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); return Napi::ArrayBuffer(_env, arrayBuffer); } inline size_t DataView::ByteOffset() const { size_t byteOffset; napi_status status = napi_get_dataview_info( _env, _value /* dataView */, nullptr /* byteLength */, nullptr /* data */, nullptr /* arrayBuffer */, &byteOffset /* byteOffset */); NAPI_THROW_IF_FAILED(_env, status, 0); return byteOffset; } inline size_t DataView::ByteLength() const { return _length; } inline void* DataView::Data() const { return _data; } inline float DataView::GetFloat32(size_t byteOffset) const { return ReadData(byteOffset); } inline double DataView::GetFloat64(size_t byteOffset) const { return ReadData(byteOffset); } inline int8_t DataView::GetInt8(size_t byteOffset) const { return ReadData(byteOffset); } inline int16_t DataView::GetInt16(size_t byteOffset) const { return ReadData(byteOffset); } inline int32_t DataView::GetInt32(size_t byteOffset) const { return ReadData(byteOffset); } inline uint8_t DataView::GetUint8(size_t byteOffset) const { return ReadData(byteOffset); } inline uint16_t DataView::GetUint16(size_t byteOffset) const { return ReadData(byteOffset); } inline uint32_t DataView::GetUint32(size_t byteOffset) const { return ReadData(byteOffset); } inline void DataView::SetFloat32(size_t byteOffset, float value) const { WriteData(byteOffset, value); } inline void DataView::SetFloat64(size_t byteOffset, double value) const { WriteData(byteOffset, value); } inline void DataView::SetInt8(size_t byteOffset, int8_t value) const { WriteData(byteOffset, value); } inline void DataView::SetInt16(size_t byteOffset, int16_t value) const { WriteData(byteOffset, value); } inline void DataView::SetInt32(size_t byteOffset, int32_t value) const { WriteData(byteOffset, value); } inline void DataView::SetUint8(size_t byteOffset, uint8_t value) const { WriteData(byteOffset, value); } inline void DataView::SetUint16(size_t byteOffset, uint16_t value) const { WriteData(byteOffset, value); } inline void DataView::SetUint32(size_t byteOffset, uint32_t value) const { WriteData(byteOffset, value); } template inline T DataView::ReadData(size_t byteOffset) const { if (byteOffset + sizeof(T) > _length || byteOffset + sizeof(T) < byteOffset) { // overflow NAPI_THROW(RangeError::New(_env, "Offset is outside the bounds of the DataView"), 0); } return *reinterpret_cast(static_cast(_data) + byteOffset); } template inline void DataView::WriteData(size_t byteOffset, T value) const { if (byteOffset + sizeof(T) > _length || byteOffset + sizeof(T) < byteOffset) { // overflow NAPI_THROW_VOID(RangeError::New(_env, "Offset is outside the bounds of the DataView")); } *reinterpret_cast(static_cast(_data) + byteOffset) = value; } //////////////////////////////////////////////////////////////////////////////// // TypedArray class //////////////////////////////////////////////////////////////////////////////// inline TypedArray::TypedArray() : Object(), _type(TypedArray::unknown_array_type), _length(0) { } inline TypedArray::TypedArray(napi_env env, napi_value value) : Object(env, value), _type(TypedArray::unknown_array_type), _length(0) { } inline TypedArray::TypedArray(napi_env env, napi_value value, napi_typedarray_type type, size_t length) : Object(env, value), _type(type), _length(length) { } inline napi_typedarray_type TypedArray::TypedArrayType() const { if (_type == TypedArray::unknown_array_type) { napi_status status = napi_get_typedarray_info(_env, _value, &const_cast(this)->_type, &const_cast(this)->_length, nullptr, nullptr, nullptr); NAPI_THROW_IF_FAILED(_env, status, napi_int8_array); } return _type; } inline uint8_t TypedArray::ElementSize() const { switch (TypedArrayType()) { case napi_int8_array: case napi_uint8_array: case napi_uint8_clamped_array: return 1; case napi_int16_array: case napi_uint16_array: return 2; case napi_int32_array: case napi_uint32_array: case napi_float32_array: return 4; case napi_float64_array: #if (NAPI_VERSION > 5) case napi_bigint64_array: case napi_biguint64_array: #endif // (NAPI_VERSION > 5) return 8; default: return 0; } } inline size_t TypedArray::ElementLength() const { if (_type == TypedArray::unknown_array_type) { napi_status status = napi_get_typedarray_info(_env, _value, &const_cast(this)->_type, &const_cast(this)->_length, nullptr, nullptr, nullptr); NAPI_THROW_IF_FAILED(_env, status, 0); } return _length; } inline size_t TypedArray::ByteOffset() const { size_t byteOffset; napi_status status = napi_get_typedarray_info( _env, _value, nullptr, nullptr, nullptr, nullptr, &byteOffset); NAPI_THROW_IF_FAILED(_env, status, 0); return byteOffset; } inline size_t TypedArray::ByteLength() const { return ElementSize() * ElementLength(); } inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const { napi_value arrayBuffer; napi_status status = napi_get_typedarray_info( _env, _value, nullptr, nullptr, nullptr, &arrayBuffer, nullptr); NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); return Napi::ArrayBuffer(_env, arrayBuffer); } //////////////////////////////////////////////////////////////////////////////// // TypedArrayOf class //////////////////////////////////////////////////////////////////////////////// template inline TypedArrayOf TypedArrayOf::New(napi_env env, size_t elementLength, napi_typedarray_type type) { Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(env, elementLength * sizeof (T)); return New(env, elementLength, arrayBuffer, 0, type); } template inline TypedArrayOf TypedArrayOf::New(napi_env env, size_t elementLength, Napi::ArrayBuffer arrayBuffer, size_t bufferOffset, napi_typedarray_type type) { napi_value value; napi_status status = napi_create_typedarray( env, type, elementLength, arrayBuffer, bufferOffset, &value); NAPI_THROW_IF_FAILED(env, status, TypedArrayOf()); return TypedArrayOf( env, value, type, elementLength, reinterpret_cast(reinterpret_cast(arrayBuffer.Data()) + bufferOffset)); } template inline TypedArrayOf::TypedArrayOf() : TypedArray(), _data(nullptr) { } template inline TypedArrayOf::TypedArrayOf(napi_env env, napi_value value) : TypedArray(env, value), _data(nullptr) { napi_status status = napi_ok; if (value != nullptr) { status = napi_get_typedarray_info( _env, _value, &_type, &_length, reinterpret_cast(&_data), nullptr, nullptr); } else { _type = TypedArrayTypeForPrimitiveType(); _length = 0; } NAPI_THROW_IF_FAILED_VOID(_env, status); } template inline TypedArrayOf::TypedArrayOf(napi_env env, napi_value value, napi_typedarray_type type, size_t length, T* data) : TypedArray(env, value, type, length), _data(data) { if (!(type == TypedArrayTypeForPrimitiveType() || (type == napi_uint8_clamped_array && std::is_same::value))) { NAPI_THROW_VOID(TypeError::New(env, "Array type must match the template parameter. " "(Uint8 arrays may optionally have the \"clamped\" array type.)")); } } template inline T& TypedArrayOf::operator [](size_t index) { return _data[index]; } template inline const T& TypedArrayOf::operator [](size_t index) const { return _data[index]; } template inline T* TypedArrayOf::Data() { return _data; } template inline const T* TypedArrayOf::Data() const { return _data; } //////////////////////////////////////////////////////////////////////////////// // Function class //////////////////////////////////////////////////////////////////////////////// template static inline napi_status CreateFunction(napi_env env, const char* utf8name, napi_callback cb, CbData* data, napi_value* result) { napi_status status = napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, cb, data, result); if (status == napi_ok) { status = Napi::details::AttachData(env, *result, data); } return status; } template inline Function Function::New(napi_env env, const char* utf8name, void* data) { napi_value result = nullptr; napi_status status = napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, details::TemplatedVoidCallback, data, &result); NAPI_THROW_IF_FAILED(env, status, Function()); return Function(env, result); } template inline Function Function::New(napi_env env, const char* utf8name, void* data) { napi_value result = nullptr; napi_status status = napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, details::TemplatedCallback, data, &result); NAPI_THROW_IF_FAILED(env, status, Function()); return Function(env, result); } template inline Function Function::New(napi_env env, const std::string& utf8name, void* data) { return Function::New(env, utf8name.c_str(), data); } template inline Function Function::New(napi_env env, const std::string& utf8name, void* data) { return Function::New(env, utf8name.c_str(), data); } template inline Function Function::New(napi_env env, Callable cb, const char* utf8name, void* data) { typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; typedef details::CallbackData CbData; auto callbackData = new CbData({ cb, data }); napi_value value; napi_status status = CreateFunction(env, utf8name, CbData::Wrapper, callbackData, &value); if (status != napi_ok) { delete callbackData; NAPI_THROW_IF_FAILED(env, status, Function()); } return Function(env, value); } template inline Function Function::New(napi_env env, Callable cb, const std::string& utf8name, void* data) { return New(env, cb, utf8name.c_str(), data); } inline Function::Function() : Object() { } inline Function::Function(napi_env env, napi_value value) : Object(env, value) { } inline Value Function::operator ()(const std::initializer_list& args) const { return Call(Env().Undefined(), args); } inline Value Function::Call(const std::initializer_list& args) const { return Call(Env().Undefined(), args); } inline Value Function::Call(const std::vector& args) const { return Call(Env().Undefined(), args); } inline Value Function::Call(size_t argc, const napi_value* args) const { return Call(Env().Undefined(), argc, args); } inline Value Function::Call(napi_value recv, const std::initializer_list& args) const { return Call(recv, args.size(), args.begin()); } inline Value Function::Call(napi_value recv, const std::vector& args) const { return Call(recv, args.size(), args.data()); } inline Value Function::Call(napi_value recv, size_t argc, const napi_value* args) const { napi_value result; napi_status status = napi_call_function( _env, recv, _value, argc, args, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } inline Value Function::MakeCallback( napi_value recv, const std::initializer_list& args, napi_async_context context) const { return MakeCallback(recv, args.size(), args.begin(), context); } inline Value Function::MakeCallback( napi_value recv, const std::vector& args, napi_async_context context) const { return MakeCallback(recv, args.size(), args.data(), context); } inline Value Function::MakeCallback( napi_value recv, size_t argc, const napi_value* args, napi_async_context context) const { napi_value result; napi_status status = napi_make_callback( _env, context, recv, _value, argc, args, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } inline Object Function::New(const std::initializer_list& args) const { return New(args.size(), args.begin()); } inline Object Function::New(const std::vector& args) const { return New(args.size(), args.data()); } inline Object Function::New(size_t argc, const napi_value* args) const { napi_value result; napi_status status = napi_new_instance( _env, _value, argc, args, &result); NAPI_THROW_IF_FAILED(_env, status, Object()); return Object(_env, result); } //////////////////////////////////////////////////////////////////////////////// // Promise class //////////////////////////////////////////////////////////////////////////////// inline Promise::Deferred Promise::Deferred::New(napi_env env) { return Promise::Deferred(env); } inline Promise::Deferred::Deferred(napi_env env) : _env(env) { napi_status status = napi_create_promise(_env, &_deferred, &_promise); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline Promise Promise::Deferred::Promise() const { return Napi::Promise(_env, _promise); } inline Napi::Env Promise::Deferred::Env() const { return Napi::Env(_env); } inline void Promise::Deferred::Resolve(napi_value value) const { napi_status status = napi_resolve_deferred(_env, _deferred, value); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline void Promise::Deferred::Reject(napi_value value) const { napi_status status = napi_reject_deferred(_env, _deferred, value); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) { } //////////////////////////////////////////////////////////////////////////////// // Buffer class //////////////////////////////////////////////////////////////////////////////// template inline Buffer Buffer::New(napi_env env, size_t length) { napi_value value; void* data; napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value); NAPI_THROW_IF_FAILED(env, status, Buffer()); return Buffer(env, value, length, static_cast(data)); } template inline Buffer Buffer::New(napi_env env, T* data, size_t length) { napi_value value; napi_status status = napi_create_external_buffer( env, length * sizeof (T), data, nullptr, nullptr, &value); NAPI_THROW_IF_FAILED(env, status, Buffer()); return Buffer(env, value, length, data); } template template inline Buffer Buffer::New(napi_env env, T* data, size_t length, Finalizer finalizeCallback) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, nullptr }); napi_status status = napi_create_external_buffer( env, length * sizeof (T), data, details::FinalizeData::Wrapper, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, Buffer()); } return Buffer(env, value, length, data); } template template inline Buffer Buffer::New(napi_env env, T* data, size_t length, Finalizer finalizeCallback, Hint* finalizeHint) { napi_value value; details::FinalizeData* finalizeData = new details::FinalizeData({ finalizeCallback, finalizeHint }); napi_status status = napi_create_external_buffer( env, length * sizeof (T), data, details::FinalizeData::WrapperWithHint, finalizeData, &value); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, Buffer()); } return Buffer(env, value, length, data); } template inline Buffer Buffer::Copy(napi_env env, const T* data, size_t length) { napi_value value; napi_status status = napi_create_buffer_copy( env, length * sizeof (T), data, nullptr, &value); NAPI_THROW_IF_FAILED(env, status, Buffer()); return Buffer(env, value); } template inline Buffer::Buffer() : Uint8Array(), _length(0), _data(nullptr) { } template inline Buffer::Buffer(napi_env env, napi_value value) : Uint8Array(env, value), _length(0), _data(nullptr) { } template inline Buffer::Buffer(napi_env env, napi_value value, size_t length, T* data) : Uint8Array(env, value), _length(length), _data(data) { } template inline size_t Buffer::Length() const { EnsureInfo(); return _length; } template inline T* Buffer::Data() const { EnsureInfo(); return _data; } template inline void Buffer::EnsureInfo() const { // The Buffer instance may have been constructed from a napi_value whose // length/data are not yet known. Fetch and cache these values just once, // since they can never change during the lifetime of the Buffer. if (_data == nullptr) { size_t byteLength; void* voidData; napi_status status = napi_get_buffer_info(_env, _value, &voidData, &byteLength); NAPI_THROW_IF_FAILED_VOID(_env, status); _length = byteLength / sizeof (T); _data = static_cast(voidData); } } //////////////////////////////////////////////////////////////////////////////// // Error class //////////////////////////////////////////////////////////////////////////////// inline Error Error::New(napi_env env) { napi_status status; napi_value error = nullptr; bool is_exception_pending; const napi_extended_error_info* info; // We must retrieve the last error info before doing anything else, because // doing anything else will replace the last error info. status = napi_get_last_error_info(env, &info); NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info"); status = napi_is_exception_pending(env, &is_exception_pending); NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending"); // A pending exception takes precedence over any internal error status. if (is_exception_pending) { status = napi_get_and_clear_last_exception(env, &error); NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception"); } else { const char* error_message = info->error_message != nullptr ? info->error_message : "Error in native callback"; napi_value message; status = napi_create_string_utf8( env, error_message, std::strlen(error_message), &message); NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8"); switch (info->error_code) { case napi_object_expected: case napi_string_expected: case napi_boolean_expected: case napi_number_expected: status = napi_create_type_error(env, nullptr, message, &error); break; default: status = napi_create_error(env, nullptr, message, &error); break; } NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error"); } return Error(env, error); } inline Error Error::New(napi_env env, const char* message) { return Error::New(env, message, std::strlen(message), napi_create_error); } inline Error Error::New(napi_env env, const std::string& message) { return Error::New(env, message.c_str(), message.size(), napi_create_error); } inline NAPI_NO_RETURN void Error::Fatal(const char* location, const char* message) { napi_fatal_error(location, NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH); } inline Error::Error() : ObjectReference() { } inline Error::Error(napi_env env, napi_value value) : ObjectReference(env, nullptr) { if (value != nullptr) { napi_status status = napi_create_reference(env, value, 1, &_ref); // Avoid infinite recursion in the failure case. // Don't try to construct & throw another Error instance. NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_reference"); } } inline Error::Error(Error&& other) : ObjectReference(std::move(other)) { } inline Error& Error::operator =(Error&& other) { static_cast*>(this)->operator=(std::move(other)); return *this; } inline Error::Error(const Error& other) : ObjectReference(other) { } inline Error& Error::operator =(const Error& other) { Reset(); _env = other.Env(); HandleScope scope(_env); napi_value value = other.Value(); if (value != nullptr) { napi_status status = napi_create_reference(_env, value, 1, &_ref); NAPI_THROW_IF_FAILED(_env, status, *this); } return *this; } inline const std::string& Error::Message() const NAPI_NOEXCEPT { if (_message.size() == 0 && _env != nullptr) { #ifdef NAPI_CPP_EXCEPTIONS try { _message = Get("message").As(); } catch (...) { // Catch all errors here, to include e.g. a std::bad_alloc from // the std::string::operator=, because this method may not throw. } #else // NAPI_CPP_EXCEPTIONS _message = Get("message").As(); #endif // NAPI_CPP_EXCEPTIONS } return _message; } inline void Error::ThrowAsJavaScriptException() const { HandleScope scope(_env); if (!IsEmpty()) { // We intentionally don't use `NAPI_THROW_*` macros here to ensure // that there is no possible recursion as `ThrowAsJavaScriptException` // is part of `NAPI_THROW_*` macro definition for noexcept. napi_status status = napi_throw(_env, Value()); #ifdef NAPI_CPP_EXCEPTIONS if (status != napi_ok) { throw Error::New(_env); } #else // NAPI_CPP_EXCEPTIONS NAPI_FATAL_IF_FAILED(status, "Error::ThrowAsJavaScriptException", "napi_throw"); #endif // NAPI_CPP_EXCEPTIONS } } #ifdef NAPI_CPP_EXCEPTIONS inline const char* Error::what() const NAPI_NOEXCEPT { return Message().c_str(); } #endif // NAPI_CPP_EXCEPTIONS template inline TError Error::New(napi_env env, const char* message, size_t length, create_error_fn create_error) { napi_value str; napi_status status = napi_create_string_utf8(env, message, length, &str); NAPI_THROW_IF_FAILED(env, status, TError()); napi_value error; status = create_error(env, nullptr, str, &error); NAPI_THROW_IF_FAILED(env, status, TError()); return TError(env, error); } inline TypeError TypeError::New(napi_env env, const char* message) { return Error::New(env, message, std::strlen(message), napi_create_type_error); } inline TypeError TypeError::New(napi_env env, const std::string& message) { return Error::New(env, message.c_str(), message.size(), napi_create_type_error); } inline TypeError::TypeError() : Error() { } inline TypeError::TypeError(napi_env env, napi_value value) : Error(env, value) { } inline RangeError RangeError::New(napi_env env, const char* message) { return Error::New(env, message, std::strlen(message), napi_create_range_error); } inline RangeError RangeError::New(napi_env env, const std::string& message) { return Error::New(env, message.c_str(), message.size(), napi_create_range_error); } inline RangeError::RangeError() : Error() { } inline RangeError::RangeError(napi_env env, napi_value value) : Error(env, value) { } //////////////////////////////////////////////////////////////////////////////// // Reference class //////////////////////////////////////////////////////////////////////////////// template inline Reference Reference::New(const T& value, uint32_t initialRefcount) { napi_env env = value.Env(); napi_value val = value; if (val == nullptr) { return Reference(env, nullptr); } napi_ref ref; napi_status status = napi_create_reference(env, value, initialRefcount, &ref); NAPI_THROW_IF_FAILED(env, status, Reference()); return Reference(env, ref); } template inline Reference::Reference() : _env(nullptr), _ref(nullptr), _suppressDestruct(false) { } template inline Reference::Reference(napi_env env, napi_ref ref) : _env(env), _ref(ref), _suppressDestruct(false) { } template inline Reference::~Reference() { if (_ref != nullptr) { if (!_suppressDestruct) { napi_delete_reference(_env, _ref); } _ref = nullptr; } } template inline Reference::Reference(Reference&& other) : _env(other._env), _ref(other._ref), _suppressDestruct(other._suppressDestruct) { other._env = nullptr; other._ref = nullptr; other._suppressDestruct = false; } template inline Reference& Reference::operator =(Reference&& other) { Reset(); _env = other._env; _ref = other._ref; _suppressDestruct = other._suppressDestruct; other._env = nullptr; other._ref = nullptr; other._suppressDestruct = false; return *this; } template inline Reference::Reference(const Reference& other) : _env(other._env), _ref(nullptr), _suppressDestruct(false) { HandleScope scope(_env); napi_value value = other.Value(); if (value != nullptr) { // Copying is a limited scenario (currently only used for Error object) and always creates a // strong reference to the given value even if the incoming reference is weak. napi_status status = napi_create_reference(_env, value, 1, &_ref); NAPI_FATAL_IF_FAILED(status, "Reference::Reference", "napi_create_reference"); } } template inline Reference::operator napi_ref() const { return _ref; } template inline bool Reference::operator ==(const Reference &other) const { HandleScope scope(_env); return this->Value().StrictEquals(other.Value()); } template inline bool Reference::operator !=(const Reference &other) const { return !this->operator ==(other); } template inline Napi::Env Reference::Env() const { return Napi::Env(_env); } template inline bool Reference::IsEmpty() const { return _ref == nullptr; } template inline T Reference::Value() const { if (_ref == nullptr) { return T(_env, nullptr); } napi_value value; napi_status status = napi_get_reference_value(_env, _ref, &value); NAPI_THROW_IF_FAILED(_env, status, T()); return T(_env, value); } template inline uint32_t Reference::Ref() { uint32_t result; napi_status status = napi_reference_ref(_env, _ref, &result); NAPI_THROW_IF_FAILED(_env, status, 1); return result; } template inline uint32_t Reference::Unref() { uint32_t result; napi_status status = napi_reference_unref(_env, _ref, &result); NAPI_THROW_IF_FAILED(_env, status, 1); return result; } template inline void Reference::Reset() { if (_ref != nullptr) { napi_status status = napi_delete_reference(_env, _ref); NAPI_THROW_IF_FAILED_VOID(_env, status); _ref = nullptr; } } template inline void Reference::Reset(const T& value, uint32_t refcount) { Reset(); _env = value.Env(); napi_value val = value; if (val != nullptr) { napi_status status = napi_create_reference(_env, value, refcount, &_ref); NAPI_THROW_IF_FAILED_VOID(_env, status); } } template inline void Reference::SuppressDestruct() { _suppressDestruct = true; } template inline Reference Weak(T value) { return Reference::New(value, 0); } inline ObjectReference Weak(Object value) { return Reference::New(value, 0); } inline FunctionReference Weak(Function value) { return Reference::New(value, 0); } template inline Reference Persistent(T value) { return Reference::New(value, 1); } inline ObjectReference Persistent(Object value) { return Reference::New(value, 1); } inline FunctionReference Persistent(Function value) { return Reference::New(value, 1); } //////////////////////////////////////////////////////////////////////////////// // ObjectReference class //////////////////////////////////////////////////////////////////////////////// inline ObjectReference::ObjectReference(): Reference() { } inline ObjectReference::ObjectReference(napi_env env, napi_ref ref): Reference(env, ref) { } inline ObjectReference::ObjectReference(Reference&& other) : Reference(std::move(other)) { } inline ObjectReference& ObjectReference::operator =(Reference&& other) { static_cast*>(this)->operator=(std::move(other)); return *this; } inline ObjectReference::ObjectReference(ObjectReference&& other) : Reference(std::move(other)) { } inline ObjectReference& ObjectReference::operator =(ObjectReference&& other) { static_cast*>(this)->operator=(std::move(other)); return *this; } inline ObjectReference::ObjectReference(const ObjectReference& other) : Reference(other) { } inline Napi::Value ObjectReference::Get(const char* utf8name) const { EscapableHandleScope scope(_env); return scope.Escape(Value().Get(utf8name)); } inline Napi::Value ObjectReference::Get(const std::string& utf8name) const { EscapableHandleScope scope(_env); return scope.Escape(Value().Get(utf8name)); } inline void ObjectReference::Set(const char* utf8name, napi_value value) { HandleScope scope(_env); Value().Set(utf8name, value); } inline void ObjectReference::Set(const char* utf8name, Napi::Value value) { HandleScope scope(_env); Value().Set(utf8name, value); } inline void ObjectReference::Set(const char* utf8name, const char* utf8value) { HandleScope scope(_env); Value().Set(utf8name, utf8value); } inline void ObjectReference::Set(const char* utf8name, bool boolValue) { HandleScope scope(_env); Value().Set(utf8name, boolValue); } inline void ObjectReference::Set(const char* utf8name, double numberValue) { HandleScope scope(_env); Value().Set(utf8name, numberValue); } inline void ObjectReference::Set(const std::string& utf8name, napi_value value) { HandleScope scope(_env); Value().Set(utf8name, value); } inline void ObjectReference::Set(const std::string& utf8name, Napi::Value value) { HandleScope scope(_env); Value().Set(utf8name, value); } inline void ObjectReference::Set(const std::string& utf8name, std::string& utf8value) { HandleScope scope(_env); Value().Set(utf8name, utf8value); } inline void ObjectReference::Set(const std::string& utf8name, bool boolValue) { HandleScope scope(_env); Value().Set(utf8name, boolValue); } inline void ObjectReference::Set(const std::string& utf8name, double numberValue) { HandleScope scope(_env); Value().Set(utf8name, numberValue); } inline Napi::Value ObjectReference::Get(uint32_t index) const { EscapableHandleScope scope(_env); return scope.Escape(Value().Get(index)); } inline void ObjectReference::Set(uint32_t index, napi_value value) { HandleScope scope(_env); Value().Set(index, value); } inline void ObjectReference::Set(uint32_t index, Napi::Value value) { HandleScope scope(_env); Value().Set(index, value); } inline void ObjectReference::Set(uint32_t index, const char* utf8value) { HandleScope scope(_env); Value().Set(index, utf8value); } inline void ObjectReference::Set(uint32_t index, const std::string& utf8value) { HandleScope scope(_env); Value().Set(index, utf8value); } inline void ObjectReference::Set(uint32_t index, bool boolValue) { HandleScope scope(_env); Value().Set(index, boolValue); } inline void ObjectReference::Set(uint32_t index, double numberValue) { HandleScope scope(_env); Value().Set(index, numberValue); } //////////////////////////////////////////////////////////////////////////////// // FunctionReference class //////////////////////////////////////////////////////////////////////////////// inline FunctionReference::FunctionReference(): Reference() { } inline FunctionReference::FunctionReference(napi_env env, napi_ref ref) : Reference(env, ref) { } inline FunctionReference::FunctionReference(Reference&& other) : Reference(std::move(other)) { } inline FunctionReference& FunctionReference::operator =(Reference&& other) { static_cast*>(this)->operator=(std::move(other)); return *this; } inline FunctionReference::FunctionReference(FunctionReference&& other) : Reference(std::move(other)) { } inline FunctionReference& FunctionReference::operator =(FunctionReference&& other) { static_cast*>(this)->operator=(std::move(other)); return *this; } inline Napi::Value FunctionReference::operator ()( const std::initializer_list& args) const { EscapableHandleScope scope(_env); return scope.Escape(Value()(args)); } inline Napi::Value FunctionReference::Call(const std::initializer_list& args) const { EscapableHandleScope scope(_env); Napi::Value result = Value().Call(args); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::Call(const std::vector& args) const { EscapableHandleScope scope(_env); Napi::Value result = Value().Call(args); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::Call( napi_value recv, const std::initializer_list& args) const { EscapableHandleScope scope(_env); Napi::Value result = Value().Call(recv, args); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::Call( napi_value recv, const std::vector& args) const { EscapableHandleScope scope(_env); Napi::Value result = Value().Call(recv, args); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::Call( napi_value recv, size_t argc, const napi_value* args) const { EscapableHandleScope scope(_env); Napi::Value result = Value().Call(recv, argc, args); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::MakeCallback( napi_value recv, const std::initializer_list& args, napi_async_context context) const { EscapableHandleScope scope(_env); Napi::Value result = Value().MakeCallback(recv, args, context); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::MakeCallback( napi_value recv, const std::vector& args, napi_async_context context) const { EscapableHandleScope scope(_env); Napi::Value result = Value().MakeCallback(recv, args, context); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Napi::Value FunctionReference::MakeCallback( napi_value recv, size_t argc, const napi_value* args, napi_async_context context) const { EscapableHandleScope scope(_env); Napi::Value result = Value().MakeCallback(recv, argc, args, context); if (scope.Env().IsExceptionPending()) { return Value(); } return scope.Escape(result); } inline Object FunctionReference::New(const std::initializer_list& args) const { EscapableHandleScope scope(_env); return scope.Escape(Value().New(args)).As(); } inline Object FunctionReference::New(const std::vector& args) const { EscapableHandleScope scope(_env); return scope.Escape(Value().New(args)).As(); } //////////////////////////////////////////////////////////////////////////////// // CallbackInfo class //////////////////////////////////////////////////////////////////////////////// inline CallbackInfo::CallbackInfo(napi_env env, napi_callback_info info) : _env(env), _info(info), _this(nullptr), _dynamicArgs(nullptr), _data(nullptr) { _argc = _staticArgCount; _argv = _staticArgs; napi_status status = napi_get_cb_info(env, info, &_argc, _argv, &_this, &_data); NAPI_THROW_IF_FAILED_VOID(_env, status); if (_argc > _staticArgCount) { // Use either a fixed-size array (on the stack) or a dynamically-allocated // array (on the heap) depending on the number of args. _dynamicArgs = new napi_value[_argc]; _argv = _dynamicArgs; status = napi_get_cb_info(env, info, &_argc, _argv, nullptr, nullptr); NAPI_THROW_IF_FAILED_VOID(_env, status); } } inline CallbackInfo::~CallbackInfo() { if (_dynamicArgs != nullptr) { delete[] _dynamicArgs; } } inline Value CallbackInfo::NewTarget() const { napi_value newTarget; napi_status status = napi_get_new_target(_env, _info, &newTarget); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, newTarget); } inline bool CallbackInfo::IsConstructCall() const { return !NewTarget().IsEmpty(); } inline Napi::Env CallbackInfo::Env() const { return Napi::Env(_env); } inline size_t CallbackInfo::Length() const { return _argc; } inline const Value CallbackInfo::operator [](size_t index) const { return index < _argc ? Value(_env, _argv[index]) : Env().Undefined(); } inline Value CallbackInfo::This() const { if (_this == nullptr) { return Env().Undefined(); } return Object(_env, _this); } inline void* CallbackInfo::Data() const { return _data; } inline void CallbackInfo::SetData(void* data) { _data = data; } //////////////////////////////////////////////////////////////////////////////// // PropertyDescriptor class //////////////////////////////////////////////////////////////////////////////// template PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = details::TemplatedCallback; desc.attributes = attributes; desc.data = data; return desc; } template PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, napi_property_attributes attributes, void* data) { return Accessor(utf8name.c_str(), attributes, data); } template PropertyDescriptor PropertyDescriptor::Accessor(Name name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = details::TemplatedCallback; desc.attributes = attributes; desc.data = data; return desc; } template < typename PropertyDescriptor::GetterCallback Getter, typename PropertyDescriptor::SetterCallback Setter> PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = details::TemplatedCallback; desc.setter = details::TemplatedVoidCallback; desc.attributes = attributes; desc.data = data; return desc; } template < typename PropertyDescriptor::GetterCallback Getter, typename PropertyDescriptor::SetterCallback Setter> PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, napi_property_attributes attributes, void* data) { return Accessor(utf8name.c_str(), attributes, data); } template < typename PropertyDescriptor::GetterCallback Getter, typename PropertyDescriptor::SetterCallback Setter> PropertyDescriptor PropertyDescriptor::Accessor(Name name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = details::TemplatedCallback; desc.setter = details::TemplatedVoidCallback; desc.attributes = attributes; desc.data = data; return desc; } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, const char* utf8name, Getter getter, napi_property_attributes attributes, void* data) { typedef details::CallbackData CbData; auto callbackData = new CbData({ getter, data }); napi_status status = AttachData(env, object, callbackData); if (status != napi_ok) { delete callbackData; NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); } return PropertyDescriptor({ utf8name, nullptr, nullptr, CbData::Wrapper, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, const std::string& utf8name, Getter getter, napi_property_attributes attributes, void* data) { return Accessor(env, object, utf8name.c_str(), getter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, Name name, Getter getter, napi_property_attributes attributes, void* data) { typedef details::CallbackData CbData; auto callbackData = new CbData({ getter, data }); napi_status status = AttachData(env, object, callbackData); if (status != napi_ok) { delete callbackData; NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); } return PropertyDescriptor({ nullptr, name, nullptr, CbData::Wrapper, nullptr, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, const char* utf8name, Getter getter, Setter setter, napi_property_attributes attributes, void* data) { typedef details::AccessorCallbackData CbData; auto callbackData = new CbData({ getter, setter, data }); napi_status status = AttachData(env, object, callbackData); if (status != napi_ok) { delete callbackData; NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); } return PropertyDescriptor({ utf8name, nullptr, nullptr, CbData::GetterWrapper, CbData::SetterWrapper, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, const std::string& utf8name, Getter getter, Setter setter, napi_property_attributes attributes, void* data) { return Accessor(env, object, utf8name.c_str(), getter, setter, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, Napi::Object object, Name name, Getter getter, Setter setter, napi_property_attributes attributes, void* data) { typedef details::AccessorCallbackData CbData; auto callbackData = new CbData({ getter, setter, data }); napi_status status = AttachData(env, object, callbackData); if (status != napi_ok) { delete callbackData; NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); } return PropertyDescriptor({ nullptr, name, nullptr, CbData::GetterWrapper, CbData::SetterWrapper, nullptr, attributes, callbackData }); } template inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, Napi::Object /*object*/, const char* utf8name, Callable cb, napi_property_attributes attributes, void* data) { return PropertyDescriptor({ utf8name, nullptr, nullptr, nullptr, nullptr, Napi::Function::New(env, cb, utf8name, data), attributes, nullptr }); } template inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, Napi::Object object, const std::string& utf8name, Callable cb, napi_property_attributes attributes, void* data) { return Function(env, object, utf8name.c_str(), cb, attributes, data); } template inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, Napi::Object /*object*/, Name name, Callable cb, napi_property_attributes attributes, void* data) { return PropertyDescriptor({ nullptr, name, nullptr, nullptr, nullptr, Napi::Function::New(env, cb, nullptr, data), attributes, nullptr }); } inline PropertyDescriptor PropertyDescriptor::Value(const char* utf8name, napi_value value, napi_property_attributes attributes) { return PropertyDescriptor({ utf8name, nullptr, nullptr, nullptr, nullptr, value, attributes, nullptr }); } inline PropertyDescriptor PropertyDescriptor::Value(const std::string& utf8name, napi_value value, napi_property_attributes attributes) { return Value(utf8name.c_str(), value, attributes); } inline PropertyDescriptor PropertyDescriptor::Value(napi_value name, napi_value value, napi_property_attributes attributes) { return PropertyDescriptor({ nullptr, name, nullptr, nullptr, nullptr, value, attributes, nullptr }); } inline PropertyDescriptor PropertyDescriptor::Value(Name name, Napi::Value value, napi_property_attributes attributes) { napi_value nameValue = name; napi_value valueValue = value; return PropertyDescriptor::Value(nameValue, valueValue, attributes); } inline PropertyDescriptor::PropertyDescriptor(napi_property_descriptor desc) : _desc(desc) { } inline PropertyDescriptor::operator napi_property_descriptor&() { return _desc; } inline PropertyDescriptor::operator const napi_property_descriptor&() const { return _desc; } //////////////////////////////////////////////////////////////////////////////// // InstanceWrap class //////////////////////////////////////////////////////////////////////////////// template inline void InstanceWrap::AttachPropData(napi_env env, napi_value value, const napi_property_descriptor* prop) { napi_status status; if (prop->method != nullptr && !(prop->attributes & napi_static)) { if (prop->method == T::InstanceVoidMethodCallbackWrapper) { status = Napi::details::AttachData(env, value, static_cast(prop->data)); NAPI_THROW_IF_FAILED_VOID(env, status); } else if (prop->method == T::InstanceMethodCallbackWrapper) { status = Napi::details::AttachData(env, value, static_cast(prop->data)); NAPI_THROW_IF_FAILED_VOID(env, status); } else if (prop->getter == T::InstanceGetterCallbackWrapper || prop->setter == T::InstanceSetterCallbackWrapper) { status = Napi::details::AttachData(env, value, static_cast(prop->data)); NAPI_THROW_IF_FAILED_VOID(env, status); } } } template inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, InstanceVoidMethodCallback method, napi_property_attributes attributes, void* data) { InstanceVoidMethodCallbackData* callbackData = new InstanceVoidMethodCallbackData({ method, data}); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = T::InstanceVoidMethodCallbackWrapper; desc.data = callbackData; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, InstanceMethodCallback method, napi_property_attributes attributes, void* data) { InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = T::InstanceMethodCallbackWrapper; desc.data = callbackData; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, InstanceVoidMethodCallback method, napi_property_attributes attributes, void* data) { InstanceVoidMethodCallbackData* callbackData = new InstanceVoidMethodCallbackData({ method, data}); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = T::InstanceVoidMethodCallbackWrapper; desc.data = callbackData; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, InstanceMethodCallback method, napi_property_attributes attributes, void* data) { InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = T::InstanceMethodCallbackWrapper; desc.data = callbackData; desc.attributes = attributes; return desc; } template template ::InstanceVoidMethodCallback method> inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = details::TemplatedInstanceVoidCallback; desc.data = data; desc.attributes = attributes; return desc; } template template ::InstanceMethodCallback method> inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = details::TemplatedInstanceCallback; desc.data = data; desc.attributes = attributes; return desc; } template template ::InstanceVoidMethodCallback method> inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = details::TemplatedInstanceVoidCallback; desc.data = data; desc.attributes = attributes; return desc; } template template ::InstanceMethodCallback method> inline ClassPropertyDescriptor InstanceWrap::InstanceMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = details::TemplatedInstanceCallback; desc.data = data; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( const char* utf8name, InstanceGetterCallback getter, InstanceSetterCallback setter, napi_property_attributes attributes, void* data) { InstanceAccessorCallbackData* callbackData = new InstanceAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; desc.data = callbackData; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( Symbol name, InstanceGetterCallback getter, InstanceSetterCallback setter, napi_property_attributes attributes, void* data) { InstanceAccessorCallbackData* callbackData = new InstanceAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; desc.data = callbackData; desc.attributes = attributes; return desc; } template template ::InstanceGetterCallback getter, typename InstanceWrap::InstanceSetterCallback setter> inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = details::TemplatedInstanceCallback; desc.setter = This::WrapSetter(This::SetterTag()); desc.data = data; desc.attributes = attributes; return desc; } template template ::InstanceGetterCallback getter, typename InstanceWrap::InstanceSetterCallback setter> inline ClassPropertyDescriptor InstanceWrap::InstanceAccessor( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = details::TemplatedInstanceCallback; desc.setter = This::WrapSetter(This::SetterTag()); desc.data = data; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceValue( const char* utf8name, Napi::Value value, napi_property_attributes attributes) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.value = value; desc.attributes = attributes; return desc; } template inline ClassPropertyDescriptor InstanceWrap::InstanceValue( Symbol name, Napi::Value value, napi_property_attributes attributes) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.value = value; desc.attributes = attributes; return desc; } template inline napi_value InstanceWrap::InstanceVoidMethodCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); InstanceVoidMethodCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); T* instance = T::Unwrap(callbackInfo.This().As()); auto cb = callbackData->callback; (instance->*cb)(callbackInfo); return nullptr; }); } template inline napi_value InstanceWrap::InstanceMethodCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); InstanceMethodCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); T* instance = T::Unwrap(callbackInfo.This().As()); auto cb = callbackData->callback; return (instance->*cb)(callbackInfo); }); } template inline napi_value InstanceWrap::InstanceGetterCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); InstanceAccessorCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); T* instance = T::Unwrap(callbackInfo.This().As()); auto cb = callbackData->getterCallback; return (instance->*cb)(callbackInfo); }); } template inline napi_value InstanceWrap::InstanceSetterCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); InstanceAccessorCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); T* instance = T::Unwrap(callbackInfo.This().As()); auto cb = callbackData->setterCallback; (instance->*cb)(callbackInfo, callbackInfo[0]); return nullptr; }); } template template ::InstanceSetterCallback method> inline napi_value InstanceWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { return details::WrapCallback([&] { const CallbackInfo cbInfo(env, info); T* instance = T::Unwrap(cbInfo.This().As()); (instance->*method)(cbInfo, cbInfo[0]); return nullptr; }); } //////////////////////////////////////////////////////////////////////////////// // ObjectWrap class //////////////////////////////////////////////////////////////////////////////// template inline ObjectWrap::ObjectWrap(const Napi::CallbackInfo& callbackInfo) { napi_env env = callbackInfo.Env(); napi_value wrapper = callbackInfo.This(); napi_status status; napi_ref ref; T* instance = static_cast(this); status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref); NAPI_THROW_IF_FAILED_VOID(env, status); Reference* instanceRef = instance; *instanceRef = Reference(env, ref); } template inline ObjectWrap::~ObjectWrap() { // If the JS object still exists at this point, remove the finalizer added // through `napi_wrap()`. if (!IsEmpty()) { Object object = Value(); // It is not valid to call `napi_remove_wrap()` with an empty `object`. // This happens e.g. during garbage collection. if (!object.IsEmpty() && _construction_failed) { napi_remove_wrap(Env(), object, nullptr); } } } template inline T* ObjectWrap::Unwrap(Object wrapper) { T* unwrapped; napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast(&unwrapped)); NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr); return unwrapped; } template inline Function ObjectWrap::DefineClass(Napi::Env env, const char* utf8name, const size_t props_count, const napi_property_descriptor* descriptors, void* data) { napi_status status; std::vector props(props_count); // We copy the descriptors to a local array because before defining the class // we must replace static method property descriptors with value property // descriptors such that the value is a function-valued `napi_value` created // with `CreateFunction()`. // // This replacement could be made for instance methods as well, but V8 aborts // if we do that, because it expects methods defined on the prototype template // to have `FunctionTemplate`s. for (size_t index = 0; index < props_count; index++) { props[index] = descriptors[index]; napi_property_descriptor* prop = &props[index]; if (prop->method == T::StaticMethodCallbackWrapper) { status = CreateFunction(env, utf8name, prop->method, static_cast(prop->data), &(prop->value)); NAPI_THROW_IF_FAILED(env, status, Function()); prop->method = nullptr; prop->data = nullptr; } else if (prop->method == T::StaticVoidMethodCallbackWrapper) { status = CreateFunction(env, utf8name, prop->method, static_cast(prop->data), &(prop->value)); NAPI_THROW_IF_FAILED(env, status, Function()); prop->method = nullptr; prop->data = nullptr; } } napi_value value; status = napi_define_class(env, utf8name, NAPI_AUTO_LENGTH, T::ConstructorCallbackWrapper, data, props_count, props.data(), &value); NAPI_THROW_IF_FAILED(env, status, Function()); // After defining the class we iterate once more over the property descriptors // and attach the data associated with accessors and instance methods to the // newly created JavaScript class. for (size_t idx = 0; idx < props_count; idx++) { const napi_property_descriptor* prop = &props[idx]; if (prop->getter == T::StaticGetterCallbackWrapper || prop->setter == T::StaticSetterCallbackWrapper) { status = Napi::details::AttachData(env, value, static_cast(prop->data)); NAPI_THROW_IF_FAILED(env, status, Function()); } else { // InstanceWrap::AttachPropData is responsible for attaching the data // of instance methods and accessors. T::AttachPropData(env, value, prop); } } return Function(env, value); } template inline Function ObjectWrap::DefineClass( Napi::Env env, const char* utf8name, const std::initializer_list>& properties, void* data) { return DefineClass(env, utf8name, properties.size(), reinterpret_cast(properties.begin()), data); } template inline Function ObjectWrap::DefineClass( Napi::Env env, const char* utf8name, const std::vector>& properties, void* data) { return DefineClass(env, utf8name, properties.size(), reinterpret_cast(properties.data()), data); } template inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, StaticVoidMethodCallback method, napi_property_attributes attributes, void* data) { StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = T::StaticVoidMethodCallbackWrapper; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, StaticMethodCallback method, napi_property_attributes attributes, void* data) { StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = T::StaticMethodCallbackWrapper; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, StaticVoidMethodCallback method, napi_property_attributes attributes, void* data) { StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = T::StaticVoidMethodCallbackWrapper; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, StaticMethodCallback method, napi_property_attributes attributes, void* data) { StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = T::StaticMethodCallbackWrapper; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticVoidMethodCallback method> inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = details::TemplatedVoidCallback; desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticVoidMethodCallback method> inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = details::TemplatedVoidCallback; desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticMethodCallback method> inline ClassPropertyDescriptor ObjectWrap::StaticMethod( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.method = details::TemplatedCallback; desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticMethodCallback method> inline ClassPropertyDescriptor ObjectWrap::StaticMethod( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.method = details::TemplatedCallback; desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( const char* utf8name, StaticGetterCallback getter, StaticSetterCallback setter, napi_property_attributes attributes, void* data) { StaticAccessorCallbackData* callbackData = new StaticAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( Symbol name, StaticGetterCallback getter, StaticSetterCallback setter, napi_property_attributes attributes, void* data) { StaticAccessorCallbackData* callbackData = new StaticAccessorCallbackData({ getter, setter, data }); napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; desc.data = callbackData; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticGetterCallback getter, typename ObjectWrap::StaticSetterCallback setter> inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( const char* utf8name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.getter = details::TemplatedCallback; desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template template ::StaticGetterCallback getter, typename ObjectWrap::StaticSetterCallback setter> inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( Symbol name, napi_property_attributes attributes, void* data) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.getter = details::TemplatedCallback; desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); desc.data = data; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticValue(const char* utf8name, Napi::Value value, napi_property_attributes attributes) { napi_property_descriptor desc = napi_property_descriptor(); desc.utf8name = utf8name; desc.value = value; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline ClassPropertyDescriptor ObjectWrap::StaticValue(Symbol name, Napi::Value value, napi_property_attributes attributes) { napi_property_descriptor desc = napi_property_descriptor(); desc.name = name; desc.value = value; desc.attributes = static_cast(attributes | napi_static); return desc; } template inline void ObjectWrap::Finalize(Napi::Env /*env*/) {} template inline napi_value ObjectWrap::ConstructorCallbackWrapper( napi_env env, napi_callback_info info) { napi_value new_target; napi_status status = napi_get_new_target(env, info, &new_target); if (status != napi_ok) return nullptr; bool isConstructCall = (new_target != nullptr); if (!isConstructCall) { napi_throw_type_error(env, nullptr, "Class constructors cannot be invoked without 'new'"); return nullptr; } napi_value wrapper = details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); T* instance = new T(callbackInfo); #ifdef NAPI_CPP_EXCEPTIONS instance->_construction_failed = false; #else if (callbackInfo.Env().IsExceptionPending()) { // We need to clear the exception so that removing the wrap might work. Error e = callbackInfo.Env().GetAndClearPendingException(); delete instance; e.ThrowAsJavaScriptException(); } else { instance->_construction_failed = false; } # endif // NAPI_CPP_EXCEPTIONS return callbackInfo.This(); }); return wrapper; } template inline napi_value ObjectWrap::StaticVoidMethodCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); StaticVoidMethodCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); callbackData->callback(callbackInfo); return nullptr; }); } template inline napi_value ObjectWrap::StaticMethodCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); StaticMethodCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); return callbackData->callback(callbackInfo); }); } template inline napi_value ObjectWrap::StaticGetterCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); StaticAccessorCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); return callbackData->getterCallback(callbackInfo); }); } template inline napi_value ObjectWrap::StaticSetterCallbackWrapper( napi_env env, napi_callback_info info) { return details::WrapCallback([&] { CallbackInfo callbackInfo(env, info); StaticAccessorCallbackData* callbackData = reinterpret_cast(callbackInfo.Data()); callbackInfo.SetData(callbackData->data); callbackData->setterCallback(callbackInfo, callbackInfo[0]); return nullptr; }); } template inline void ObjectWrap::FinalizeCallback(napi_env env, void* data, void* /*hint*/) { HandleScope scope(env); T* instance = static_cast(data); instance->Finalize(Napi::Env(env)); delete instance; } template template ::StaticSetterCallback method> inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { return details::WrapCallback([&] { const CallbackInfo cbInfo(env, info); method(cbInfo, cbInfo[0]); return nullptr; }); } //////////////////////////////////////////////////////////////////////////////// // HandleScope class //////////////////////////////////////////////////////////////////////////////// inline HandleScope::HandleScope(napi_env env, napi_handle_scope scope) : _env(env), _scope(scope) { } inline HandleScope::HandleScope(Napi::Env env) : _env(env) { napi_status status = napi_open_handle_scope(_env, &_scope); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline HandleScope::~HandleScope() { napi_status status = napi_close_handle_scope(_env, _scope); NAPI_FATAL_IF_FAILED(status, "HandleScope::~HandleScope", "napi_close_handle_scope"); } inline HandleScope::operator napi_handle_scope() const { return _scope; } inline Napi::Env HandleScope::Env() const { return Napi::Env(_env); } //////////////////////////////////////////////////////////////////////////////// // EscapableHandleScope class //////////////////////////////////////////////////////////////////////////////// inline EscapableHandleScope::EscapableHandleScope( napi_env env, napi_escapable_handle_scope scope) : _env(env), _scope(scope) { } inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) { napi_status status = napi_open_escapable_handle_scope(_env, &_scope); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline EscapableHandleScope::~EscapableHandleScope() { napi_status status = napi_close_escapable_handle_scope(_env, _scope); NAPI_FATAL_IF_FAILED(status, "EscapableHandleScope::~EscapableHandleScope", "napi_close_escapable_handle_scope"); } inline EscapableHandleScope::operator napi_escapable_handle_scope() const { return _scope; } inline Napi::Env EscapableHandleScope::Env() const { return Napi::Env(_env); } inline Value EscapableHandleScope::Escape(napi_value escapee) { napi_value result; napi_status status = napi_escape_handle(_env, _scope, escapee, &result); NAPI_THROW_IF_FAILED(_env, status, Value()); return Value(_env, result); } #if (NAPI_VERSION > 2) //////////////////////////////////////////////////////////////////////////////// // CallbackScope class //////////////////////////////////////////////////////////////////////////////// inline CallbackScope::CallbackScope( napi_env env, napi_callback_scope scope) : _env(env), _scope(scope) { } inline CallbackScope::CallbackScope(napi_env env, napi_async_context context) : _env(env) { napi_status status = napi_open_callback_scope( _env, Object::New(env), context, &_scope); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline CallbackScope::~CallbackScope() { napi_status status = napi_close_callback_scope(_env, _scope); NAPI_FATAL_IF_FAILED(status, "CallbackScope::~CallbackScope", "napi_close_callback_scope"); } inline CallbackScope::operator napi_callback_scope() const { return _scope; } inline Napi::Env CallbackScope::Env() const { return Napi::Env(_env); } #endif //////////////////////////////////////////////////////////////////////////////// // AsyncContext class //////////////////////////////////////////////////////////////////////////////// inline AsyncContext::AsyncContext(napi_env env, const char* resource_name) : AsyncContext(env, resource_name, Object::New(env)) { } inline AsyncContext::AsyncContext(napi_env env, const char* resource_name, const Object& resource) : _env(env), _context(nullptr) { napi_value resource_id; napi_status status = napi_create_string_utf8( _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); NAPI_THROW_IF_FAILED_VOID(_env, status); status = napi_async_init(_env, resource, resource_id, &_context); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline AsyncContext::~AsyncContext() { if (_context != nullptr) { napi_async_destroy(_env, _context); _context = nullptr; } } inline AsyncContext::AsyncContext(AsyncContext&& other) { _env = other._env; other._env = nullptr; _context = other._context; other._context = nullptr; } inline AsyncContext& AsyncContext::operator =(AsyncContext&& other) { _env = other._env; other._env = nullptr; _context = other._context; other._context = nullptr; return *this; } inline AsyncContext::operator napi_async_context() const { return _context; } inline Napi::Env AsyncContext::Env() const { return Napi::Env(_env); } //////////////////////////////////////////////////////////////////////////////// // AsyncWorker class //////////////////////////////////////////////////////////////////////////////// inline AsyncWorker::AsyncWorker(const Function& callback) : AsyncWorker(callback, "generic") { } inline AsyncWorker::AsyncWorker(const Function& callback, const char* resource_name) : AsyncWorker(callback, resource_name, Object::New(callback.Env())) { } inline AsyncWorker::AsyncWorker(const Function& callback, const char* resource_name, const Object& resource) : AsyncWorker(Object::New(callback.Env()), callback, resource_name, resource) { } inline AsyncWorker::AsyncWorker(const Object& receiver, const Function& callback) : AsyncWorker(receiver, callback, "generic") { } inline AsyncWorker::AsyncWorker(const Object& receiver, const Function& callback, const char* resource_name) : AsyncWorker(receiver, callback, resource_name, Object::New(callback.Env())) { } inline AsyncWorker::AsyncWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource) : _env(callback.Env()), _receiver(Napi::Persistent(receiver)), _callback(Napi::Persistent(callback)), _suppress_destruct(false) { napi_value resource_id; napi_status status = napi_create_string_latin1( _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); NAPI_THROW_IF_FAILED_VOID(_env, status); status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute, OnAsyncWorkComplete, this, &_work); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline AsyncWorker::AsyncWorker(Napi::Env env) : AsyncWorker(env, "generic") { } inline AsyncWorker::AsyncWorker(Napi::Env env, const char* resource_name) : AsyncWorker(env, resource_name, Object::New(env)) { } inline AsyncWorker::AsyncWorker(Napi::Env env, const char* resource_name, const Object& resource) : _env(env), _receiver(), _callback(), _suppress_destruct(false) { napi_value resource_id; napi_status status = napi_create_string_latin1( _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); NAPI_THROW_IF_FAILED_VOID(_env, status); status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute, OnAsyncWorkComplete, this, &_work); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline AsyncWorker::~AsyncWorker() { if (_work != nullptr) { napi_delete_async_work(_env, _work); _work = nullptr; } } inline void AsyncWorker::Destroy() { delete this; } inline AsyncWorker::AsyncWorker(AsyncWorker&& other) { _env = other._env; other._env = nullptr; _work = other._work; other._work = nullptr; _receiver = std::move(other._receiver); _callback = std::move(other._callback); _error = std::move(other._error); _suppress_destruct = other._suppress_destruct; } inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) { _env = other._env; other._env = nullptr; _work = other._work; other._work = nullptr; _receiver = std::move(other._receiver); _callback = std::move(other._callback); _error = std::move(other._error); _suppress_destruct = other._suppress_destruct; return *this; } inline AsyncWorker::operator napi_async_work() const { return _work; } inline Napi::Env AsyncWorker::Env() const { return Napi::Env(_env); } inline void AsyncWorker::Queue() { napi_status status = napi_queue_async_work(_env, _work); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline void AsyncWorker::Cancel() { napi_status status = napi_cancel_async_work(_env, _work); NAPI_THROW_IF_FAILED_VOID(_env, status); } inline ObjectReference& AsyncWorker::Receiver() { return _receiver; } inline FunctionReference& AsyncWorker::Callback() { return _callback; } inline void AsyncWorker::SuppressDestruct() { _suppress_destruct = true; } inline void AsyncWorker::OnOK() { if (!_callback.IsEmpty()) { _callback.Call(_receiver.Value(), GetResult(_callback.Env())); } } inline void AsyncWorker::OnError(const Error& e) { if (!_callback.IsEmpty()) { _callback.Call(_receiver.Value(), std::initializer_list{ e.Value() }); } } inline void AsyncWorker::SetError(const std::string& error) { _error = error; } inline std::vector AsyncWorker::GetResult(Napi::Env /*env*/) { return {}; } // The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT // use it within this method, as it does not run on the JavaScript thread and // must not run any method that would cause JavaScript to run. In practice, // this means that almost any use of napi_env will be incorrect. inline void AsyncWorker::OnAsyncWorkExecute(napi_env env, void* asyncworker) { AsyncWorker* self = static_cast(asyncworker); self->OnExecute(env); } // The OnExecute method receives an napi_env argument. However, do NOT // use it within this method, as it does not run on the JavaScript thread and // must not run any method that would cause JavaScript to run. In practice, // this means that almost any use of napi_env will be incorrect. inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) { #ifdef NAPI_CPP_EXCEPTIONS try { Execute(); } catch (const std::exception& e) { SetError(e.what()); } #else // NAPI_CPP_EXCEPTIONS Execute(); #endif // NAPI_CPP_EXCEPTIONS } inline void AsyncWorker::OnAsyncWorkComplete(napi_env env, napi_status status, void* asyncworker) { AsyncWorker* self = static_cast(asyncworker); self->OnWorkComplete(env, status); } inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) { if (status != napi_cancelled) { HandleScope scope(_env); details::WrapCallback([&] { if (_error.size() == 0) { OnOK(); } else { OnError(Error::New(_env, _error)); } return nullptr; }); } if (!_suppress_destruct) { Destroy(); } } #if (NAPI_VERSION > 3 && !defined(__wasm32__)) //////////////////////////////////////////////////////////////////////////////// // TypedThreadSafeFunction class //////////////////////////////////////////////////////////////////////////////// // Starting with NAPI 5, the JavaScript function `func` parameter of // `napi_create_threadsafe_function` is optional. #if NAPI_VERSION > 4 // static, with Callback [missing] Resource [missing] Finalizer [missing] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { TypedThreadSafeFunction tsfn; napi_status status = napi_create_threadsafe_function(env, nullptr, nullptr, String::From(env, resourceName), maxQueueSize, initialThreadCount, nullptr, nullptr, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with Callback [missing] Resource [passed] Finalizer [missing] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { TypedThreadSafeFunction tsfn; napi_status status = napi_create_threadsafe_function(env, nullptr, resource, String::From(env, resourceName), maxQueueSize, initialThreadCount, nullptr, nullptr, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with Callback [missing] Resource [missing] Finalizer [passed] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { TypedThreadSafeFunction tsfn; auto* finalizeData = new details:: ThreadSafeFinalize( {data, finalizeCallback}); napi_status status = napi_create_threadsafe_function( env, nullptr, nullptr, String::From(env, resourceName), maxQueueSize, initialThreadCount, finalizeData, details::ThreadSafeFinalize:: FinalizeFinalizeWrapperWithDataAndContext, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with Callback [missing] Resource [passed] Finalizer [passed] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { TypedThreadSafeFunction tsfn; auto* finalizeData = new details:: ThreadSafeFinalize( {data, finalizeCallback}); napi_status status = napi_create_threadsafe_function( env, nullptr, resource, String::From(env, resourceName), maxQueueSize, initialThreadCount, finalizeData, details::ThreadSafeFinalize:: FinalizeFinalizeWrapperWithDataAndContext, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } #endif // static, with Callback [passed] Resource [missing] Finalizer [missing] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { TypedThreadSafeFunction tsfn; napi_status status = napi_create_threadsafe_function(env, callback, nullptr, String::From(env, resourceName), maxQueueSize, initialThreadCount, nullptr, nullptr, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with Callback [passed] Resource [passed] Finalizer [missing] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { TypedThreadSafeFunction tsfn; napi_status status = napi_create_threadsafe_function(env, callback, resource, String::From(env, resourceName), maxQueueSize, initialThreadCount, nullptr, nullptr, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with Callback [passed] Resource [missing] Finalizer [passed] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { TypedThreadSafeFunction tsfn; auto* finalizeData = new details:: ThreadSafeFinalize( {data, finalizeCallback}); napi_status status = napi_create_threadsafe_function( env, callback, nullptr, String::From(env, resourceName), maxQueueSize, initialThreadCount, finalizeData, details::ThreadSafeFinalize:: FinalizeFinalizeWrapperWithDataAndContext, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } // static, with: Callback [passed] Resource [passed] Finalizer [passed] template template inline TypedThreadSafeFunction TypedThreadSafeFunction::New( napi_env env, CallbackType callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { TypedThreadSafeFunction tsfn; auto* finalizeData = new details:: ThreadSafeFinalize( {data, finalizeCallback}); napi_status status = napi_create_threadsafe_function( env, details::DefaultCallbackWrapper< CallbackType, TypedThreadSafeFunction>(env, callback), resource, String::From(env, resourceName), maxQueueSize, initialThreadCount, finalizeData, details::ThreadSafeFinalize:: FinalizeFinalizeWrapperWithDataAndContext, context, CallJsInternal, &tsfn._tsfn); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED( env, status, TypedThreadSafeFunction()); } return tsfn; } template inline TypedThreadSafeFunction:: TypedThreadSafeFunction() : _tsfn() {} template inline TypedThreadSafeFunction:: TypedThreadSafeFunction(napi_threadsafe_function tsfn) : _tsfn(tsfn) {} template inline TypedThreadSafeFunction:: operator napi_threadsafe_function() const { return _tsfn; } template inline napi_status TypedThreadSafeFunction::BlockingCall( DataType* data) const { return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking); } template inline napi_status TypedThreadSafeFunction::NonBlockingCall( DataType* data) const { return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking); } template inline void TypedThreadSafeFunction::Ref( napi_env env) const { if (_tsfn != nullptr) { napi_status status = napi_ref_threadsafe_function(env, _tsfn); NAPI_THROW_IF_FAILED_VOID(env, status); } } template inline void TypedThreadSafeFunction::Unref( napi_env env) const { if (_tsfn != nullptr) { napi_status status = napi_unref_threadsafe_function(env, _tsfn); NAPI_THROW_IF_FAILED_VOID(env, status); } } template inline napi_status TypedThreadSafeFunction::Acquire() const { return napi_acquire_threadsafe_function(_tsfn); } template inline napi_status TypedThreadSafeFunction::Release() { return napi_release_threadsafe_function(_tsfn, napi_tsfn_release); } template inline napi_status TypedThreadSafeFunction::Abort() { return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort); } template inline ContextType* TypedThreadSafeFunction::GetContext() const { void* context; napi_status status = napi_get_threadsafe_function_context(_tsfn, &context); NAPI_FATAL_IF_FAILED(status, "TypedThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context"); return static_cast(context); } // static template void TypedThreadSafeFunction::CallJsInternal( napi_env env, napi_value jsCallback, void* context, void* data) { details::CallJsWrapper( env, jsCallback, context, data); } #if NAPI_VERSION == 4 // static template Napi::Function TypedThreadSafeFunction::EmptyFunctionFactory( Napi::Env env) { return Napi::Function::New(env, [](const CallbackInfo& cb) {}); } // static template Napi::Function TypedThreadSafeFunction::FunctionOrEmpty( Napi::Env env, Napi::Function& callback) { if (callback.IsEmpty()) { return EmptyFunctionFactory(env); } return callback; } #else // static template std::nullptr_t TypedThreadSafeFunction::EmptyFunctionFactory( Napi::Env /*env*/) { return nullptr; } // static template Napi::Function TypedThreadSafeFunction::FunctionOrEmpty( Napi::Env /*env*/, Napi::Function& callback) { return callback; } #endif //////////////////////////////////////////////////////////////////////////////// // ThreadSafeFunction class //////////////////////////////////////////////////////////////////////////////// // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount, context); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount, finalizeCallback); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback, FinalizerDataType* data) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount, finalizeCallback, data); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount, context, finalizeCallback); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { return New(env, callback, Object(), resourceName, maxQueueSize, initialThreadCount, context, finalizeCallback, data); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, static_cast(nullptr) /* context */); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, context, [](Env, ContextType*) {} /* empty finalizer */); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, static_cast(nullptr) /* context */, finalizeCallback, static_cast(nullptr) /* data */, details::ThreadSafeFinalize::Wrapper); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback, FinalizerDataType* data) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, static_cast(nullptr) /* context */, finalizeCallback, data, details::ThreadSafeFinalize< void, Finalizer, FinalizerDataType>::FinalizeWrapperWithData); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, context, finalizeCallback, static_cast(nullptr) /* data */, details::ThreadSafeFinalize< ContextType, Finalizer>::FinalizeWrapperWithContext); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data) { return New(env, callback, resource, resourceName, maxQueueSize, initialThreadCount, context, finalizeCallback, data, details::ThreadSafeFinalize::FinalizeFinalizeWrapperWithDataAndContext); } inline ThreadSafeFunction::ThreadSafeFunction() : _tsfn() { } inline ThreadSafeFunction::ThreadSafeFunction( napi_threadsafe_function tsfn) : _tsfn(tsfn) { } inline ThreadSafeFunction::operator napi_threadsafe_function() const { return _tsfn; } inline napi_status ThreadSafeFunction::BlockingCall() const { return CallInternal(nullptr, napi_tsfn_blocking); } template <> inline napi_status ThreadSafeFunction::BlockingCall( void* data) const { return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking); } template inline napi_status ThreadSafeFunction::BlockingCall( Callback callback) const { return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking); } template inline napi_status ThreadSafeFunction::BlockingCall( DataType* data, Callback callback) const { auto wrapper = [data, callback](Env env, Function jsCallback) { callback(env, jsCallback, data); }; return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking); } inline napi_status ThreadSafeFunction::NonBlockingCall() const { return CallInternal(nullptr, napi_tsfn_nonblocking); } template <> inline napi_status ThreadSafeFunction::NonBlockingCall( void* data) const { return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking); } template inline napi_status ThreadSafeFunction::NonBlockingCall( Callback callback) const { return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking); } template inline napi_status ThreadSafeFunction::NonBlockingCall( DataType* data, Callback callback) const { auto wrapper = [data, callback](Env env, Function jsCallback) { callback(env, jsCallback, data); }; return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking); } inline void ThreadSafeFunction::Ref(napi_env env) const { if (_tsfn != nullptr) { napi_status status = napi_ref_threadsafe_function(env, _tsfn); NAPI_THROW_IF_FAILED_VOID(env, status); } } inline void ThreadSafeFunction::Unref(napi_env env) const { if (_tsfn != nullptr) { napi_status status = napi_unref_threadsafe_function(env, _tsfn); NAPI_THROW_IF_FAILED_VOID(env, status); } } inline napi_status ThreadSafeFunction::Acquire() const { return napi_acquire_threadsafe_function(_tsfn); } inline napi_status ThreadSafeFunction::Release() { return napi_release_threadsafe_function(_tsfn, napi_tsfn_release); } inline napi_status ThreadSafeFunction::Abort() { return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort); } inline ThreadSafeFunction::ConvertibleContext ThreadSafeFunction::GetContext() const { void* context; napi_status status = napi_get_threadsafe_function_context(_tsfn, &context); NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context"); return ConvertibleContext({ context }); } // static template inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data, napi_finalize wrapper) { static_assert(details::can_make_string::value || std::is_convertible::value, "Resource name should be convertible to the string type"); ThreadSafeFunction tsfn; auto* finalizeData = new details::ThreadSafeFinalize({ data, finalizeCallback }); napi_status status = napi_create_threadsafe_function(env, callback, resource, Value::From(env, resourceName), maxQueueSize, initialThreadCount, finalizeData, wrapper, context, CallJS, &tsfn._tsfn); if (status != napi_ok) { delete finalizeData; NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction()); } return tsfn; } inline napi_status ThreadSafeFunction::CallInternal( CallbackWrapper* callbackWrapper, napi_threadsafe_function_call_mode mode) const { napi_status status = napi_call_threadsafe_function( _tsfn, callbackWrapper, mode); if (status != napi_ok && callbackWrapper != nullptr) { delete callbackWrapper; } return status; } // static inline void ThreadSafeFunction::CallJS(napi_env env, napi_value jsCallback, void* /* context */, void* data) { if (env == nullptr && jsCallback == nullptr) { return; } if (data != nullptr) { auto* callbackWrapper = static_cast(data); (*callbackWrapper)(env, Function(env, jsCallback)); delete callbackWrapper; } else if (jsCallback != nullptr) { Function(env, jsCallback).Call({}); } } //////////////////////////////////////////////////////////////////////////////// // Async Progress Worker Base class //////////////////////////////////////////////////////////////////////////////// template inline AsyncProgressWorkerBase::AsyncProgressWorkerBase(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource, size_t queue_size) : AsyncWorker(receiver, callback, resource_name, resource) { // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures. _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource, resource_name, queue_size, /** initialThreadCount */ 1, /** context */ this, OnThreadSafeFunctionFinalize, /** finalizeData */ this); } #if NAPI_VERSION > 4 template inline AsyncProgressWorkerBase::AsyncProgressWorkerBase(Napi::Env env, const char* resource_name, const Object& resource, size_t queue_size) : AsyncWorker(env, resource_name, resource) { // TODO: Once the changes to make the callback optional for threadsafe // functions are available on all versions we can remove the dummy Function here. Function callback; // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures. _tsfn = ThreadSafeFunction::New(env, callback, resource, resource_name, queue_size, /** initialThreadCount */ 1, /** context */ this, OnThreadSafeFunctionFinalize, /** finalizeData */ this); } #endif template inline AsyncProgressWorkerBase::~AsyncProgressWorkerBase() { // Abort pending tsfn call. // Don't send progress events after we've already completed. // It's ok to call ThreadSafeFunction::Abort and ThreadSafeFunction::Release duplicated. _tsfn.Abort(); } template inline void AsyncProgressWorkerBase::OnAsyncWorkProgress(Napi::Env /* env */, Napi::Function /* jsCallback */, void* data) { ThreadSafeData* tsd = static_cast(data); tsd->asyncprogressworker()->OnWorkProgress(tsd->data()); delete tsd; } template inline napi_status AsyncProgressWorkerBase::NonBlockingCall(DataType* data) { auto tsd = new AsyncProgressWorkerBase::ThreadSafeData(this, data); return _tsfn.NonBlockingCall(tsd, OnAsyncWorkProgress); } template inline void AsyncProgressWorkerBase::OnWorkComplete(Napi::Env /* env */, napi_status status) { _work_completed = true; _complete_status = status; _tsfn.Release(); } template inline void AsyncProgressWorkerBase::OnThreadSafeFunctionFinalize(Napi::Env env, void* /* data */, AsyncProgressWorkerBase* context) { if (context->_work_completed) { context->AsyncWorker::OnWorkComplete(env, context->_complete_status); } } //////////////////////////////////////////////////////////////////////////////// // Async Progress Worker class //////////////////////////////////////////////////////////////////////////////// template inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback) : AsyncProgressWorker(callback, "generic") { } template inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback, const char* resource_name) : AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) { } template inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback, const char* resource_name, const Object& resource) : AsyncProgressWorker(Object::New(callback.Env()), callback, resource_name, resource) { } template inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, const Function& callback) : AsyncProgressWorker(receiver, callback, "generic") { } template inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, const Function& callback, const char* resource_name) : AsyncProgressWorker(receiver, callback, resource_name, Object::New(callback.Env())) { } template inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource) : AsyncProgressWorkerBase(receiver, callback, resource_name, resource), _asyncdata(nullptr), _asyncsize(0) { } #if NAPI_VERSION > 4 template inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env) : AsyncProgressWorker(env, "generic") { } template inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env, const char* resource_name) : AsyncProgressWorker(env, resource_name, Object::New(env)) { } template inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env, const char* resource_name, const Object& resource) : AsyncProgressWorkerBase(env, resource_name, resource), _asyncdata(nullptr), _asyncsize(0) { } #endif template inline AsyncProgressWorker::~AsyncProgressWorker() { { std::lock_guard lock(this->_mutex); _asyncdata = nullptr; _asyncsize = 0; } } template inline void AsyncProgressWorker::Execute() { ExecutionProgress progress(this); Execute(progress); } template inline void AsyncProgressWorker::OnWorkProgress(void*) { T* data; size_t size; { std::lock_guard lock(this->_mutex); data = this->_asyncdata; size = this->_asyncsize; this->_asyncdata = nullptr; this->_asyncsize = 0; } /** * The callback of ThreadSafeFunction is not been invoked immediately on the * callback of uv_async_t (uv io poll), rather the callback of TSFN is * invoked on the right next uv idle callback. There are chances that during * the deferring the signal of uv_async_t is been sent again, i.e. potential * not coalesced two calls of the TSFN callback. */ if (data == nullptr) { return; } this->OnProgress(data, size); delete[] data; } template inline void AsyncProgressWorker::SendProgress_(const T* data, size_t count) { T* new_data = new T[count]; std::copy(data, data + count, new_data); T* old_data; { std::lock_guard lock(this->_mutex); old_data = _asyncdata; _asyncdata = new_data; _asyncsize = count; } this->NonBlockingCall(nullptr); delete[] old_data; } template inline void AsyncProgressWorker::Signal() const { this->NonBlockingCall(static_cast(nullptr)); } template inline void AsyncProgressWorker::ExecutionProgress::Signal() const { _worker->Signal(); } template inline void AsyncProgressWorker::ExecutionProgress::Send(const T* data, size_t count) const { _worker->SendProgress_(data, count); } //////////////////////////////////////////////////////////////////////////////// // Async Progress Queue Worker class //////////////////////////////////////////////////////////////////////////////// template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Function& callback) : AsyncProgressQueueWorker(callback, "generic") { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Function& callback, const char* resource_name) : AsyncProgressQueueWorker(callback, resource_name, Object::New(callback.Env())) { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Function& callback, const char* resource_name, const Object& resource) : AsyncProgressQueueWorker(Object::New(callback.Env()), callback, resource_name, resource) { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Object& receiver, const Function& callback) : AsyncProgressQueueWorker(receiver, callback, "generic") { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Object& receiver, const Function& callback, const char* resource_name) : AsyncProgressQueueWorker(receiver, callback, resource_name, Object::New(callback.Env())) { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource) : AsyncProgressWorkerBase>(receiver, callback, resource_name, resource, /** unlimited queue size */0) { } #if NAPI_VERSION > 4 template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(Napi::Env env) : AsyncProgressQueueWorker(env, "generic") { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(Napi::Env env, const char* resource_name) : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) { } template inline AsyncProgressQueueWorker::AsyncProgressQueueWorker(Napi::Env env, const char* resource_name, const Object& resource) : AsyncProgressWorkerBase>(env, resource_name, resource, /** unlimited queue size */0) { } #endif template inline void AsyncProgressQueueWorker::Execute() { ExecutionProgress progress(this); Execute(progress); } template inline void AsyncProgressQueueWorker::OnWorkProgress(std::pair* datapair) { if (datapair == nullptr) { return; } T *data = datapair->first; size_t size = datapair->second; this->OnProgress(data, size); delete datapair; delete[] data; } template inline void AsyncProgressQueueWorker::SendProgress_(const T* data, size_t count) { T* new_data = new T[count]; std::copy(data, data + count, new_data); auto pair = new std::pair(new_data, count); this->NonBlockingCall(pair); } template inline void AsyncProgressQueueWorker::Signal() const { this->NonBlockingCall(nullptr); } template inline void AsyncProgressQueueWorker::OnWorkComplete(Napi::Env env, napi_status status) { // Draining queued items in TSFN. AsyncProgressWorkerBase>::OnWorkComplete(env, status); } template inline void AsyncProgressQueueWorker::ExecutionProgress::Signal() const { _worker->Signal(); } template inline void AsyncProgressQueueWorker::ExecutionProgress::Send(const T* data, size_t count) const { _worker->SendProgress_(data, count); } #endif // NAPI_VERSION > 3 && !defined(__wasm32__) //////////////////////////////////////////////////////////////////////////////// // Memory Management class //////////////////////////////////////////////////////////////////////////////// inline int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes) { int64_t result; napi_status status = napi_adjust_external_memory(env, change_in_bytes, &result); NAPI_THROW_IF_FAILED(env, status, 0); return result; } //////////////////////////////////////////////////////////////////////////////// // Version Management class //////////////////////////////////////////////////////////////////////////////// inline uint32_t VersionManagement::GetNapiVersion(Env env) { uint32_t result; napi_status status = napi_get_version(env, &result); NAPI_THROW_IF_FAILED(env, status, 0); return result; } inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) { const napi_node_version* result; napi_status status = napi_get_node_version(env, &result); NAPI_THROW_IF_FAILED(env, status, 0); return result; } #if NAPI_VERSION > 5 //////////////////////////////////////////////////////////////////////////////// // Addon class //////////////////////////////////////////////////////////////////////////////// template inline Object Addon::Init(Env env, Object exports) { T* addon = new T(env, exports); env.SetInstanceData(addon); return addon->entry_point_; } template inline T* Addon::Unwrap(Object wrapper) { return wrapper.Env().GetInstanceData(); } template inline void Addon::DefineAddon(Object exports, const std::initializer_list& props) { DefineProperties(exports, props); entry_point_ = exports; } template inline Napi::Object Addon::DefineProperties(Object object, const std::initializer_list& props) { const napi_property_descriptor* properties = reinterpret_cast(props.begin()); size_t size = props.size(); napi_status status = napi_define_properties(object.Env(), object, size, properties); NAPI_THROW_IF_FAILED(object.Env(), status, object); for (size_t idx = 0; idx < size; idx++) T::AttachPropData(object.Env(), object, &properties[idx]); return object; } #endif // NAPI_VERSION > 5 } // namespace Napi #endif // SRC_NAPI_INL_H_ #ifndef SRC_NAPI_H_ #define SRC_NAPI_H_ #include #include #include #include #include #include #include // VS2015 RTM has bugs with constexpr, so require min of VS2015 Update 3 (known good version) #if !defined(_MSC_VER) || _MSC_FULL_VER >= 190024210 #define NAPI_HAS_CONSTEXPR 1 #endif // VS2013 does not support char16_t literal strings, so we'll work around it using wchar_t strings // and casting them. This is safe as long as the character sizes are the same. #if defined(_MSC_VER) && _MSC_VER <= 1800 static_assert(sizeof(char16_t) == sizeof(wchar_t), "Size mismatch between char16_t and wchar_t"); #define NAPI_WIDE_TEXT(x) reinterpret_cast(L ## x) #else #define NAPI_WIDE_TEXT(x) u ## x #endif // If C++ exceptions are not explicitly enabled or disabled, enable them // if exceptions were enabled in the compiler settings. #if !defined(NAPI_CPP_EXCEPTIONS) && !defined(NAPI_DISABLE_CPP_EXCEPTIONS) #if defined(_CPPUNWIND) || defined (__EXCEPTIONS) #define NAPI_CPP_EXCEPTIONS #else #error Exception support not detected. \ Define either NAPI_CPP_EXCEPTIONS or NAPI_DISABLE_CPP_EXCEPTIONS. #endif #endif #ifdef _NOEXCEPT #define NAPI_NOEXCEPT _NOEXCEPT #else #define NAPI_NOEXCEPT noexcept #endif #ifdef NAPI_CPP_EXCEPTIONS // When C++ exceptions are enabled, Errors are thrown directly. There is no need // to return anything after the throw statements. The variadic parameter is an // optional return value that is ignored. // We need _VOID versions of the macros to avoid warnings resulting from // leaving the NAPI_THROW_* `...` argument empty. #define NAPI_THROW(e, ...) throw e #define NAPI_THROW_VOID(e) throw e #define NAPI_THROW_IF_FAILED(env, status, ...) \ if ((status) != napi_ok) throw Napi::Error::New(env); #define NAPI_THROW_IF_FAILED_VOID(env, status) \ if ((status) != napi_ok) throw Napi::Error::New(env); #else // NAPI_CPP_EXCEPTIONS // When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions, // which are pending until the callback returns to JS. The variadic parameter // is an optional return value; usually it is an empty result. // We need _VOID versions of the macros to avoid warnings resulting from // leaving the NAPI_THROW_* `...` argument empty. #define NAPI_THROW(e, ...) \ do { \ (e).ThrowAsJavaScriptException(); \ return __VA_ARGS__; \ } while (0) #define NAPI_THROW_VOID(e) \ do { \ (e).ThrowAsJavaScriptException(); \ return; \ } while (0) #define NAPI_THROW_IF_FAILED(env, status, ...) \ if ((status) != napi_ok) { \ Napi::Error::New(env).ThrowAsJavaScriptException(); \ return __VA_ARGS__; \ } #define NAPI_THROW_IF_FAILED_VOID(env, status) \ if ((status) != napi_ok) { \ Napi::Error::New(env).ThrowAsJavaScriptException(); \ return; \ } #endif // NAPI_CPP_EXCEPTIONS # define NAPI_DISALLOW_ASSIGN(CLASS) void operator=(const CLASS&) = delete; # define NAPI_DISALLOW_COPY(CLASS) CLASS(const CLASS&) = delete; #define NAPI_DISALLOW_ASSIGN_COPY(CLASS) \ NAPI_DISALLOW_ASSIGN(CLASS) \ NAPI_DISALLOW_COPY(CLASS) #define NAPI_FATAL_IF_FAILED(status, location, message) \ do { \ if ((status) != napi_ok) { \ Napi::Error::Fatal((location), (message)); \ } \ } while (0) //////////////////////////////////////////////////////////////////////////////// /// N-API C++ Wrapper Classes /// /// These classes wrap the "N-API" ABI-stable C APIs for Node.js, providing a /// C++ object model and C++ exception-handling semantics with low overhead. /// The wrappers are all header-only so that they do not affect the ABI. //////////////////////////////////////////////////////////////////////////////// namespace Napi { // Forward declarations class Env; class Value; class Boolean; class Number; #if NAPI_VERSION > 5 class BigInt; #endif // NAPI_VERSION > 5 #if (NAPI_VERSION > 4) class Date; #endif class String; class Object; class Array; class ArrayBuffer; class Function; class Error; class PropertyDescriptor; class CallbackInfo; class TypedArray; template class TypedArrayOf; typedef TypedArrayOf Int8Array; ///< Typed-array of signed 8-bit integers typedef TypedArrayOf Uint8Array; ///< Typed-array of unsigned 8-bit integers typedef TypedArrayOf Int16Array; ///< Typed-array of signed 16-bit integers typedef TypedArrayOf Uint16Array; ///< Typed-array of unsigned 16-bit integers typedef TypedArrayOf Int32Array; ///< Typed-array of signed 32-bit integers typedef TypedArrayOf Uint32Array; ///< Typed-array of unsigned 32-bit integers typedef TypedArrayOf Float32Array; ///< Typed-array of 32-bit floating-point values typedef TypedArrayOf Float64Array; ///< Typed-array of 64-bit floating-point values #if NAPI_VERSION > 5 typedef TypedArrayOf BigInt64Array; ///< Typed array of signed 64-bit integers typedef TypedArrayOf BigUint64Array; ///< Typed array of unsigned 64-bit integers #endif // NAPI_VERSION > 5 /// Defines the signature of a N-API C++ module's registration callback (init) function. typedef Object (*ModuleRegisterCallback)(Env env, Object exports); class MemoryManagement; /// Environment for N-API values and operations. /// /// All N-API values and operations must be associated with an environment. An environment /// instance is always provided to callback functions; that environment must then be used for any /// creation of N-API values or other N-API operations within the callback. (Many methods infer /// the environment from the `this` instance that the method is called on.) /// /// In the future, multiple environments per process may be supported, although current /// implementations only support one environment per process. /// /// In the V8 JavaScript engine, a N-API environment approximately corresponds to an Isolate. class Env { #if NAPI_VERSION > 5 private: template static void DefaultFini(Env, T* data); template static void DefaultFiniWithHint(Env, DataType* data, HintType* hint); #endif // NAPI_VERSION > 5 public: Env(napi_env env); operator napi_env() const; Object Global() const; Value Undefined() const; Value Null() const; bool IsExceptionPending() const; Error GetAndClearPendingException(); Value RunScript(const char* utf8script); Value RunScript(const std::string& utf8script); Value RunScript(String script); #if NAPI_VERSION > 5 template T* GetInstanceData(); template using Finalizer = void (*)(Env, T*); template fini = Env::DefaultFini> void SetInstanceData(T* data); template using FinalizerWithHint = void (*)(Env, DataType*, HintType*); template fini = Env::DefaultFiniWithHint> void SetInstanceData(DataType* data, HintType* hint); #endif // NAPI_VERSION > 5 private: napi_env _env; }; /// A JavaScript value of unknown type. /// /// For type-specific operations, convert to one of the Value subclasses using a `To*` or `As()` /// method. The `To*` methods do type coercion; the `As()` method does not. /// /// Napi::Value value = ... /// if (!value.IsString()) throw Napi::TypeError::New(env, "Invalid arg..."); /// Napi::String str = value.As(); // Cast to a string value /// /// Napi::Value anotherValue = ... /// bool isTruthy = anotherValue.ToBoolean(); // Coerce to a boolean value class Value { public: Value(); ///< Creates a new _empty_ Value instance. Value(napi_env env, napi_value value); ///< Wraps a N-API value primitive. /// Creates a JS value from a C++ primitive. /// /// `value` may be any of: /// - bool /// - Any integer type /// - Any floating point type /// - const char* (encoded using UTF-8, null-terminated) /// - const char16_t* (encoded using UTF-16-LE, null-terminated) /// - std::string (encoded using UTF-8) /// - std::u16string /// - napi::Value /// - napi_value template static Value From(napi_env env, const T& value); /// Converts to a N-API value primitive. /// /// If the instance is _empty_, this returns `nullptr`. operator napi_value() const; /// Tests if this value strictly equals another value. bool operator ==(const Value& other) const; /// Tests if this value does not strictly equal another value. bool operator !=(const Value& other) const; /// Tests if this value strictly equals another value. bool StrictEquals(const Value& other) const; /// Gets the environment the value is associated with. Napi::Env Env() const; /// Checks if the value is empty (uninitialized). /// /// An empty value is invalid, and most attempts to perform an operation on an empty value /// will result in an exception. Note an empty value is distinct from JavaScript `null` or /// `undefined`, which are valid values. /// /// When C++ exceptions are disabled at compile time, a method with a `Value` return type may /// return an empty value to indicate a pending exception. So when not using C++ exceptions, /// callers should check whether the value is empty before attempting to use it. bool IsEmpty() const; napi_valuetype Type() const; ///< Gets the type of the value. bool IsUndefined() const; ///< Tests if a value is an undefined JavaScript value. bool IsNull() const; ///< Tests if a value is a null JavaScript value. bool IsBoolean() const; ///< Tests if a value is a JavaScript boolean. bool IsNumber() const; ///< Tests if a value is a JavaScript number. #if NAPI_VERSION > 5 bool IsBigInt() const; ///< Tests if a value is a JavaScript bigint. #endif // NAPI_VERSION > 5 #if (NAPI_VERSION > 4) bool IsDate() const; ///< Tests if a value is a JavaScript date. #endif bool IsString() const; ///< Tests if a value is a JavaScript string. bool IsSymbol() const; ///< Tests if a value is a JavaScript symbol. bool IsArray() const; ///< Tests if a value is a JavaScript array. bool IsArrayBuffer() const; ///< Tests if a value is a JavaScript array buffer. bool IsTypedArray() const; ///< Tests if a value is a JavaScript typed array. bool IsObject() const; ///< Tests if a value is a JavaScript object. bool IsFunction() const; ///< Tests if a value is a JavaScript function. bool IsPromise() const; ///< Tests if a value is a JavaScript promise. bool IsDataView() const; ///< Tests if a value is a JavaScript data view. bool IsBuffer() const; ///< Tests if a value is a Node buffer. bool IsExternal() const; ///< Tests if a value is a pointer to external data. /// Casts to another type of `Napi::Value`, when the actual type is known or assumed. /// /// This conversion does NOT coerce the type. Calling any methods inappropriate for the actual /// value type will throw `Napi::Error`. template T As() const; Boolean ToBoolean() const; ///< Coerces a value to a JavaScript boolean. Number ToNumber() const; ///< Coerces a value to a JavaScript number. String ToString() const; ///< Coerces a value to a JavaScript string. Object ToObject() const; ///< Coerces a value to a JavaScript object. protected: /// !cond INTERNAL napi_env _env; napi_value _value; /// !endcond }; /// A JavaScript boolean value. class Boolean : public Value { public: static Boolean New( napi_env env, ///< N-API environment bool value ///< Boolean value ); Boolean(); ///< Creates a new _empty_ Boolean instance. Boolean(napi_env env, napi_value value); ///< Wraps a N-API value primitive. operator bool() const; ///< Converts a Boolean value to a boolean primitive. bool Value() const; ///< Converts a Boolean value to a boolean primitive. }; /// A JavaScript number value. class Number : public Value { public: static Number New( napi_env env, ///< N-API environment double value ///< Number value ); Number(); ///< Creates a new _empty_ Number instance. Number(napi_env env, napi_value value); ///< Wraps a N-API value primitive. operator int32_t() const; ///< Converts a Number value to a 32-bit signed integer value. operator uint32_t() const; ///< Converts a Number value to a 32-bit unsigned integer value. operator int64_t() const; ///< Converts a Number value to a 64-bit signed integer value. operator float() const; ///< Converts a Number value to a 32-bit floating-point value. operator double() const; ///< Converts a Number value to a 64-bit floating-point value. int32_t Int32Value() const; ///< Converts a Number value to a 32-bit signed integer value. uint32_t Uint32Value() const; ///< Converts a Number value to a 32-bit unsigned integer value. int64_t Int64Value() const; ///< Converts a Number value to a 64-bit signed integer value. float FloatValue() const; ///< Converts a Number value to a 32-bit floating-point value. double DoubleValue() const; ///< Converts a Number value to a 64-bit floating-point value. }; #if NAPI_VERSION > 5 /// A JavaScript bigint value. class BigInt : public Value { public: static BigInt New( napi_env env, ///< N-API environment int64_t value ///< Number value ); static BigInt New( napi_env env, ///< N-API environment uint64_t value ///< Number value ); /// Creates a new BigInt object using a specified sign bit and a /// specified list of digits/words. /// The resulting number is calculated as: /// (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...) static BigInt New( napi_env env, ///< N-API environment int sign_bit, ///< Sign bit. 1 if negative. size_t word_count, ///< Number of words in array const uint64_t* words ///< Array of words ); BigInt(); ///< Creates a new _empty_ BigInt instance. BigInt(napi_env env, napi_value value); ///< Wraps a N-API value primitive. int64_t Int64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit signed integer value. uint64_t Uint64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit unsigned integer value. size_t WordCount() const; ///< The number of 64-bit words needed to store the result of ToWords(). /// Writes the contents of this BigInt to a specified memory location. /// `sign_bit` must be provided and will be set to 1 if this BigInt is negative. /// `*word_count` has to be initialized to the length of the `words` array. /// Upon return, it will be set to the actual number of words that would /// be needed to store this BigInt (i.e. the return value of `WordCount()`). void ToWords(int* sign_bit, size_t* word_count, uint64_t* words); }; #endif // NAPI_VERSION > 5 #if (NAPI_VERSION > 4) /// A JavaScript date value. class Date : public Value { public: /// Creates a new Date value from a double primitive. static Date New( napi_env env, ///< N-API environment double value ///< Number value ); Date(); ///< Creates a new _empty_ Date instance. Date(napi_env env, napi_value value); ///< Wraps a N-API value primitive. operator double() const; ///< Converts a Date value to double primitive double ValueOf() const; ///< Converts a Date value to a double primitive. }; #endif /// A JavaScript string or symbol value (that can be used as a property name). class Name : public Value { public: Name(); ///< Creates a new _empty_ Name instance. Name(napi_env env, napi_value value); ///< Wraps a N-API value primitive. }; /// A JavaScript string value. class String : public Name { public: /// Creates a new String value from a UTF-8 encoded C++ string. static String New( napi_env env, ///< N-API environment const std::string& value ///< UTF-8 encoded C++ string ); /// Creates a new String value from a UTF-16 encoded C++ string. static String New( napi_env env, ///< N-API environment const std::u16string& value ///< UTF-16 encoded C++ string ); /// Creates a new String value from a UTF-8 encoded C string. static String New( napi_env env, ///< N-API environment const char* value ///< UTF-8 encoded null-terminated C string ); /// Creates a new String value from a UTF-16 encoded C string. static String New( napi_env env, ///< N-API environment const char16_t* value ///< UTF-16 encoded null-terminated C string ); /// Creates a new String value from a UTF-8 encoded C string with specified length. static String New( napi_env env, ///< N-API environment const char* value, ///< UTF-8 encoded C string (not necessarily null-terminated) size_t length ///< length of the string in bytes ); /// Creates a new String value from a UTF-16 encoded C string with specified length. static String New( napi_env env, ///< N-API environment const char16_t* value, ///< UTF-16 encoded C string (not necessarily null-terminated) size_t length ///< Length of the string in 2-byte code units ); /// Creates a new String based on the original object's type. /// /// `value` may be any of: /// - const char* (encoded using UTF-8, null-terminated) /// - const char16_t* (encoded using UTF-16-LE, null-terminated) /// - std::string (encoded using UTF-8) /// - std::u16string template static String From(napi_env env, const T& value); String(); ///< Creates a new _empty_ String instance. String(napi_env env, napi_value value); ///< Wraps a N-API value primitive. operator std::string() const; ///< Converts a String value to a UTF-8 encoded C++ string. operator std::u16string() const; ///< Converts a String value to a UTF-16 encoded C++ string. std::string Utf8Value() const; ///< Converts a String value to a UTF-8 encoded C++ string. std::u16string Utf16Value() const; ///< Converts a String value to a UTF-16 encoded C++ string. }; /// A JavaScript symbol value. class Symbol : public Name { public: /// Creates a new Symbol value with an optional description. static Symbol New( napi_env env, ///< N-API environment const char* description = nullptr ///< Optional UTF-8 encoded null-terminated C string /// describing the symbol ); /// Creates a new Symbol value with a description. static Symbol New( napi_env env, ///< N-API environment const std::string& description ///< UTF-8 encoded C++ string describing the symbol ); /// Creates a new Symbol value with a description. static Symbol New( napi_env env, ///< N-API environment String description ///< String value describing the symbol ); /// Creates a new Symbol value with a description. static Symbol New( napi_env env, ///< N-API environment napi_value description ///< String value describing the symbol ); /// Get a public Symbol (e.g. Symbol.iterator). static Symbol WellKnown(napi_env, const std::string& name); Symbol(); ///< Creates a new _empty_ Symbol instance. Symbol(napi_env env, napi_value value); ///< Wraps a N-API value primitive. }; /// A JavaScript object value. class Object : public Value { public: /// Enables property and element assignments using indexing syntax. /// /// Example: /// /// Napi::Value propertyValue = object1['A']; /// object2['A'] = propertyValue; /// Napi::Value elementValue = array[0]; /// array[1] = elementValue; template class PropertyLValue { public: /// Converts an L-value to a value. operator Value() const; /// Assigns a value to the property. The type of value can be /// anything supported by `Object::Set`. template PropertyLValue& operator =(ValueType value); private: PropertyLValue() = delete; PropertyLValue(Object object, Key key); napi_env _env; napi_value _object; Key _key; friend class Napi::Object; }; /// Creates a new Object value. static Object New( napi_env env ///< N-API environment ); Object(); ///< Creates a new _empty_ Object instance. Object(napi_env env, napi_value value); ///< Wraps a N-API value primitive. /// Gets or sets a named property. PropertyLValue operator []( const char* utf8name ///< UTF-8 encoded null-terminated property name ); /// Gets or sets a named property. PropertyLValue operator []( const std::string& utf8name ///< UTF-8 encoded property name ); /// Gets or sets an indexed property or array element. PropertyLValue operator []( uint32_t index /// Property / element index ); /// Gets a named property. Value operator []( const char* utf8name ///< UTF-8 encoded null-terminated property name ) const; /// Gets a named property. Value operator []( const std::string& utf8name ///< UTF-8 encoded property name ) const; /// Gets an indexed property or array element. Value operator []( uint32_t index ///< Property / element index ) const; /// Checks whether a property is present. bool Has( napi_value key ///< Property key primitive ) const; /// Checks whether a property is present. bool Has( Value key ///< Property key ) const; /// Checks whether a named property is present. bool Has( const char* utf8name ///< UTF-8 encoded null-terminated property name ) const; /// Checks whether a named property is present. bool Has( const std::string& utf8name ///< UTF-8 encoded property name ) const; /// Checks whether a own property is present. bool HasOwnProperty( napi_value key ///< Property key primitive ) const; /// Checks whether a own property is present. bool HasOwnProperty( Value key ///< Property key ) const; /// Checks whether a own property is present. bool HasOwnProperty( const char* utf8name ///< UTF-8 encoded null-terminated property name ) const; /// Checks whether a own property is present. bool HasOwnProperty( const std::string& utf8name ///< UTF-8 encoded property name ) const; /// Gets a property. Value Get( napi_value key ///< Property key primitive ) const; /// Gets a property. Value Get( Value key ///< Property key ) const; /// Gets a named property. Value Get( const char* utf8name ///< UTF-8 encoded null-terminated property name ) const; /// Gets a named property. Value Get( const std::string& utf8name ///< UTF-8 encoded property name ) const; /// Sets a property. template void Set( napi_value key, ///< Property key primitive const ValueType& value ///< Property value primitive ); /// Sets a property. template void Set( Value key, ///< Property key const ValueType& value ///< Property value ); /// Sets a named property. template void Set( const char* utf8name, ///< UTF-8 encoded null-terminated property name const ValueType& value ); /// Sets a named property. template void Set( const std::string& utf8name, ///< UTF-8 encoded property name const ValueType& value ///< Property value primitive ); /// Delete property. bool Delete( napi_value key ///< Property key primitive ); /// Delete property. bool Delete( Value key ///< Property key ); /// Delete property. bool Delete( const char* utf8name ///< UTF-8 encoded null-terminated property name ); /// Delete property. bool Delete( const std::string& utf8name ///< UTF-8 encoded property name ); /// Checks whether an indexed property is present. bool Has( uint32_t index ///< Property / element index ) const; /// Gets an indexed property or array element. Value Get( uint32_t index ///< Property / element index ) const; /// Sets an indexed property or array element. template void Set( uint32_t index, ///< Property / element index const ValueType& value ///< Property value primitive ); /// Deletes an indexed property or array element. bool Delete( uint32_t index ///< Property / element index ); Array GetPropertyNames() const; ///< Get all property names /// Defines a property on the object. void DefineProperty( const PropertyDescriptor& property ///< Descriptor for the property to be defined ); /// Defines properties on the object. void DefineProperties( const std::initializer_list& properties ///< List of descriptors for the properties to be defined ); /// Defines properties on the object. void DefineProperties( const std::vector& properties ///< Vector of descriptors for the properties to be defined ); /// Checks if an object is an instance created by a constructor function. /// /// This is equivalent to the JavaScript `instanceof` operator. bool InstanceOf( const Function& constructor ///< Constructor function ) const; template inline void AddFinalizer(Finalizer finalizeCallback, T* data); template inline void AddFinalizer(Finalizer finalizeCallback, T* data, Hint* finalizeHint); }; template class External : public Value { public: static External New(napi_env env, T* data); // Finalizer must implement `void operator()(Env env, T* data)`. template static External New(napi_env env, T* data, Finalizer finalizeCallback); // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`. template static External New(napi_env env, T* data, Finalizer finalizeCallback, Hint* finalizeHint); External(); External(napi_env env, napi_value value); T* Data() const; }; class Array : public Object { public: static Array New(napi_env env); static Array New(napi_env env, size_t length); Array(); Array(napi_env env, napi_value value); uint32_t Length() const; }; /// A JavaScript array buffer value. class ArrayBuffer : public Object { public: /// Creates a new ArrayBuffer instance over a new automatically-allocated buffer. static ArrayBuffer New( napi_env env, ///< N-API environment size_t byteLength ///< Length of the buffer to be allocated, in bytes ); /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. static ArrayBuffer New( napi_env env, ///< N-API environment void* externalData, ///< Pointer to the external buffer to be used by the array size_t byteLength ///< Length of the external buffer to be used by the array, in bytes ); /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. template static ArrayBuffer New( napi_env env, ///< N-API environment void* externalData, ///< Pointer to the external buffer to be used by the array size_t byteLength, ///< Length of the external buffer to be used by the array, /// in bytes Finalizer finalizeCallback ///< Function to be called when the array buffer is destroyed; /// must implement `void operator()(Env env, void* externalData)` ); /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. template static ArrayBuffer New( napi_env env, ///< N-API environment void* externalData, ///< Pointer to the external buffer to be used by the array size_t byteLength, ///< Length of the external buffer to be used by the array, /// in bytes Finalizer finalizeCallback, ///< Function to be called when the array buffer is destroyed; /// must implement `void operator()(Env env, void* externalData, Hint* hint)` Hint* finalizeHint ///< Hint (second parameter) to be passed to the finalize callback ); ArrayBuffer(); ///< Creates a new _empty_ ArrayBuffer instance. ArrayBuffer(napi_env env, napi_value value); ///< Wraps a N-API value primitive. void* Data(); ///< Gets a pointer to the data buffer. size_t ByteLength(); ///< Gets the length of the array buffer in bytes. #if NAPI_VERSION >= 7 bool IsDetached() const; void Detach(); #endif // NAPI_VERSION >= 7 }; /// A JavaScript typed-array value with unknown array type. /// /// For type-specific operations, cast to a `TypedArrayOf` instance using the `As()` /// method: /// /// Napi::TypedArray array = ... /// if (t.TypedArrayType() == napi_int32_array) { /// Napi::Int32Array int32Array = t.As(); /// } class TypedArray : public Object { public: TypedArray(); ///< Creates a new _empty_ TypedArray instance. TypedArray(napi_env env, napi_value value); ///< Wraps a N-API value primitive. napi_typedarray_type TypedArrayType() const; ///< Gets the type of this typed-array. Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer. uint8_t ElementSize() const; ///< Gets the size in bytes of one element in the array. size_t ElementLength() const; ///< Gets the number of elements in the array. size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts. size_t ByteLength() const; ///< Gets the length of the array in bytes. protected: /// !cond INTERNAL napi_typedarray_type _type; size_t _length; TypedArray(napi_env env, napi_value value, napi_typedarray_type type, size_t length); static const napi_typedarray_type unknown_array_type = static_cast(-1); template static #if defined(NAPI_HAS_CONSTEXPR) constexpr #endif napi_typedarray_type TypedArrayTypeForPrimitiveType() { return std::is_same::value ? napi_int8_array : std::is_same::value ? napi_uint8_array : std::is_same::value ? napi_int16_array : std::is_same::value ? napi_uint16_array : std::is_same::value ? napi_int32_array : std::is_same::value ? napi_uint32_array : std::is_same::value ? napi_float32_array : std::is_same::value ? napi_float64_array #if NAPI_VERSION > 5 : std::is_same::value ? napi_bigint64_array : std::is_same::value ? napi_biguint64_array #endif // NAPI_VERSION > 5 : unknown_array_type; } /// !endcond }; /// A JavaScript typed-array value with known array type. /// /// Note while it is possible to create and access Uint8 "clamped" arrays using this class, /// the _clamping_ behavior is only applied in JavaScript. template class TypedArrayOf : public TypedArray { public: /// Creates a new TypedArray instance over a new automatically-allocated array buffer. /// /// The array type parameter can normally be omitted (because it is inferred from the template /// parameter T), except when creating a "clamped" array: /// /// Uint8Array::New(env, length, napi_uint8_clamped_array) static TypedArrayOf New( napi_env env, ///< N-API environment size_t elementLength, ///< Length of the created array, as a number of elements #if defined(NAPI_HAS_CONSTEXPR) napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() #else napi_typedarray_type type #endif ///< Type of array, if different from the default array type for the template parameter T. ); /// Creates a new TypedArray instance over a provided array buffer. /// /// The array type parameter can normally be omitted (because it is inferred from the template /// parameter T), except when creating a "clamped" array: /// /// Uint8Array::New(env, length, buffer, 0, napi_uint8_clamped_array) static TypedArrayOf New( napi_env env, ///< N-API environment size_t elementLength, ///< Length of the created array, as a number of elements Napi::ArrayBuffer arrayBuffer, ///< Backing array buffer instance to use size_t bufferOffset, ///< Offset into the array buffer where the typed-array starts #if defined(NAPI_HAS_CONSTEXPR) napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() #else napi_typedarray_type type #endif ///< Type of array, if different from the default array type for the template parameter T. ); TypedArrayOf(); ///< Creates a new _empty_ TypedArrayOf instance. TypedArrayOf(napi_env env, napi_value value); ///< Wraps a N-API value primitive. T& operator [](size_t index); ///< Gets or sets an element in the array. const T& operator [](size_t index) const; ///< Gets an element in the array. /// Gets a pointer to the array's backing buffer. /// /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. T* Data(); /// Gets a pointer to the array's backing buffer. /// /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. const T* Data() const; private: T* _data; TypedArrayOf(napi_env env, napi_value value, napi_typedarray_type type, size_t length, T* data); }; /// The DataView provides a low-level interface for reading/writing multiple /// number types in an ArrayBuffer irrespective of the platform's endianness. class DataView : public Object { public: static DataView New(napi_env env, Napi::ArrayBuffer arrayBuffer); static DataView New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset); static DataView New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset, size_t byteLength); DataView(); ///< Creates a new _empty_ DataView instance. DataView(napi_env env, napi_value value); ///< Wraps a N-API value primitive. Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer. size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts. size_t ByteLength() const; ///< Gets the length of the array in bytes. void* Data() const; float GetFloat32(size_t byteOffset) const; double GetFloat64(size_t byteOffset) const; int8_t GetInt8(size_t byteOffset) const; int16_t GetInt16(size_t byteOffset) const; int32_t GetInt32(size_t byteOffset) const; uint8_t GetUint8(size_t byteOffset) const; uint16_t GetUint16(size_t byteOffset) const; uint32_t GetUint32(size_t byteOffset) const; void SetFloat32(size_t byteOffset, float value) const; void SetFloat64(size_t byteOffset, double value) const; void SetInt8(size_t byteOffset, int8_t value) const; void SetInt16(size_t byteOffset, int16_t value) const; void SetInt32(size_t byteOffset, int32_t value) const; void SetUint8(size_t byteOffset, uint8_t value) const; void SetUint16(size_t byteOffset, uint16_t value) const; void SetUint32(size_t byteOffset, uint32_t value) const; private: template T ReadData(size_t byteOffset) const; template void WriteData(size_t byteOffset, T value) const; void* _data; size_t _length; }; class Function : public Object { public: typedef void (*VoidCallback)(const CallbackInfo& info); typedef Value (*Callback)(const CallbackInfo& info); template static Function New(napi_env env, const char* utf8name = nullptr, void* data = nullptr); template static Function New(napi_env env, const char* utf8name = nullptr, void* data = nullptr); template static Function New(napi_env env, const std::string& utf8name, void* data = nullptr); template static Function New(napi_env env, const std::string& utf8name, void* data = nullptr); /// Callable must implement operator() accepting a const CallbackInfo& /// and return either void or Value. template static Function New(napi_env env, Callable cb, const char* utf8name = nullptr, void* data = nullptr); /// Callable must implement operator() accepting a const CallbackInfo& /// and return either void or Value. template static Function New(napi_env env, Callable cb, const std::string& utf8name, void* data = nullptr); Function(); Function(napi_env env, napi_value value); Value operator ()(const std::initializer_list& args) const; Value Call(const std::initializer_list& args) const; Value Call(const std::vector& args) const; Value Call(size_t argc, const napi_value* args) const; Value Call(napi_value recv, const std::initializer_list& args) const; Value Call(napi_value recv, const std::vector& args) const; Value Call(napi_value recv, size_t argc, const napi_value* args) const; Value MakeCallback(napi_value recv, const std::initializer_list& args, napi_async_context context = nullptr) const; Value MakeCallback(napi_value recv, const std::vector& args, napi_async_context context = nullptr) const; Value MakeCallback(napi_value recv, size_t argc, const napi_value* args, napi_async_context context = nullptr) const; Object New(const std::initializer_list& args) const; Object New(const std::vector& args) const; Object New(size_t argc, const napi_value* args) const; }; class Promise : public Object { public: class Deferred { public: static Deferred New(napi_env env); Deferred(napi_env env); Napi::Promise Promise() const; Napi::Env Env() const; void Resolve(napi_value value) const; void Reject(napi_value value) const; private: napi_env _env; napi_deferred _deferred; napi_value _promise; }; Promise(napi_env env, napi_value value); }; template class Buffer : public Uint8Array { public: static Buffer New(napi_env env, size_t length); static Buffer New(napi_env env, T* data, size_t length); // Finalizer must implement `void operator()(Env env, T* data)`. template static Buffer New(napi_env env, T* data, size_t length, Finalizer finalizeCallback); // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`. template static Buffer New(napi_env env, T* data, size_t length, Finalizer finalizeCallback, Hint* finalizeHint); static Buffer Copy(napi_env env, const T* data, size_t length); Buffer(); Buffer(napi_env env, napi_value value); size_t Length() const; T* Data() const; private: mutable size_t _length; mutable T* _data; Buffer(napi_env env, napi_value value, size_t length, T* data); void EnsureInfo() const; }; /// Holds a counted reference to a value; initially a weak reference unless otherwise specified, /// may be changed to/from a strong reference by adjusting the refcount. /// /// The referenced value is not immediately destroyed when the reference count is zero; it is /// merely then eligible for garbage-collection if there are no other references to the value. template class Reference { public: static Reference New(const T& value, uint32_t initialRefcount = 0); Reference(); Reference(napi_env env, napi_ref ref); ~Reference(); // A reference can be moved but cannot be copied. Reference(Reference&& other); Reference& operator =(Reference&& other); NAPI_DISALLOW_ASSIGN(Reference) operator napi_ref() const; bool operator ==(const Reference &other) const; bool operator !=(const Reference &other) const; Napi::Env Env() const; bool IsEmpty() const; // Note when getting the value of a Reference it is usually correct to do so // within a HandleScope so that the value handle gets cleaned up efficiently. T Value() const; uint32_t Ref(); uint32_t Unref(); void Reset(); void Reset(const T& value, uint32_t refcount = 0); // Call this on a reference that is declared as static data, to prevent its destructor // from running at program shutdown time, which would attempt to reset the reference when // the environment is no longer valid. void SuppressDestruct(); protected: Reference(const Reference&); /// !cond INTERNAL napi_env _env; napi_ref _ref; /// !endcond private: bool _suppressDestruct; }; class ObjectReference: public Reference { public: ObjectReference(); ObjectReference(napi_env env, napi_ref ref); // A reference can be moved but cannot be copied. ObjectReference(Reference&& other); ObjectReference& operator =(Reference&& other); ObjectReference(ObjectReference&& other); ObjectReference& operator =(ObjectReference&& other); NAPI_DISALLOW_ASSIGN(ObjectReference) Napi::Value Get(const char* utf8name) const; Napi::Value Get(const std::string& utf8name) const; void Set(const char* utf8name, napi_value value); void Set(const char* utf8name, Napi::Value value); void Set(const char* utf8name, const char* utf8value); void Set(const char* utf8name, bool boolValue); void Set(const char* utf8name, double numberValue); void Set(const std::string& utf8name, napi_value value); void Set(const std::string& utf8name, Napi::Value value); void Set(const std::string& utf8name, std::string& utf8value); void Set(const std::string& utf8name, bool boolValue); void Set(const std::string& utf8name, double numberValue); Napi::Value Get(uint32_t index) const; void Set(uint32_t index, const napi_value value); void Set(uint32_t index, const Napi::Value value); void Set(uint32_t index, const char* utf8value); void Set(uint32_t index, const std::string& utf8value); void Set(uint32_t index, bool boolValue); void Set(uint32_t index, double numberValue); protected: ObjectReference(const ObjectReference&); }; class FunctionReference: public Reference { public: FunctionReference(); FunctionReference(napi_env env, napi_ref ref); // A reference can be moved but cannot be copied. FunctionReference(Reference&& other); FunctionReference& operator =(Reference&& other); FunctionReference(FunctionReference&& other); FunctionReference& operator =(FunctionReference&& other); NAPI_DISALLOW_ASSIGN_COPY(FunctionReference) Napi::Value operator ()(const std::initializer_list& args) const; Napi::Value Call(const std::initializer_list& args) const; Napi::Value Call(const std::vector& args) const; Napi::Value Call(napi_value recv, const std::initializer_list& args) const; Napi::Value Call(napi_value recv, const std::vector& args) const; Napi::Value Call(napi_value recv, size_t argc, const napi_value* args) const; Napi::Value MakeCallback(napi_value recv, const std::initializer_list& args, napi_async_context context = nullptr) const; Napi::Value MakeCallback(napi_value recv, const std::vector& args, napi_async_context context = nullptr) const; Napi::Value MakeCallback(napi_value recv, size_t argc, const napi_value* args, napi_async_context context = nullptr) const; Object New(const std::initializer_list& args) const; Object New(const std::vector& args) const; }; // Shortcuts to creating a new reference with inferred type and refcount = 0. template Reference Weak(T value); ObjectReference Weak(Object value); FunctionReference Weak(Function value); // Shortcuts to creating a new reference with inferred type and refcount = 1. template Reference Persistent(T value); ObjectReference Persistent(Object value); FunctionReference Persistent(Function value); /// A persistent reference to a JavaScript error object. Use of this class depends somewhat /// on whether C++ exceptions are enabled at compile time. /// /// ### Handling Errors With C++ Exceptions /// /// If C++ exceptions are enabled, then the `Error` class extends `std::exception` and enables /// integrated error-handling for C++ exceptions and JavaScript exceptions. /// /// If a N-API call fails without executing any JavaScript code (for example due to an invalid /// argument), then the N-API wrapper automatically converts and throws the error as a C++ /// exception of type `Napi::Error`. Or if a JavaScript function called by C++ code via N-API /// throws a JavaScript exception, then the N-API wrapper automatically converts and throws it as /// a C++ exception of type `Napi::Error`. /// /// If a C++ exception of type `Napi::Error` escapes from a N-API C++ callback, then the N-API /// wrapper automatically converts and throws it as a JavaScript exception. Therefore, catching /// a C++ exception of type `Napi::Error` prevents a JavaScript exception from being thrown. /// /// #### Example 1A - Throwing a C++ exception: /// /// Napi::Env env = ... /// throw Napi::Error::New(env, "Example exception"); /// /// Following C++ statements will not be executed. The exception will bubble up as a C++ /// exception of type `Napi::Error`, until it is either caught while still in C++, or else /// automatically propataged as a JavaScript exception when the callback returns to JavaScript. /// /// #### Example 2A - Propagating a N-API C++ exception: /// /// Napi::Function jsFunctionThatThrows = someObj.As(); /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); /// /// Following C++ statements will not be executed. The exception will bubble up as a C++ /// exception of type `Napi::Error`, until it is either caught while still in C++, or else /// automatically propagated as a JavaScript exception when the callback returns to JavaScript. /// /// #### Example 3A - Handling a N-API C++ exception: /// /// Napi::Function jsFunctionThatThrows = someObj.As(); /// Napi::Value result; /// try { /// result = jsFunctionThatThrows({ arg1, arg2 }); /// } catch (const Napi::Error& e) { /// cerr << "Caught JavaScript exception: " + e.what(); /// } /// /// Since the exception was caught here, it will not be propagated as a JavaScript exception. /// /// ### Handling Errors Without C++ Exceptions /// /// If C++ exceptions are disabled (by defining `NAPI_DISABLE_CPP_EXCEPTIONS`) then this class /// does not extend `std::exception`, and APIs in the `Napi` namespace do not throw C++ /// exceptions when they fail. Instead, they raise _pending_ JavaScript exceptions and /// return _empty_ `Value`s. Calling code should check `Value::IsEmpty()` before attempting /// to use a returned value, and may use methods on the `Env` class to check for, get, and /// clear a pending JavaScript exception. If the pending exception is not cleared, it will /// be thrown when the native callback returns to JavaScript. /// /// #### Example 1B - Throwing a JS exception /// /// Napi::Env env = ... /// Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException(); /// return; /// /// After throwing a JS exception, the code should generally return immediately from the native /// callback, after performing any necessary cleanup. /// /// #### Example 2B - Propagating a N-API JS exception: /// /// Napi::Function jsFunctionThatThrows = someObj.As(); /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); /// if (result.IsEmpty()) return; /// /// An empty value result from a N-API call indicates an error occurred, and a JavaScript /// exception is pending. To let the exception propagate, the code should generally return /// immediately from the native callback, after performing any necessary cleanup. /// /// #### Example 3B - Handling a N-API JS exception: /// /// Napi::Function jsFunctionThatThrows = someObj.As(); /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); /// if (result.IsEmpty()) { /// Napi::Error e = env.GetAndClearPendingException(); /// cerr << "Caught JavaScript exception: " + e.Message(); /// } /// /// Since the exception was cleared here, it will not be propagated as a JavaScript exception /// after the native callback returns. class Error : public ObjectReference #ifdef NAPI_CPP_EXCEPTIONS , public std::exception #endif // NAPI_CPP_EXCEPTIONS { public: static Error New(napi_env env); static Error New(napi_env env, const char* message); static Error New(napi_env env, const std::string& message); static NAPI_NO_RETURN void Fatal(const char* location, const char* message); Error(); Error(napi_env env, napi_value value); // An error can be moved or copied. Error(Error&& other); Error& operator =(Error&& other); Error(const Error&); Error& operator =(const Error&); const std::string& Message() const NAPI_NOEXCEPT; void ThrowAsJavaScriptException() const; #ifdef NAPI_CPP_EXCEPTIONS const char* what() const NAPI_NOEXCEPT override; #endif // NAPI_CPP_EXCEPTIONS protected: /// !cond INTERNAL typedef napi_status (*create_error_fn)(napi_env envb, napi_value code, napi_value msg, napi_value* result); template static TError New(napi_env env, const char* message, size_t length, create_error_fn create_error); /// !endcond private: mutable std::string _message; }; class TypeError : public Error { public: static TypeError New(napi_env env, const char* message); static TypeError New(napi_env env, const std::string& message); TypeError(); TypeError(napi_env env, napi_value value); }; class RangeError : public Error { public: static RangeError New(napi_env env, const char* message); static RangeError New(napi_env env, const std::string& message); RangeError(); RangeError(napi_env env, napi_value value); }; class CallbackInfo { public: CallbackInfo(napi_env env, napi_callback_info info); ~CallbackInfo(); // Disallow copying to prevent multiple free of _dynamicArgs NAPI_DISALLOW_ASSIGN_COPY(CallbackInfo) Napi::Env Env() const; Value NewTarget() const; bool IsConstructCall() const; size_t Length() const; const Value operator [](size_t index) const; Value This() const; void* Data() const; void SetData(void* data); private: const size_t _staticArgCount = 6; napi_env _env; napi_callback_info _info; napi_value _this; size_t _argc; napi_value* _argv; napi_value _staticArgs[6]; napi_value* _dynamicArgs; void* _data; }; class PropertyDescriptor { public: typedef Napi::Value (*GetterCallback)(const Napi::CallbackInfo& info); typedef void (*SetterCallback)(const Napi::CallbackInfo& info); #ifndef NODE_ADDON_API_DISABLE_DEPRECATED template static PropertyDescriptor Accessor(const char* utf8name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const std::string& utf8name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(napi_value name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Name name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const char* utf8name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const std::string& utf8name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(napi_value name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Name name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(const char* utf8name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(const std::string& utf8name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(napi_value name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(Name name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); #endif // !NODE_ADDON_API_DISABLE_DEPRECATED template static PropertyDescriptor Accessor(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const std::string& utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Name name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(const std::string& utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Name name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, const char* utf8name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, const std::string& utf8name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, Name name, Getter getter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, const char* utf8name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, const std::string& utf8name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Accessor(Napi::Env env, Napi::Object object, Name name, Getter getter, Setter setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(Napi::Env env, Napi::Object object, const char* utf8name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(Napi::Env env, Napi::Object object, const std::string& utf8name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor Function(Napi::Env env, Napi::Object object, Name name, Callable cb, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor Value(const char* utf8name, napi_value value, napi_property_attributes attributes = napi_default); static PropertyDescriptor Value(const std::string& utf8name, napi_value value, napi_property_attributes attributes = napi_default); static PropertyDescriptor Value(napi_value name, napi_value value, napi_property_attributes attributes = napi_default); static PropertyDescriptor Value(Name name, Napi::Value value, napi_property_attributes attributes = napi_default); PropertyDescriptor(napi_property_descriptor desc); operator napi_property_descriptor&(); operator const napi_property_descriptor&() const; private: napi_property_descriptor _desc; }; /// Property descriptor for use with `ObjectWrap::DefineClass()`. /// /// This is different from the standalone `PropertyDescriptor` because it is specific to each /// `ObjectWrap` subclass. This prevents using descriptors from a different class when /// defining a new class (preventing the callbacks from having incorrect `this` pointers). template class ClassPropertyDescriptor { public: ClassPropertyDescriptor(napi_property_descriptor desc) : _desc(desc) {} operator napi_property_descriptor&() { return _desc; } operator const napi_property_descriptor&() const { return _desc; } private: napi_property_descriptor _desc; }; template struct MethodCallbackData { TCallback callback; void* data; }; template struct AccessorCallbackData { TGetterCallback getterCallback; TSetterCallback setterCallback; void* data; }; template class InstanceWrap { public: typedef void (T::*InstanceVoidMethodCallback)(const CallbackInfo& info); typedef Napi::Value (T::*InstanceMethodCallback)(const CallbackInfo& info); typedef Napi::Value (T::*InstanceGetterCallback)(const CallbackInfo& info); typedef void (T::*InstanceSetterCallback)(const CallbackInfo& info, const Napi::Value& value); typedef ClassPropertyDescriptor PropertyDescriptor; static PropertyDescriptor InstanceMethod(const char* utf8name, InstanceVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceMethod(const char* utf8name, InstanceMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceMethod(Symbol name, InstanceVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceMethod(Symbol name, InstanceMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceMethod(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceMethod(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceMethod(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceMethod(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceAccessor(const char* utf8name, InstanceGetterCallback getter, InstanceSetterCallback setter, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceAccessor(Symbol name, InstanceGetterCallback getter, InstanceSetterCallback setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceAccessor(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor InstanceAccessor(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor InstanceValue(const char* utf8name, Napi::Value value, napi_property_attributes attributes = napi_default); static PropertyDescriptor InstanceValue(Symbol name, Napi::Value value, napi_property_attributes attributes = napi_default); protected: static void AttachPropData(napi_env env, napi_value value, const napi_property_descriptor* prop); private: using This = InstanceWrap; typedef MethodCallbackData InstanceVoidMethodCallbackData; typedef MethodCallbackData InstanceMethodCallbackData; typedef AccessorCallbackData InstanceAccessorCallbackData; static napi_value InstanceVoidMethodCallbackWrapper(napi_env env, napi_callback_info info); static napi_value InstanceMethodCallbackWrapper(napi_env env, napi_callback_info info); static napi_value InstanceGetterCallbackWrapper(napi_env env, napi_callback_info info); static napi_value InstanceSetterCallbackWrapper(napi_env env, napi_callback_info info); template static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; template struct SetterTag {}; template static napi_callback WrapSetter(SetterTag) noexcept { return &This::WrappedMethod; } static napi_callback WrapSetter(SetterTag) noexcept { return nullptr; } }; /// Base class to be extended by C++ classes exposed to JavaScript; each C++ class instance gets /// "wrapped" by a JavaScript object that is managed by this class. /// /// At initialization time, the `DefineClass()` method must be used to /// hook up the accessor and method callbacks. It takes a list of /// property descriptors, which can be constructed via the various /// static methods on the base class. /// /// #### Example: /// /// class Example: public Napi::ObjectWrap { /// public: /// static void Initialize(Napi::Env& env, Napi::Object& target) { /// Napi::Function constructor = DefineClass(env, "Example", { /// InstanceAccessor<&Example::GetSomething, &Example::SetSomething>("value"), /// InstanceMethod<&Example::DoSomething>("doSomething"), /// }); /// target.Set("Example", constructor); /// } /// /// Example(const Napi::CallbackInfo& info); // Constructor /// Napi::Value GetSomething(const Napi::CallbackInfo& info); /// void SetSomething(const Napi::CallbackInfo& info, const Napi::Value& value); /// Napi::Value DoSomething(const Napi::CallbackInfo& info); /// } template class ObjectWrap : public InstanceWrap, public Reference { public: ObjectWrap(const CallbackInfo& callbackInfo); virtual ~ObjectWrap(); static T* Unwrap(Object wrapper); // Methods exposed to JavaScript must conform to one of these callback signatures. typedef void (*StaticVoidMethodCallback)(const CallbackInfo& info); typedef Napi::Value (*StaticMethodCallback)(const CallbackInfo& info); typedef Napi::Value (*StaticGetterCallback)(const CallbackInfo& info); typedef void (*StaticSetterCallback)(const CallbackInfo& info, const Napi::Value& value); typedef ClassPropertyDescriptor PropertyDescriptor; static Function DefineClass(Napi::Env env, const char* utf8name, const std::initializer_list& properties, void* data = nullptr); static Function DefineClass(Napi::Env env, const char* utf8name, const std::vector& properties, void* data = nullptr); static PropertyDescriptor StaticMethod(const char* utf8name, StaticVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticMethod(const char* utf8name, StaticMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticMethod(Symbol name, StaticVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticMethod(Symbol name, StaticMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticMethod(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticMethod(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticMethod(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticMethod(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticAccessor(const char* utf8name, StaticGetterCallback getter, StaticSetterCallback setter, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticAccessor(Symbol name, StaticGetterCallback getter, StaticSetterCallback setter, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticAccessor(const char* utf8name, napi_property_attributes attributes = napi_default, void* data = nullptr); template static PropertyDescriptor StaticAccessor(Symbol name, napi_property_attributes attributes = napi_default, void* data = nullptr); static PropertyDescriptor StaticValue(const char* utf8name, Napi::Value value, napi_property_attributes attributes = napi_default); static PropertyDescriptor StaticValue(Symbol name, Napi::Value value, napi_property_attributes attributes = napi_default); virtual void Finalize(Napi::Env env); private: using This = ObjectWrap; static napi_value ConstructorCallbackWrapper(napi_env env, napi_callback_info info); static napi_value StaticVoidMethodCallbackWrapper(napi_env env, napi_callback_info info); static napi_value StaticMethodCallbackWrapper(napi_env env, napi_callback_info info); static napi_value StaticGetterCallbackWrapper(napi_env env, napi_callback_info info); static napi_value StaticSetterCallbackWrapper(napi_env env, napi_callback_info info); static void FinalizeCallback(napi_env env, void* data, void* hint); static Function DefineClass(Napi::Env env, const char* utf8name, const size_t props_count, const napi_property_descriptor* props, void* data = nullptr); typedef MethodCallbackData StaticVoidMethodCallbackData; typedef MethodCallbackData StaticMethodCallbackData; typedef AccessorCallbackData StaticAccessorCallbackData; template static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; template struct StaticSetterTag {}; template static napi_callback WrapStaticSetter(StaticSetterTag) noexcept { return &This::WrappedMethod; } static napi_callback WrapStaticSetter(StaticSetterTag) noexcept { return nullptr; } bool _construction_failed = true; }; class HandleScope { public: HandleScope(napi_env env, napi_handle_scope scope); explicit HandleScope(Napi::Env env); ~HandleScope(); // Disallow copying to prevent double close of napi_handle_scope NAPI_DISALLOW_ASSIGN_COPY(HandleScope) operator napi_handle_scope() const; Napi::Env Env() const; private: napi_env _env; napi_handle_scope _scope; }; class EscapableHandleScope { public: EscapableHandleScope(napi_env env, napi_escapable_handle_scope scope); explicit EscapableHandleScope(Napi::Env env); ~EscapableHandleScope(); // Disallow copying to prevent double close of napi_escapable_handle_scope NAPI_DISALLOW_ASSIGN_COPY(EscapableHandleScope) operator napi_escapable_handle_scope() const; Napi::Env Env() const; Value Escape(napi_value escapee); private: napi_env _env; napi_escapable_handle_scope _scope; }; #if (NAPI_VERSION > 2) class CallbackScope { public: CallbackScope(napi_env env, napi_callback_scope scope); CallbackScope(napi_env env, napi_async_context context); virtual ~CallbackScope(); // Disallow copying to prevent double close of napi_callback_scope NAPI_DISALLOW_ASSIGN_COPY(CallbackScope) operator napi_callback_scope() const; Napi::Env Env() const; private: napi_env _env; napi_callback_scope _scope; }; #endif class AsyncContext { public: explicit AsyncContext(napi_env env, const char* resource_name); explicit AsyncContext(napi_env env, const char* resource_name, const Object& resource); virtual ~AsyncContext(); AsyncContext(AsyncContext&& other); AsyncContext& operator =(AsyncContext&& other); NAPI_DISALLOW_ASSIGN_COPY(AsyncContext) operator napi_async_context() const; Napi::Env Env() const; private: napi_env _env; napi_async_context _context; }; class AsyncWorker { public: virtual ~AsyncWorker(); // An async worker can be moved but cannot be copied. AsyncWorker(AsyncWorker&& other); AsyncWorker& operator =(AsyncWorker&& other); NAPI_DISALLOW_ASSIGN_COPY(AsyncWorker) operator napi_async_work() const; Napi::Env Env() const; void Queue(); void Cancel(); void SuppressDestruct(); ObjectReference& Receiver(); FunctionReference& Callback(); virtual void OnExecute(Napi::Env env); virtual void OnWorkComplete(Napi::Env env, napi_status status); protected: explicit AsyncWorker(const Function& callback); explicit AsyncWorker(const Function& callback, const char* resource_name); explicit AsyncWorker(const Function& callback, const char* resource_name, const Object& resource); explicit AsyncWorker(const Object& receiver, const Function& callback); explicit AsyncWorker(const Object& receiver, const Function& callback, const char* resource_name); explicit AsyncWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource); explicit AsyncWorker(Napi::Env env); explicit AsyncWorker(Napi::Env env, const char* resource_name); explicit AsyncWorker(Napi::Env env, const char* resource_name, const Object& resource); virtual void Execute() = 0; virtual void OnOK(); virtual void OnError(const Error& e); virtual void Destroy(); virtual std::vector GetResult(Napi::Env env); void SetError(const std::string& error); private: static inline void OnAsyncWorkExecute(napi_env env, void* asyncworker); static inline void OnAsyncWorkComplete(napi_env env, napi_status status, void* asyncworker); napi_env _env; napi_async_work _work; ObjectReference _receiver; FunctionReference _callback; std::string _error; bool _suppress_destruct; }; #if (NAPI_VERSION > 3 && !defined(__wasm32__)) class ThreadSafeFunction { public: // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback, FinalizerDataType* data); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, Finalizer finalizeCallback, FinalizerDataType* data); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback); // This API may only be called from the main thread. template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data); ThreadSafeFunction(); ThreadSafeFunction(napi_threadsafe_function tsFunctionValue); operator napi_threadsafe_function() const; // This API may be called from any thread. napi_status BlockingCall() const; // This API may be called from any thread. template napi_status BlockingCall(Callback callback) const; // This API may be called from any thread. template napi_status BlockingCall(DataType* data, Callback callback) const; // This API may be called from any thread. napi_status NonBlockingCall() const; // This API may be called from any thread. template napi_status NonBlockingCall(Callback callback) const; // This API may be called from any thread. template napi_status NonBlockingCall(DataType* data, Callback callback) const; // This API may only be called from the main thread. void Ref(napi_env env) const; // This API may only be called from the main thread. void Unref(napi_env env) const; // This API may be called from any thread. napi_status Acquire() const; // This API may be called from any thread. napi_status Release(); // This API may be called from any thread. napi_status Abort(); struct ConvertibleContext { template operator T*() { return static_cast(context); } void* context; }; // This API may be called from any thread. ConvertibleContext GetContext() const; private: using CallbackWrapper = std::function; template static ThreadSafeFunction New(napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data, napi_finalize wrapper); napi_status CallInternal(CallbackWrapper* callbackWrapper, napi_threadsafe_function_call_mode mode) const; static void CallJS(napi_env env, napi_value jsCallback, void* context, void* data); napi_threadsafe_function _tsfn; }; // A TypedThreadSafeFunction by default has no context (nullptr) and can // accept any type (void) to its CallJs. template class TypedThreadSafeFunction { public: // This API may only be called from the main thread. // Helper function that returns nullptr if running N-API 5+, otherwise a // non-empty, no-op Function. This provides the ability to specify at // compile-time a callback parameter to `New` that safely does no action // when targeting _any_ N-API version. #if NAPI_VERSION > 4 static std::nullptr_t EmptyFunctionFactory(Napi::Env env); #else static Napi::Function EmptyFunctionFactory(Napi::Env env); #endif static Napi::Function FunctionOrEmpty(Napi::Env env, Napi::Function& callback); #if NAPI_VERSION > 4 // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [missing] Resource [missing] Finalizer [missing] template static TypedThreadSafeFunction New( napi_env env, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [missing] Resource [passed] Finalizer [missing] template static TypedThreadSafeFunction New( napi_env env, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [missing] Resource [missing] Finalizer [passed] template static TypedThreadSafeFunction New( napi_env env, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [missing] Resource [passed] Finalizer [passed] template static TypedThreadSafeFunction New( napi_env env, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data = nullptr); #endif // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [passed] Resource [missing] Finalizer [missing] template static TypedThreadSafeFunction New( napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [passed] Resource [passed] Finalizer [missing] template static TypedThreadSafeFunction New( napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [passed] Resource [missing] Finalizer [passed] template static TypedThreadSafeFunction New( napi_env env, const Function& callback, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data = nullptr); // This API may only be called from the main thread. // Creates a new threadsafe function with: // Callback [passed] Resource [passed] Finalizer [passed] template static TypedThreadSafeFunction New( napi_env env, CallbackType callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data = nullptr); TypedThreadSafeFunction(); TypedThreadSafeFunction( napi_threadsafe_function tsFunctionValue); operator napi_threadsafe_function() const; // This API may be called from any thread. napi_status BlockingCall(DataType* data = nullptr) const; // This API may be called from any thread. napi_status NonBlockingCall(DataType* data = nullptr) const; // This API may only be called from the main thread. void Ref(napi_env env) const; // This API may only be called from the main thread. void Unref(napi_env env) const; // This API may be called from any thread. napi_status Acquire() const; // This API may be called from any thread. napi_status Release(); // This API may be called from any thread. napi_status Abort(); // This API may be called from any thread. ContextType* GetContext() const; private: template static TypedThreadSafeFunction New( napi_env env, const Function& callback, const Object& resource, ResourceString resourceName, size_t maxQueueSize, size_t initialThreadCount, ContextType* context, Finalizer finalizeCallback, FinalizerDataType* data, napi_finalize wrapper); static void CallJsInternal(napi_env env, napi_value jsCallback, void* context, void* data); protected: napi_threadsafe_function _tsfn; }; template class AsyncProgressWorkerBase : public AsyncWorker { public: virtual void OnWorkProgress(DataType* data) = 0; class ThreadSafeData { public: ThreadSafeData(AsyncProgressWorkerBase* asyncprogressworker, DataType* data) : _asyncprogressworker(asyncprogressworker), _data(data) {} AsyncProgressWorkerBase* asyncprogressworker() { return _asyncprogressworker; }; DataType* data() { return _data; }; private: AsyncProgressWorkerBase* _asyncprogressworker; DataType* _data; }; void OnWorkComplete(Napi::Env env, napi_status status) override; protected: explicit AsyncProgressWorkerBase(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource, size_t queue_size = 1); virtual ~AsyncProgressWorkerBase(); // Optional callback of Napi::ThreadSafeFunction only available after NAPI_VERSION 4. // Refs: https://github.com/nodejs/node/pull/27791 #if NAPI_VERSION > 4 explicit AsyncProgressWorkerBase(Napi::Env env, const char* resource_name, const Object& resource, size_t queue_size = 1); #endif static inline void OnAsyncWorkProgress(Napi::Env env, Napi::Function jsCallback, void* data); napi_status NonBlockingCall(DataType* data); private: ThreadSafeFunction _tsfn; bool _work_completed = false; napi_status _complete_status; static inline void OnThreadSafeFunctionFinalize(Napi::Env env, void* data, AsyncProgressWorkerBase* context); }; template class AsyncProgressWorker : public AsyncProgressWorkerBase { public: virtual ~AsyncProgressWorker(); class ExecutionProgress { friend class AsyncProgressWorker; public: void Signal() const; void Send(const T* data, size_t count) const; private: explicit ExecutionProgress(AsyncProgressWorker* worker) : _worker(worker) {} AsyncProgressWorker* const _worker; }; void OnWorkProgress(void*) override; protected: explicit AsyncProgressWorker(const Function& callback); explicit AsyncProgressWorker(const Function& callback, const char* resource_name); explicit AsyncProgressWorker(const Function& callback, const char* resource_name, const Object& resource); explicit AsyncProgressWorker(const Object& receiver, const Function& callback); explicit AsyncProgressWorker(const Object& receiver, const Function& callback, const char* resource_name); explicit AsyncProgressWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource); // Optional callback of Napi::ThreadSafeFunction only available after NAPI_VERSION 4. // Refs: https://github.com/nodejs/node/pull/27791 #if NAPI_VERSION > 4 explicit AsyncProgressWorker(Napi::Env env); explicit AsyncProgressWorker(Napi::Env env, const char* resource_name); explicit AsyncProgressWorker(Napi::Env env, const char* resource_name, const Object& resource); #endif virtual void Execute(const ExecutionProgress& progress) = 0; virtual void OnProgress(const T* data, size_t count) = 0; private: void Execute() override; void Signal() const; void SendProgress_(const T* data, size_t count); std::mutex _mutex; T* _asyncdata; size_t _asyncsize; }; template class AsyncProgressQueueWorker : public AsyncProgressWorkerBase> { public: virtual ~AsyncProgressQueueWorker() {}; class ExecutionProgress { friend class AsyncProgressQueueWorker; public: void Signal() const; void Send(const T* data, size_t count) const; private: explicit ExecutionProgress(AsyncProgressQueueWorker* worker) : _worker(worker) {} AsyncProgressQueueWorker* const _worker; }; void OnWorkComplete(Napi::Env env, napi_status status) override; void OnWorkProgress(std::pair*) override; protected: explicit AsyncProgressQueueWorker(const Function& callback); explicit AsyncProgressQueueWorker(const Function& callback, const char* resource_name); explicit AsyncProgressQueueWorker(const Function& callback, const char* resource_name, const Object& resource); explicit AsyncProgressQueueWorker(const Object& receiver, const Function& callback); explicit AsyncProgressQueueWorker(const Object& receiver, const Function& callback, const char* resource_name); explicit AsyncProgressQueueWorker(const Object& receiver, const Function& callback, const char* resource_name, const Object& resource); // Optional callback of Napi::ThreadSafeFunction only available after NAPI_VERSION 4. // Refs: https://github.com/nodejs/node/pull/27791 #if NAPI_VERSION > 4 explicit AsyncProgressQueueWorker(Napi::Env env); explicit AsyncProgressQueueWorker(Napi::Env env, const char* resource_name); explicit AsyncProgressQueueWorker(Napi::Env env, const char* resource_name, const Object& resource); #endif virtual void Execute(const ExecutionProgress& progress) = 0; virtual void OnProgress(const T* data, size_t count) = 0; private: void Execute() override; void Signal() const; void SendProgress_(const T* data, size_t count); }; #endif // NAPI_VERSION > 3 && !defined(__wasm32__) // Memory management. class MemoryManagement { public: static int64_t AdjustExternalMemory(Env env, int64_t change_in_bytes); }; // Version management class VersionManagement { public: static uint32_t GetNapiVersion(Env env); static const napi_node_version* GetNodeVersion(Env env); }; #if NAPI_VERSION > 5 template class Addon : public InstanceWrap { public: static inline Object Init(Env env, Object exports); static T* Unwrap(Object wrapper); protected: typedef ClassPropertyDescriptor AddonProp; void DefineAddon(Object exports, const std::initializer_list& props); Napi::Object DefineProperties(Object object, const std::initializer_list& props); private: Object entry_point_; }; #endif // NAPI_VERSION > 5 } // namespace Napi // Inline implementations of all the above class methods are included here. #include "napi-inl.h" #endif // SRC_NAPI_H_ { 'targets': [ { 'target_name': 'nothing', 'type': 'static_library', 'sources': [ 'nothing.c' ] } ] } { 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ], 'cflags': [ '-fno-exceptions' ], 'cflags_cc': [ '-fno-exceptions' ], 'msvs_settings': { 'VCCLCompilerTool': { 'ExceptionHandling': 0, 'EnablePREfast': 'true', }, }, 'xcode_settings': { 'CLANG_CXX_LIBRARY': 'libc++', 'MACOSX_DEPLOYMENT_TARGET': '10.7', 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', }, } { "versions": [ { "version": "*", "target": { "node": "active" }, "response": { "type": "time-permitting", "paid": false, "contact": { "name": "node-addon-api team", "url": "https://github.com/nodejs/node-addon-api/issues" } }, "backing": [ { "project": "https://github.com/nodejs" }, { "foundation": "https://openjsf.org/" } ] } ] } { "dependencies": {}, "deprecated": false, "description": "Node.js API (N-API)", "devDependencies": { "benchmark": "^2.1.4", "bindings": "^1.5.0", "clang-format": "^1.4.0", "fs-extra": "^9.0.1", "pre-commit": "^1.2.2", "safe-buffer": "^5.1.1" }, "directories": {}, "gypfile": false, "homepage": "https://github.com/nodejs/node-addon-api", "license": "MIT", "main": "index.js", "name": "node-addon-api", "optionalDependencies": {}, "pre-commit": "lint", "repository": { "type": "git", "url": "git://github.com/nodejs/node-addon-api.git" }, "support": true, "version": "3.1.0" }# Tools ## clang-format The clang-format checking tools is designed to check changed lines of code compared to given git-refs. ## Migration Script The migration tool is designed to reduce repetitive work in the migration process. However, the script is not aiming to convert every thing for you. There are usually some small fixes and major reconstruction required. ### How To Use To run the conversion script, first make sure you have the latest `node-addon-api` in your `node_modules` directory. ``` npm install node-addon-api ``` Then run the script passing your project directory ``` node ./node_modules/node-addon-api/tools/conversion.js ./ ``` After finish, recompile and debug things that are missed by the script. ### Quick Fixes Here is the list of things that can be fixed easily. 1. Change your methods' return value to void if it doesn't return value to JavaScript. 2. Use `.` to access attribute or to invoke member function in Napi::Object instead of `->`. 3. `Napi::New(env, value);` to `Napi::[Type]::New(env, value); ### Major Reconstructions The implementation of `Napi::ObjectWrap` is significantly different from NAN's. `Napi::ObjectWrap` takes a pointer to the wrapped object and creates a reference to the wrapped object inside ObjectWrap constructor. `Napi::ObjectWrap` also associates wrapped object's instance methods to Javascript module instead of static methods like NAN. So if you use Nan::ObjectWrap in your module, you will need to execute the following steps. 1. Convert your [ClassName]::New function to a constructor function that takes a `Napi::CallbackInfo`. Declare it as ``` [ClassName](const Napi::CallbackInfo& info); ``` and define it as ``` [ClassName]::[ClassName](const Napi::CallbackInfo& info) : Napi::ObjectWrap<[ClassName]>(info){ ... } ``` This way, the `Napi::ObjectWrap` constructor will be invoked after the object has been instantiated and `Napi::ObjectWrap` can use the `this` pointer to create a reference to the wrapped object. 2. Move your original constructor code into the new constructor. Delete your original constructor. 3. In your class initialization function, associate native methods in the following way. ``` Napi::FunctionReference constructor; void [ClassName]::Init(Napi::Env env, Napi::Object exports, Napi::Object module) { Napi::HandleScope scope(env); Napi::Function ctor = DefineClass(env, "Canvas", { InstanceMethod<&[ClassName]::Func1>("Func1"), InstanceMethod<&[ClassName]::Func2>("Func2"), InstanceAccessor<&[ClassName]::ValueGetter>("Value"), StaticMethod<&[ClassName]::StaticMethod>("MethodName"), InstanceValue("Value", Napi::[Type]::New(env, value)), }); constructor = Napi::Persistent(ctor); constructor .SuppressDestruct(); exports.Set("[ClassName]", ctor); } ``` 4. In function where you need to Unwrap the ObjectWrap in NAN like `[ClassName]* native = Nan::ObjectWrap::Unwrap<[ClassName]>(info.This());`, use `this` pointer directly as the unwrapped object as each ObjectWrap instance is associated with a unique object instance. If you still find issues after following this guide, please leave us an issue describing your problem and we will try to resolve it. 'use strict'; // Descend into a directory structure and, for each file matching *.node, output // based on the imports found in the file whether it's an N-API module or not. const fs = require('fs'); const path = require('path'); const child_process = require('child_process'); // Read the output of the command, break it into lines, and use the reducer to // decide whether the file is an N-API module or not. function checkFile(file, command, argv, reducer) { const child = child_process.spawn(command, argv, { stdio: ['inherit', 'pipe', 'inherit'] }); let leftover = ''; let isNapi = undefined; child.stdout.on('data', (chunk) => { if (isNapi === undefined) { chunk = (leftover + chunk.toString()).split(/[\r\n]+/); leftover = chunk.pop(); isNapi = chunk.reduce(reducer, isNapi); if (isNapi !== undefined) { child.kill(); } } }); child.on('close', (code, signal) => { if ((code === null && signal !== null) || (code !== 0)) { console.log( command + ' exited with code: ' + code + ' and signal: ' + signal); } else { // Green if it's a N-API module, red otherwise. console.log( '\x1b[' + (isNapi ? '42' : '41') + 'm' + (isNapi ? ' N-API' : 'Not N-API') + '\x1b[0m: ' + file); } }); } // Use nm -a to list symbols. function checkFileUNIX(file) { checkFile(file, 'nm', ['-a', file], (soFar, line) => { if (soFar === undefined) { line = line.match(/([0-9a-f]*)? ([a-zA-Z]) (.*$)/); if (line[2] === 'U') { if (/^napi/.test(line[3])) { soFar = true; } } } return soFar; }); } // Use dumpbin /imports to list symbols. function checkFileWin32(file) { checkFile(file, 'dumpbin', ['/imports', file], (soFar, line) => { if (soFar === undefined) { line = line.match(/([0-9a-f]*)? +([a-zA-Z0-9]) (.*$)/); if (line && /^napi/.test(line[line.length - 1])) { soFar = true; } } return soFar; }); } // Descend into a directory structure and pass each file ending in '.node' to // one of the above checks, depending on the OS. function recurse(top) { fs.readdir(top, (error, items) => { if (error) { throw ("error reading directory " + top + ": " + error); } items.forEach((item) => { item = path.join(top, item); fs.stat(item, ((item) => (error, stats) => { if (error) { throw ("error about " + item + ": " + error); } if (stats.isDirectory()) { recurse(item); } else if (/[.]node$/.test(item) && // Explicitly ignore files called 'nothing.node' because they are // artefacts of node-addon-api having identified a version of // Node.js that ships with a correct implementation of N-API. path.basename(item) !== 'nothing.node') { process.platform === 'win32' ? checkFileWin32(item) : checkFileUNIX(item); } })(item)); }); }); } // Start with the directory given on the command line or the current directory // if nothing was given. recurse(process.argv.length > 3 ? process.argv[2] : '.'); #!/usr/bin/env node const spawn = require('child_process').spawnSync; const path = require('path'); const filesToCheck = ['*.h', '*.cc']; const CLANG_FORMAT_START = process.env.CLANG_FORMAT_START || 'master'; function main(args) { let clangFormatPath = path.dirname(require.resolve('clang-format')); const options = ['--binary=node_modules/.bin/clang-format', '--style=file']; const gitClangFormatPath = path.join(clangFormatPath, 'bin/git-clang-format'); const result = spawn('python', [ gitClangFormatPath, ...options, '--diff', CLANG_FORMAT_START, 'HEAD', ...filesToCheck ], { encoding: 'utf-8' }); if (result.error) { console.error('Error running git-clang-format:', result.error); return 2; } const clangFormatOutput = result.stdout.trim(); if (clangFormatOutput !== '' && clangFormatOutput !== ('no modified files to format') && clangFormatOutput !== ('clang-format did not modify any files')) { console.error(clangFormatOutput); const fixCmd = '"npm run lint:fix"'; console.error(` ERROR: please run ${fixCmd} to format changes in your commit Note that when running the command locally, please keep your local master branch and working branch up to date with nodejs/node-addon-api to exclude un-related complains. Or you can run "env CLANG_FORMAT_START=upstream/master ${fixCmd}".`); return 1; } } if (require.main === module) { process.exitCode = main(process.argv.slice(2)); } #! /usr/bin/env node 'use strict' const fs = require('fs'); const path = require('path'); const args = process.argv.slice(2); const dir = args[0]; if (!dir) { console.log('Usage: node ' + path.basename(__filename) + ' '); process.exit(1); } const NodeApiVersion = require('../package.json').version; const disable = args[1]; if (disable != "--disable" && dir != "--disable") { var ConfigFileOperations = { 'package.json': [ [ /([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'], [ /[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '' ] ], 'binding.gyp': [ [ /([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ], [ /Local\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);\s+(\w+)\.Reset\((\1)\);\s+\1->SetClassName\((Nan::String::New|Nan::New<(v8::)*String>)\("(.+?)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$6", {'], [ /Local\s+(\w+)\s*=\s*Nan::New\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ], [ /Nan::New\(([\w\d:]+)\)->GetFunction\(\)/g, 'Napi::Function::New(env, $1)' ], [ /Nan::New\(([\w\d:]+)\)->GetFunction()/g, 'Napi::Function::New(env, $1);' ], [ /Nan::New\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ], [ /Nan::New\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ], // FunctionTemplate to FunctionReference [ /Nan::Persistent<(v8::)*FunctionTemplate>/g, 'Napi::FunctionReference' ], [ /Nan::Persistent<(v8::)*Function>/g, 'Napi::FunctionReference' ], [ /v8::Local/g, 'Napi::FunctionReference' ], [ /Local/g, 'Napi::FunctionReference' ], [ /v8::FunctionTemplate/g, 'Napi::FunctionReference' ], [ /FunctionTemplate/g, 'Napi::FunctionReference' ], [ /([ ]*)Nan::SetPrototypeMethod\(\w+, "(\w+)", (\w+)\);/g, '$1InstanceMethod("$2", &$3),' ], [ /([ ]*)(?:\w+\.Reset\(\w+\);\s+)?\(target\)\.Set\("(\w+)",\s*Nan::GetFunction\((\w+)\)\);/gm, '});\n\n' + '$1constructor = Napi::Persistent($3);\n' + '$1constructor.SuppressDestruct();\n' + '$1target.Set("$2", $3);' ], // TODO: Other attribute combinations [ /static_cast\(ReadOnly\s*\|\s*DontDelete\)/gm, 'static_cast(napi_enumerable | napi_configurable)' ], [ /([\w\d:<>]+?)::Cast\((.+?)\)/g, '$2.As<$1>()' ], [ /\*Nan::Utf8String\(([^)]+)\)/g, '$1->As().Utf8Value().c_str()' ], [ /Nan::Utf8String +(\w+)\(([^)]+)\)/g, 'std::string $1 = $2.As()' ], [ /Nan::Utf8String/g, 'std::string' ], [ /v8::String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ], [ /String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ], [ /\.length\(\)/g, '.Length()' ], [ /Nan::MakeCallback\(([^,]+),[\s\\]+([^,]+),/gm, '$2.MakeCallback($1,' ], [ /class\s+(\w+)\s*:\s*public\s+Nan::ObjectWrap/g, 'class $1 : public Napi::ObjectWrap<$1>' ], [ /(\w+)\(([^\)]*)\)\s*:\s*Nan::ObjectWrap\(\)\s*(,)?/gm, '$1($2) : Napi::ObjectWrap<$1>()$3' ], // HandleOKCallback to OnOK [ /HandleOKCallback/g, 'OnOK' ], // HandleErrorCallback to OnError [ /HandleErrorCallback/g, 'OnError' ], // ex. .As() to .As() [ /\.As\(\)/g, '.As()' ], [ /\.As<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As()' ], // ex. Nan::New(info[0]) to Napi::Number::New(info[0]) [ /Nan::New<(v8::)*Integer>\((.+?)\)/g, 'Napi::Number::New(env, $2)' ], [ /Nan::New\(([0-9\.]+)\)/g, 'Napi::Number::New(env, $1)' ], [ /Nan::New<(v8::)*String>\("(.+?)"\)/g, 'Napi::String::New(env, "$2")' ], [ /Nan::New\("(.+?)"\)/g, 'Napi::String::New(env, "$1")' ], [ /Nan::New<(v8::)*(.+?)>\(\)/g, 'Napi::$2::New(env)' ], [ /Nan::New<(.+?)>\(\)/g, 'Napi::$1::New(env)' ], [ /Nan::New<(v8::)*(.+?)>\(/g, 'Napi::$2::New(env, ' ], [ /Nan::New<(.+?)>\(/g, 'Napi::$1::New(env, ' ], [ /Nan::NewBuffer\(/g, 'Napi::Buffer::New(env, ' ], // TODO: Properly handle this [ /Nan::New\(/g, 'Napi::New(env, ' ], [ /\.IsInt32\(\)/g, '.IsNumber()' ], [ /->IsInt32\(\)/g, '.IsNumber()' ], [ /(.+?)->BooleanValue\(\)/g, '$1.As().Value()' ], [ /(.+?)->Int32Value\(\)/g, '$1.As().Int32Value()' ], [ /(.+?)->Uint32Value\(\)/g, '$1.As().Uint32Value()' ], [ /(.+?)->IntegerValue\(\)/g, '$1.As().Int64Value()' ], [ /(.+?)->NumberValue\(\)/g, '$1.As().DoubleValue()' ], // ex. Nan::To(info[0]) to info[0].Value() [ /Nan::To\((.+?)\)/g, '$2.To()' ], [ /Nan::To<(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To()' ], // ex. Nan::To(info[0]) to info[0].As().Value() [ /Nan::To\((.+?)\)/g, '$1.As().Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Uint32Value() [ /Nan::To\((.+?)\)/g, '$1.As().Uint32Value()' ], // ex. Nan::To(info[0]) to info[0].As().Int64Value() [ /Nan::To\((.+?)\)/g, '$1.As().Int64Value()' ], // ex. Nan::To(info[0]) to info[0].As().FloatValue() [ /Nan::To\((.+?)\)/g, '$1.As().FloatValue()' ], // ex. Nan::To(info[0]) to info[0].As().DoubleValue() [ /Nan::To\((.+?)\)/g, '$1.As().DoubleValue()' ], [ /Nan::New\((\w+)\)->HasInstance\((\w+)\)/g, '$2.InstanceOf($1.Value())' ], [ /Nan::Has\(([^,]+),\s*/gm, '($1).Has(' ], [ /\.Has\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Has($1)' ], [ /\.Has\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Has($1)' ], [ /Nan::Get\(([^,]+),\s*/gm, '($1).Get(' ], [ /\.Get\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Get($1)' ], [ /\.Get\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Get($1)' ], [ /Nan::Set\(([^,]+),\s*/gm, '($1).Set(' ], [ /\.Set\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\s*,/gm, '.Set($1,' ], [ /\.Set\([\s|\\]*Nan::New\(([^)]+)\)\s*,/gm, '.Set($1,' ], // ex. node::Buffer::HasInstance(info[0]) to info[0].IsBuffer() [ /node::Buffer::HasInstance\((.+?)\)/g, '$1.IsBuffer()' ], // ex. node::Buffer::Length(info[0]) to info[0].Length() [ /node::Buffer::Length\((.+?)\)/g, '$1.As>().Length()' ], // ex. node::Buffer::Data(info[0]) to info[0].Data() [ /node::Buffer::Data\((.+?)\)/g, '$1.As>().Data()' ], [ /Nan::CopyBuffer\(/g, 'Napi::Buffer::Copy(env, ' ], // Nan::AsyncQueueWorker(worker) [ /Nan::AsyncQueueWorker\((.+)\);/g, '$1.Queue();' ], [ /Nan::(Undefined|Null|True|False)\(\)/g, 'env.$1()' ], // Nan::ThrowError(error) to Napi::Error::New(env, error).ThrowAsJavaScriptException() [ /([ ]*)return Nan::Throw(\w*?)Error\((.+?)\);/g, '$1Napi::$2Error::New(env, $3).ThrowAsJavaScriptException();\n$1return env.Null();' ], [ /Nan::Throw(\w*?)Error\((.+?)\);\n(\s*)return;/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n$3return env.Null();' ], [ /Nan::Throw(\w*?)Error\((.+?)\);/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n' ], // Nan::RangeError(error) to Napi::RangeError::New(env, error) [ /Nan::(\w*?)Error\((.+)\)/g, 'Napi::$1Error::New(env, $2)' ], [ /Nan::Set\((.+?),\n* *(.+?),\n* *(.+?),\n* *(.+?)\)/g, '$1.Set($2, $3, $4)' ], [ /Nan::(Escapable)?HandleScope\s+(\w+)\s*;/g, 'Napi::$1HandleScope $2(env);' ], [ /Nan::(Escapable)?HandleScope/g, 'Napi::$1HandleScope' ], [ /Nan::ForceSet\(([^,]+), ?/g, '$1->DefineProperty(' ], [ /\.ForceSet\(Napi::String::New\(env, "(\w+)"\),\s*?/g, '.DefineProperty("$1", ' ], // [ /Nan::GetPropertyNames\(([^,]+)\)/, '$1->GetPropertyNames()' ], [ /Nan::Equals\(([^,]+),/g, '$1.StrictEquals(' ], [ /(.+)->Set\(/g, '$1.Set\(' ], [ /Nan::Callback/g, 'Napi::FunctionReference' ], [ /Nan::Persistent/g, 'Napi::ObjectReference' ], [ /Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target/g, 'Napi::Env& env, Napi::Object& target' ], [ /(\w+)\*\s+(\w+)\s*=\s*Nan::ObjectWrap::Unwrap<\w+>\(info\.This\(\)\);/g, '$1* $2 = this;' ], [ /Nan::ObjectWrap::Unwrap<(\w+)>\((.*)\);/g, '$2.Unwrap<$1>();' ], [ /Nan::NAN_METHOD_RETURN_TYPE/g, 'void' ], [ /NAN_INLINE/g, 'inline' ], [ /Nan::NAN_METHOD_ARGS_TYPE/g, 'const Napi::CallbackInfo&' ], [ /NAN_METHOD\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'], [ /static\s*NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ], [ /NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ], [ /static\s*NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ], [ /NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ], [ /void Init\((v8::)*Local<(v8::)*Object> exports\)/g, 'Napi::Object Init(Napi::Env env, Napi::Object exports)' ], [ /NAN_MODULE_INIT\(([\w\d:]+?)\);/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports);' ], [ /NAN_MODULE_INIT\(([\w\d:]+?)\)/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports)' ], [ /::(Init(?:ialize)?)\(target\)/g, '::$1(env, target, module)' ], [ /constructor_template/g, 'constructor' ], [ /Nan::FunctionCallbackInfo<(v8::)?Value>[ ]*& [ ]*info\)[ ]*{\n*([ ]*)/gm, 'Napi::CallbackInfo& info) {\n$2Napi::Env env = info.Env();\n$2' ], [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&\s*info\);/g, 'Napi::CallbackInfo& info);' ], [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&/g, 'Napi::CallbackInfo&' ], [ /Buffer::HasInstance\(([^)]+)\)/g, '$1.IsBuffer()' ], [ /info\[(\d+)\]->/g, 'info[$1].' ], [ /info\[([\w\d]+)\]->/g, 'info[$1].' ], [ /info\.This\(\)->/g, 'info.This().' ], [ /->Is(Object|String|Int32|Number)\(\)/g, '.Is$1()' ], [ /info.GetReturnValue\(\).SetUndefined\(\)/g, 'return env.Undefined()' ], [ /info\.GetReturnValue\(\)\.Set\(((\n|.)+?)\);/g, 'return $1;' ], // ex. Local to Napi::Value [ /v8::Local/g, 'Napi::$1' ], [ /Local<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1' ], // Declare an env in helper functions that take a Napi::Value [ /(\w+)\(Napi::Value (\w+)(,\s*[^\()]+)?\)\s*{\n*([ ]*)/gm, '$1(Napi::Value $2$3) {\n$4Napi::Env env = $2.Env();\n$4' ], // delete #include and/or [ /#include +(<|")(?:node|nan).h("|>)/g, "#include $1napi.h$2\n#include $1uv.h$2" ], // NODE_MODULE to NODE_API_MODULE [ /NODE_MODULE/g, 'NODE_API_MODULE' ], [ /Nan::/g, 'Napi::' ], [ /nan.h/g, 'napi.h' ], // delete .FromJust() [ /\.FromJust\(\)/g, '' ], // delete .ToLocalCheck() [ /\.ToLocalChecked\(\)/g, '' ], [ /^.*->SetInternalFieldCount\(.*$/gm, '' ], // replace using node; and/or using v8; to using Napi; [ /using (node|v8);/g, 'using Napi;' ], [ /using namespace (node|Nan|v8);/g, 'using namespace Napi;' ], // delete using v8::Local; [ /using v8::Local;\n/g, '' ], // replace using v8::XXX; with using Napi::XXX [ /using v8::([A-Za-z]+);/g, 'using Napi::$1;' ], ]; var paths = listFiles(dir); paths.forEach(function(dirEntry) { var filename = dirEntry.split('\\').pop().split('/').pop(); // Check whether the file is a source file or a config file // then execute function accordingly var sourcePattern = /.+\.h|.+\.cc|.+\.cpp/; if (sourcePattern.test(filename)) { convertFile(dirEntry, SourceFileOperations); } else if (ConfigFileOperations[filename] != null) { convertFile(dirEntry, ConfigFileOperations[filename]); } }); function listFiles(dir, filelist) { var files = fs.readdirSync(dir); filelist = filelist || []; files.forEach(function(file) { if (file === 'node_modules') { return } if (fs.statSync(path.join(dir, file)).isDirectory()) { filelist = listFiles(path.join(dir, file), filelist); } else { filelist.push(path.join(dir, file)); } }); return filelist; } function convert(content, operations) { for (let i = 0; i < operations.length; i ++) { let operation = operations[i]; content = content.replace(operation[0], operation[1]); } return content; } function convertFile(fileName, operations) { fs.readFile(fileName, "utf-8", function (err, file) { if (err) throw err; file = convert(file, operations); fs.writeFile(fileName, file, function(err){ if (err) throw err; }); }); } # Add-on Structure Class `Napi::Addon` inherits from class [`Napi::InstanceWrap`][]. Creating add-ons that work correctly when loaded multiple times from the same source package into multiple Node.js threads and/or multiple times into the same Node.js thread requires that all global data they hold be associated with the environment in which they run. It is not safe to store global data in static variables because doing so does not take into account the fact that an add-on may be loaded into multiple threads nor that an add-on may be loaded multiple times into a single thread. The `Napi::Addon` class can be used to define an entire add-on. Instances of `Napi::Addon` subclasses become instances of the add-on, stored safely by Node.js on its various threads and into its various contexts. Thus, any data stored in the instance variables of a `Napi::Addon` subclass instance are stored safely by Node.js. Functions exposed to JavaScript using `Napi::Addon::InstanceMethod` and/or `Napi::Addon::DefineAddon` are instance methods of the `Napi::Addon` subclass and thus have access to data stored inside the instance. `Napi::Addon::DefineProperties` may be used to attach `Napi::Addon` subclass instance methods to objects other than the one that will be returned to Node.js as the add-on instance. The `Napi::Addon` class can be used together with the `NODE_API_ADDON()` and `NODE_API_NAMED_ADDON()` macros to define add-ons. ## Example ```cpp #include class ExampleAddon : public Napi::Addon { public: ExampleAddon(Napi::Env env, Napi::Object exports) { // In the constructor we declare the functions the add-on makes available // to JavaScript. DefineAddon(exports, { InstanceMethod("increment", &ExampleAddon::Increment), // We can also attach plain objects to `exports`, and instance methods as // properties of those sub-objects. InstanceValue("subObject", DefineProperties(Napi::Object::New(env), { InstanceMethod("decrement", &ExampleAddon::Decrement) }), napi_enumerable) }); } private: // This method has access to the data stored in the environment because it is // an instance method of `ExampleAddon` and because it was listed among the // property descriptors passed to `DefineAddon()` in the constructor. Napi::Value Increment(const Napi::CallbackInfo& info) { return Napi::Number::New(info.Env(), ++value); } // This method has access to the data stored in the environment because it is // an instance method of `ExampleAddon` and because it was exposed to // JavaScript by calling `DefineProperties()` with the object onto which it is // attached. Napi::Value Decrement(const Napi::CallbackInfo& info) { return Napi::Number::New(info.Env(), --value); } // Data stored in these variables is unique to each instance of the add-on. uint32_t value = 42; }; // The macro announces that instances of the class `ExampleAddon` will be // created for each instance of the add-on that must be loaded into Node.js. NODE_API_ADDON(ExampleAddon) ``` The above code can be used from JavaScript as follows: ```js 'use strict' const exampleAddon = require('bindings')('example_addon'); console.log(exampleAddon.increment()); // prints 43 console.log(exampleAddon.increment()); // prints 44 console.log(exampleAddon.subObject.decrement()); // prints 43 ``` When Node.js loads an instance of the add-on, a new instance of the class is created. Its constructor receives the environment `Napi::Env env` and the exports object `Napi::Object exports`. It can then use the method `DefineAddon` to either attach methods, accessors, and/or values to the `exports` object or to create its own `exports` object and attach methods, accessors, and/or values to it. Functions created with `Napi::Function::New()`, accessors created with `PropertyDescriptor::Accessor()`, and values can also be attached. If their implementation requires the `ExampleAddon` instance, it can be retrieved from the `Napi::Env env` with `GetInstanceData()`: ```cpp void ExampleBinding(const Napi::CallbackInfo& info) { ExampleAddon* addon = info.Env().GetInstanceData(); } ``` ## Methods ### Constructor Creates a new instance of the add-on. ```cpp Napi::Addon(Napi::Env env, Napi::Object exports); ``` - `[in] env`: The environment into which the add-on is being loaded. - `[in] exports`: The exports object received from JavaScript. Typically, the constructor calls `DefineAddon()` to attach methods, accessors, and/or values to `exports`. The constructor may also create a new object and pass it to `DefineAddon()` as its first parameter if it wishes to replace the `exports` object as provided by Node.js. ### DefineAddon Defines an add-on instance with functions, accessors, and/or values. ```cpp template void Napi::Addon::DefineAddon(Napi::Object exports, const std::initializer_list& properties); ``` * `[in] exports`: The object to return to Node.js as an instance of the add-on. * `[in] properties`: Initializer list of add-on property descriptors of the methods, property accessors, and values that define the add-on. They will be set on `exports`. See: [`Class property and descriptor`](class_property_descriptor.md). ### DefineProperties Defines function, accessor, and/or value properties on an object using add-on instance methods. ```cpp template Napi::Object Napi::Addon::DefineProperties(Napi::Object object, const std::initializer_list& properties); ``` * `[in] object`: The object that will receive the new properties. * `[in] properties`: Initializer list of property descriptors of the methods, property accessors, and values to attach to `object`. See: [`Class property and descriptor`](class_property_descriptor.md). Returns `object`. [`Napi::InstanceWrap`]: ./instance_wrap.md # Array Class [`Napi::Array`][] inherits from class [`Napi::Object`][]. Arrays are native representations of JavaScript Arrays. `Napi::Array` is a wrapper around `napi_value` representing a JavaScript Array. [`Napi::TypedArray`][] and [`Napi::ArrayBuffer`][] correspond to JavaScript data types such as [`Napi::Int32Array`][] and [`Napi::ArrayBuffer`][], respectively, that can be used for transferring large amounts of data from JavaScript to the native side. An example illustrating the use of a JavaScript-provided `ArrayBuffer` in native code is available [here](https://github.com/nodejs/node-addon-examples/tree/master/array_buffer_to_native/node-addon-api). ## Constructor ```cpp Napi::Array::Array(); ``` Returns an empty array. If an error occurs, a `Napi::Error` will be thrown. If C++ exceptions are not being used, callers should check the result of `Env::IsExceptionPending` before attempting to use the returned value. ```cpp Napi::Array::Array(napi_env env, napi_value value); ``` - `[in] env` - The environment in which to create the array. - `[in] value` - The primitive to wrap. Returns a `Napi::Array` wrapping a `napi_value`. If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not being used, callers should check the result of `Env::IsExceptionPending` before attempting to use the returned value. ## Methods ### New ```cpp static Napi::Array Napi::Array::New(napi_env env); ``` - `[in] env` - The environment in which to create the array. Returns a new `Napi::Array`. If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not being used, callers should check the result of `Env::IsExceptionPending` before attempting to use the returned value. ### New ```cpp static Napi::Array Napi::Array::New(napi_env env, size_t length); ``` - `[in] env` - The environment in which to create the array. - `[in] length` - The length of the array. Returns a new `Napi::Array` with the given length. If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not being used, callers should check the result of `Env::IsExceptionPending` before attempting to use the returned value. ### Length ```cpp uint32_t Napi::Array::Length() const; ``` Returns the length of the array. Note: This can execute JavaScript code implicitly according to JavaScript semantics. If an error occurs, a `Napi::Error` will get thrown. If C++ exceptions are not being used, callers should check the result of `Env::IsExceptionPending` before attempting to use the returned value. [`Napi::ArrayBuffer`]: ./array_buffer.md [`Napi::Int32Array`]: ./typed_array_of.md [`Napi::Object`]: ./object.md [`Napi::TypedArray`]: ./typed_array.md # ArrayBuffer Class `Napi::ArrayBuffer` inherits from class [`Napi::Object`][]. The `Napi::ArrayBuffer` class corresponds to the [JavaScript `ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) class. ## Methods ### New Allocates a new `Napi::ArrayBuffer` instance with a given length. ```cpp static Napi::ArrayBuffer Napi::ArrayBuffer::New(napi_env env, size_t byteLength); ``` - `[in] env`: The environment in which to create the `Napi::ArrayBuffer` instance. - `[in] byteLength`: The length to be allocated, in bytes. Returns a new `Napi::ArrayBuffer` instance. ### New Wraps the provided external data into a new `Napi::ArrayBuffer` instance. The `Napi::ArrayBuffer` instance does not assume ownership for the data and expects it to be valid for the lifetime of the instance. Since the `Napi::ArrayBuffer` is subject to garbage collection this overload is only suitable for data which is static and never needs to be freed. ```cpp static Napi::ArrayBuffer Napi::ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength); ``` - `[in] env`: The environment in which to create the `Napi::ArrayBuffer` instance. - `[in] externalData`: The pointer to the external data to wrap. - `[in] byteLength`: The length of the `externalData`, in bytes. Returns a new `Napi::ArrayBuffer` instance. ### New Wraps the provided external data into a new `Napi::ArrayBuffer` instance. The `Napi::ArrayBuffer` instance does not assume ownership for the data and expects it to be valid for the lifetime of the instance. The data can only be freed once the `finalizeCallback` is invoked to indicate that the `Napi::ArrayBuffer` has been released. ```cpp template static Napi::ArrayBuffer Napi::ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength, Finalizer finalizeCallback); ``` - `[in] env`: The environment in which to create the `Napi::ArrayBuffer` instance. - `[in] externalData`: The pointer to the external data to wrap. - `[in] byteLength`: The length of the `externalData`, in bytes. - `[in] finalizeCallback`: A function to be called when the `Napi::ArrayBuffer` is destroyed. It must implement `operator()`, accept a `void*` (which is the `externalData` pointer), and return `void`. Returns a new `Napi::ArrayBuffer` instance. ### New Wraps the provided external data into a new `Napi::ArrayBuffer` instance. The `Napi::ArrayBuffer` instance does not assume ownership for the data and expects it to be valid for the lifetime of the instance. The data can only be freed once the `finalizeCallback` is invoked to indicate that the `Napi::ArrayBuffer` has been released. ```cpp template static Napi::ArrayBuffer Napi::ArrayBuffer::New(napi_env env, void* externalData, size_t byteLength, Finalizer finalizeCallback, Hint* finalizeHint); ``` - `[in] env`: The environment in which to create the `Napi::ArrayBuffer` instance. - `[in] externalData`: The pointer to the external data to wrap. - `[in] byteLength`: The length of the `externalData`, in bytes. - `[in] finalizeCallback`: The function to be called when the `Napi::ArrayBuffer` is destroyed. It must implement `operator()`, accept a `void*` (which is the `externalData` pointer) and `Hint*`, and return `void`. - `[in] finalizeHint`: The hint to be passed as the second parameter of the finalize callback. Returns a new `Napi::ArrayBuffer` instance. ### Constructor Initializes an empty instance of the `Napi::ArrayBuffer` class. ```cpp Napi::ArrayBuffer::ArrayBuffer(); ``` ### Constructor Initializes a wrapper instance of an existing `Napi::ArrayBuffer` object. ```cpp Napi::ArrayBuffer::ArrayBuffer(napi_env env, napi_value value); ``` - `[in] env`: The environment in which to create the `Napi::ArrayBuffer` instance. - `[in] value`: The `Napi::ArrayBuffer` reference to wrap. ### ByteLength ```cpp size_t Napi::ArrayBuffer::ByteLength() const; ``` Returns the length of the wrapped data, in bytes. ### Data ```cpp void* Napi::ArrayBuffer::Data() const; ``` Returns a pointer the wrapped data. ### Detach ```cpp void Napi::ArrayBuffer::Detach(); ``` Invokes the `ArrayBuffer` detach operation on a detachable `ArrayBuffer`. ### IsDetached ```cpp bool Napi::ArrayBuffer::IsDetached() const; ``` Returns `true` if this `ArrayBuffer` has been detached. [`Napi::Object`]: ./object.md # AsyncContext The [Napi::AsyncWorker](async_worker.md) class may not be appropriate for every scenario. When using any other async mechanism, introducing a new class `Napi::AsyncContext` is necessary to ensure an async operation is properly tracked by the runtime. The `Napi::AsyncContext` class can be passed to [Napi::Function::MakeCallback()](function.md) method to properly restore the correct async execution context. ## Methods ### Constructor Creates a new `Napi::AsyncContext`. ```cpp explicit Napi::AsyncContext::AsyncContext(napi_env env, const char* resource_name); ``` - `[in] env`: The environment in which to create the `Napi::AsyncContext`. - `[in] resource_name`: Null-terminated strings that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the `async_hooks` API. ### Constructor Creates a new `Napi::AsyncContext`. ```cpp explicit Napi::AsyncContext::AsyncContext(napi_env env, const char* resource_name, const Napi::Object& resource); ``` - `[in] env`: The environment in which to create the `Napi::AsyncContext`. - `[in] resource_name`: Null-terminated strings that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the `async_hooks` API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible `async_hooks`. ### Destructor The `Napi::AsyncContext` to be destroyed. ```cpp virtual Napi::AsyncContext::~AsyncContext(); ``` ### Env Requests the environment in which the async context has been initially created. ```cpp Napi::Env Env() const; ``` Returns the `Napi::Env` environment in which the async context has been created. ## Operator ```cpp Napi::AsyncContext::operator napi_async_context() const; ``` Returns the N-API `napi_async_context` wrapped by the `Napi::AsyncContext` object. This can be used to mix usage of the C N-API and node-addon-api. ## Example ```cpp #include "napi.h" void MakeCallbackWithAsyncContext(const Napi::CallbackInfo& info) { Napi::Function callback = info[0].As(); Napi::Object resource = info[1].As(); // Create a new async context instance. Napi::AsyncContext context(info.Env(), "async_context_test", resource); // Invoke the callback with the async context instance. callback.MakeCallback(Napi::Object::New(info.Env()), std::initializer_list{}, context); // The async context instance is automatically destroyed here because it's // block-scope like `Napi::HandleScope`. } ``` # Asynchronous operations Node.js native add-ons often need to execute long running tasks and to avoid blocking the **event loop** they have to run them asynchronously from the **event loop**. In the Node.js model of execution the event loop thread represents the thread where JavaScript code is executing. The Node.js guidance is to avoid blocking other work queued on the event loop thread. Therefore, we need to do this work on another thread. All this means that native add-ons need to leverage async helpers from libuv as part of their implementation. This allows them to schedule work to be executed asynchronously so that their methods can return in advance of the work being completed. Node Addon API provides an interface to support functions that cover the most common asynchronous use cases. There is an abstract classes to implement asynchronous operations: - **[`Napi::AsyncWorker`](async_worker.md)** These class helps manage asynchronous operations through an abstraction of the concept of moving data between the **event loop** and **worker threads**. Also, the above class may not be appropriate for every scenario. When using any other asynchronous mechanism, the following API is necessary to ensure an asynchronous operation is properly tracked by the runtime: - **[AsyncContext](async_context.md)** - **[CallbackScope](callback_scope.md)** # AsyncWorker `Napi::AsyncWorker` is an abstract class that you can subclass to remove many of the tedious tasks of moving data between the event loop and worker threads. This class internally handles all the details of creating and executing an asynchronous operation. Once created, execution is requested by calling `Napi::AsyncWorker::Queue`. When a thread is available for execution the `Napi::AsyncWorker::Execute` method will be invoked. Once `Napi::AsyncWorker::Execute` completes either `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` will be invoked. Once the `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` methods are complete the `Napi::AsyncWorker` instance is destructed. For the most basic use, only the `Napi::AsyncWorker::Execute` method must be implemented in a subclass. ## Methods ### Env Requests the environment in which the async worker has been initially created. ```cpp Napi::Env Napi::AsyncWorker::Env() const; ``` Returns the environment in which the async worker has been created. ### Queue Requests that the work be queued for execution. ```cpp void Napi::AsyncWorker::Queue(); ``` ### Cancel Cancels queued work if it has not yet been started. If it has already started executing, it cannot be cancelled. If cancelled successfully neither `OnOK` nor `OnError` will be called. ```cpp void Napi::AsyncWorker::Cancel(); ``` ### Receiver ```cpp Napi::ObjectReference& Napi::AsyncWorker::Receiver(); ``` Returns the persistent object reference of the receiver object set when the async worker was created. ### Callback ```cpp Napi::FunctionReference& Napi::AsyncWorker::Callback(); ``` Returns the persistent function reference of the callback set when the async worker was created. The returned function reference will receive the results of the computation that happened in the `Napi::AsyncWorker::Execute` method, unless the default implementation of `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` is overridden. ### SuppressDestruct ```cpp void Napi::AsyncWorker::SuppressDestruct(); ``` Prevents the destruction of the `Napi::AsyncWorker` instance upon completion of the `Napi::AsyncWorker::OnOK` callback. ### SetError Sets the error message for the error that happened during the execution. Setting an error message will cause the `Napi::AsyncWorker::OnError` method to be invoked instead of `Napi::AsyncWorker::OnOK` once the `Napi::AsyncWorker::Execute` method completes. ```cpp void Napi::AsyncWorker::SetError(const std::string& error); ``` - `[in] error`: The reference to the string that represent the message of the error. ### Execute This method is used to execute some tasks outside of the **event loop** on a libuv worker thread. Subclasses must implement this method and the method is run on a thread other than that running the main event loop. As the method is not running on the main event loop, it must avoid calling any methods from node-addon-api or running any code that might invoke JavaScript. Instead, once this method is complete any interaction through node-addon-api with JavaScript should be implemented in the `Napi::AsyncWorker::OnOK` method and `Napi::AsyncWorker::OnError` which run on the main thread and are invoked when the `Napi::AsyncWorker::Execute` method completes. ```cpp virtual void Napi::AsyncWorker::Execute() = 0; ``` ### OnOK This method is invoked when the computation in the `Execute` method ends. The default implementation runs the `Callback` optionally provided when the `AsyncWorker` class was created. The `Callback` will by default receive no arguments. The arguments to the `Callback` can be provided by overriding the `GetResult()` method. ```cpp virtual void Napi::AsyncWorker::OnOK(); ``` ### GetResult This method returns the arguments passed to the `Callback` invoked by the default `OnOK()` implementation. The default implementation returns an empty vector, providing no arguments to the `Callback`. ```cpp virtual std::vector Napi::AsyncWorker::GetResult(Napi::Env env); ``` ### OnError This method is invoked after `Napi::AsyncWorker::Execute` completes if an error occurs while `Napi::AsyncWorker::Execute` is running and C++ exceptions are enabled or if an error was set through a call to `Napi::AsyncWorker::SetError`. The default implementation calls the `Callback` provided when the `Napi::AsyncWorker` class was created, passing in the error as the first parameter. ```cpp virtual void Napi::AsyncWorker::OnError(const Napi::Error& e); ``` ### OnWorkComplete This method is invoked after the work has completed on JavaScript thread. The default implementation of this method checks the status of the work and tries to dispatch the result to `Napi::AsyncWorker::OnOk` or `Napi::AsyncWorker::Error` if the work has committed an error. If the work was cancelled, neither `Napi::AsyncWorker::OnOk` nor `Napi::AsyncWorker::Error` will be invoked. After the result is dispatched, the default implementation will call into `Napi::AsyncWorker::Destroy` if `SuppressDestruct()` was not called. ```cpp virtual void OnWorkComplete(Napi::Env env, napi_status status); ``` ### OnExecute This method is invoked immediately on the work thread when scheduled. The default implementation of this method just calls the `Napi::AsyncWorker::Execute` and handles exceptions if cpp exceptions were enabled. The `OnExecute` method receives an `napi_env` argument. However, the `napi_env` must NOT be used within this method, as it does not run on the JavaScript thread and must not run any method that would cause JavaScript to run. In practice, this means that almost any use of `napi_env` will be incorrect. ```cpp virtual void OnExecute(Napi::Env env); ``` ### Destroy This method is invoked when the instance must be deallocated. If `SuppressDestruct()` was not called then this method will be called after either `OnError()` or `OnOK()` complete. The default implementation of this method causes the instance to delete itself using the `delete` operator. The method is provided so as to ensure that instances allocated by means other than the `new` operator can be deallocated upon work completion. ```cpp virtual void Napi::AsyncWorker::Destroy(); ``` ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Function& callback); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Function& callback, const char* resource_name); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Function& callback, const char* resource_name, const Napi::Object& resource); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& callback); ``` - `[in] receiver`: The `this` object passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& callback, const char* resource_name); ``` - `[in] receiver`: The `this` object passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncWork` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(const Napi::Object& receiver, const Napi::Function& callback, const char* resource_name, const Napi::Object& resource); ``` - `[in] receiver`: The `this` object passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncWork` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(Napi::Env env); ``` - `[in] env`: The environment in which to create the `Napi::AsyncWorker`. Returns an `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWorker::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name); ``` - `[in] env`: The environment in which to create the `Napi::AsyncWorker`. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWorker::Queue`. ### Constructor Creates a new `Napi::AsyncWorker`. ```cpp explicit Napi::AsyncWorker(Napi::Env env, const char* resource_name, const Napi::Object& resource); ``` - `[in] env`: The environment in which to create the `Napi::AsyncWorker`. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncWorker` instance which can later be queued for execution by calling `Napi::AsyncWorker::Queue`. ### Destructor Deletes the created work object that is used to execute logic asynchronously. ```cpp virtual Napi::AsyncWorker::~AsyncWorker(); ``` ## Operator ```cpp Napi::AsyncWorker::operator napi_async_work() const; ``` Returns the N-API napi_async_work wrapped by the `Napi::AsyncWorker` object. This can be used to mix usage of the C N-API and node-addon-api. ## Example The first step to use the `Napi::AsyncWorker` class is to create a new class that inherits from it and implement the `Napi::AsyncWorker::Execute` abstract method. Typically input to your worker will be saved within class' fields generally passed in through its constructor. When the `Napi::AsyncWorker::Execute` method completes without errors the `Napi::AsyncWorker::OnOK` function callback will be invoked. In this function the results of the computation will be reassembled and returned back to the initial JavaScript context. `Napi::AsyncWorker` ensures that all the code in the `Napi::AsyncWorker::Execute` function runs in the background out of the **event loop** thread and at the end the `Napi::AsyncWorker::OnOK` or `Napi::AsyncWorker::OnError` function will be called and are executed as part of the event loop. The code below shows a basic example of `Napi::AsyncWorker` the implementation: ```cpp #include #include #include using namespace Napi; class EchoWorker : public AsyncWorker { public: EchoWorker(Function& callback, std::string& echo) : AsyncWorker(callback), echo(echo) {} ~EchoWorker() {} // This code will be executed on the worker thread void Execute() override { // Need to simulate cpu heavy task std::this_thread::sleep_for(std::chrono::seconds(1)); } void OnOK() override { HandleScope scope(Env()); Callback().Call({Env().Null(), String::New(Env(), echo)}); } private: std::string echo; }; ``` The `EchoWorker`'s constructor calls the base class' constructor to pass in the callback that the `Napi::AsyncWorker` base class will store persistently. When the work on the `Napi::AsyncWorker::Execute` method is done the `Napi::AsyncWorker::OnOk` method is called and the results return back to JavaScript invoking the stored callback with its associated environment. The following code shows an example of how to create and use an `Napi::AsyncWorker`. ```cpp #include // Include EchoWorker class // .. using namespace Napi; Value Echo(const CallbackInfo& info) { // You need to validate the arguments here. Function cb = info[1].As(); std::string in = info[0].As(); EchoWorker* wk = new EchoWorker(cb, in); wk->Queue(); return info.Env().Undefined(); ``` Using the implementation of a `Napi::AsyncWorker` is straight forward. You only need to create a new instance and pass to its constructor the callback you want to execute when your asynchronous task ends and other data you need for your computation. Once created the only other action you have to do is to call the `Napi::AsyncWorker::Queue` method that will queue the created worker for execution. # AsyncProgressWorker `Napi::AsyncProgressWorker` is an abstract class which implements `Napi::AsyncWorker` while extending `Napi::AsyncWorker` internally with `Napi::ThreadSafeFunction` for moving work progress reports from worker thread(s) to event loop threads. Like `Napi::AsyncWorker`, once created, execution is requested by calling `Napi::AsyncProgressWorker::Queue`. When a thread is available for execution the `Napi::AsyncProgressWorker::Execute` method will be invoked. During the execution, `Napi::AsyncProgressWorker::ExecutionProgress::Send` can be used to indicate execution process, which will eventually invoke `Napi::AsyncProgressWorker::OnProgress` on the JavaScript thread to safely call into JavaScript. Once `Napi::AsyncProgressWorker::Execute` completes either `Napi::AsyncProgressWorker::OnOK` or `Napi::AsyncProgressWorker::OnError` will be invoked. Once the `Napi::AsyncProgressWorker::OnOK` or `Napi::AsyncProgressWorker::OnError` methods are complete the `Napi::AsyncProgressWorker` instance is destructed. For the most basic use, only the `Napi::AsyncProgressWorker::Execute` and `Napi::AsyncProgressWorker::OnProgress` method must be implemented in a subclass. ## Methods [`Napi::AsyncWorker`][] provides detailed descriptions for most methods. ### Execute This method is used to execute some tasks outside of the **event loop** on a libuv worker thread. Subclasses must implement this method and the method is run on a thread other than that running the main event loop. As the method is not running on the main event loop, it must avoid calling any methods from node-addon-api or running any code that might invoke JavaScript. Instead, once this method is complete any interaction through node-addon-api with JavaScript should be implemented in the `Napi::AsyncProgressWorker::OnOK` method and/or `Napi::AsyncProgressWorker::OnError` which run on the main thread and are invoked when the `Napi::AsyncProgressWorker::Execute` method completes. ```cpp virtual void Napi::AsyncProgressWorker::Execute(const ExecutionProgress& progress) = 0; ``` ### OnOK This method is invoked when the computation in the `Execute` method ends. The default implementation runs the `Callback` optionally provided when the `AsyncProgressWorker` class was created. The `Callback` will by default receive no arguments. Arguments to the callback can be provided by overriding the `GetResult()` method. ```cpp virtual void Napi::AsyncProgressWorker::OnOK(); ``` ### OnProgress This method is invoked when the computation in the `Napi::AsyncProgressWorker::ExecutionProcess::Send` method was called during worker thread execution. ```cpp virtual void Napi::AsyncProgressWorker::OnProgress(const T* data, size_t count) ``` ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Function& callback); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Function& callback, const char* resource_name); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Function& callback, const char* resource_name, const Napi::Object& resource); ``` - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Object& receiver, const Napi::Function& callback); ``` - `[in] receiver`: The `this` object passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Object& receiver, const Napi::Function& callback, const char* resource_name); ``` - `[in] receiver`: The `this` object passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncWork` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(const Napi::Object& receiver, const Napi::Function& callback, const char* resource_name, const Napi::Object& resource); ``` - `[in] receiver`: The `this` object to be passed to the called function. - `[in] callback`: The function which will be called when an asynchronous operations ends. The given function is called from the main event loop thread. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncWork` instance which can later be queued for execution by calling `Napi::AsyncWork::Queue`. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(Napi::Env env); ``` - `[in] env`: The environment in which to create the `Napi::AsyncProgressWorker`. Returns an `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncProgressWorker::Queue`. Available with `NAPI_VERSION` equal to or greater than 5. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(Napi::Env env, const char* resource_name); ``` - `[in] env`: The environment in which to create the `Napi::AsyncProgressWorker`. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncProgressWorker::Queue`. Available with `NAPI_VERSION` equal to or greater than 5. ### Constructor Creates a new `Napi::AsyncProgressWorker`. ```cpp explicit Napi::AsyncProgressWorker(Napi::Env env, const char* resource_name, const Napi::Object& resource); ``` - `[in] env`: The environment in which to create the `Napi::AsyncProgressWorker`. - `[in] resource_name`: Null-terminated string that represents the identifier for the kind of resource that is being provided for diagnostic information exposed by the async_hooks API. - `[in] resource`: Object associated with the asynchronous operation that will be passed to possible async_hooks. Returns a `Napi::AsyncProgressWorker` instance which can later be queued for execution by calling `Napi::AsyncProgressWorker::Queue`. Available with `NAPI_VERSION` equal to or greater than 5. ### Destructor Deletes the created work object that is used to execute logic asynchronously and release the internal `Napi::ThreadSafeFunction`, which will be aborted to prevent unexpected upcoming thread safe calls. ```cpp virtual Napi::AsyncProgressWorker::~AsyncProgressWorker(); ``` # AsyncProgressWorker::ExecutionProcess A bridge class created before the worker thread execution of `Napi::AsyncProgressWorker::Execute`. ## Methods ### Send `Napi::AsyncProgressWorker::ExecutionProcess::Send` takes two arguments, a pointer to a generic type of data, and a `size_t` to indicate how many items the pointer is pointing to. The data pointed to will be copied to internal slots of `Napi::AsyncProgressWorker` so after the call to `Napi::AsyncProgressWorker::ExecutionProcess::Send` the data can be safely released. Note that `Napi::AsyncProgressWorker::ExecutionProcess::Send` merely guarantees **eventual** invocation of `Napi::AsyncProgressWorker::OnProgress`, which means multiple send might be coalesced into single invocation of `Napi::AsyncProgressWorker::OnProgress` with latest data. If you would like to guarantee that there is one invocation of `OnProgress` for every `Send` call, you should use the `Napi::AsyncProgressQueueWorker` class instead which is documented further down this page. ```cpp void Napi::AsyncProgressWorker::ExecutionProcess::Send(const T* data, size_t count) const; ``` ## Example The first step to use the `Napi::AsyncProgressWorker` class is to create a new class that inherits from it and implement the `Napi::AsyncProgressWorker::Execute` abstract method. Typically input to the worker will be saved within the class' fields generally passed in through its constructor. During the worker thread execution, the first argument of `Napi::AsyncProgressWorker::Execute` can be used to report the progress of the execution. When the `Napi::AsyncProgressWorker::Execute` method completes without errors the `Napi::AsyncProgressWorker::OnOK` function callback will be invoked. In this function the results of the computation will be reassembled and returned back to the initial JavaScript context. `Napi::AsyncProgressWorker` ensures that all the code in the `Napi::AsyncProgressWorker::Execute` function runs in the background out of the **event loop** thread and at the end the `Napi::AsyncProgressWorker::OnOK` or `Napi::AsyncProgressWorker::OnError` function will be called and are executed as part of the event loop. The code below shows a basic example of the `Napi::AsyncProgressWorker` implementation along with an example of how the counterpart in Javascript would appear: ```cpp #include #include #include using namespace Napi; class EchoWorker : public AsyncProgressWorker { public: EchoWorker(Function& okCallback, std::string& echo) : AsyncProgressWorker(okCallback), echo(echo) {} ~EchoWorker() {} // This code will be executed on the worker thread void Execute(const ExecutionProgress& progress) { // Need to simulate cpu heavy task // Note: This Send() call is not guaranteed to trigger an equal // number of OnProgress calls (read documentation above for more info) for (uint32_t i = 0; i < 100; ++i) { progress.Send(&i, 1) } } void OnError(const Error &e) { HandleScope scope(Env()); // Pass error onto JS, no data for other parameters Callback().Call({String::New(Env(), e.Message())}); } void OnOK() { HandleScope scope(Env()); // Pass no error, give back original data Callback().Call({Env().Null(), String::New(Env(), echo)}); } void OnProgress(const uint32_t* data, size_t /* count */) { HandleScope scope(Env()); // Pass no error, no echo data, but do pass on the progress data Callback().Call({Env().Null(), Env().Null(), Number::New(Env(), *data)}); } private: std::string echo; }; ``` The `EchoWorker`'s constructor calls the base class' constructor to pass in the callback that the `Napi::AsyncProgressWorker` base class will store persistently. When the work on the `Napi::AsyncProgressWorker::Execute` method is done the `Napi::AsyncProgressWorker::OnOk` method is called and the results are return back to JavaScript when the stored callback is invoked with its associated environment. The following code shows an example of how to create and use an `Napi::AsyncProgressWorker` ```cpp #include // Include EchoWorker class // .. using namespace Napi; Value Echo(const CallbackInfo& info) { // We need to validate the arguments here std::string in = info[0].As(); Function cb = info[1].As(); EchoWorker* wk = new EchoWorker(cb, in); wk->Queue(); return info.Env().Undefined(); } // Register the native method for JS to access Object Init(Env env, Object exports) { exports.Set(String::New(env, "echo"), Function::New(env, Echo)); return exports; } // Register our native addon NODE_API_MODULE(nativeAddon, Init) ``` The implementation of a `Napi::AsyncProgressWorker` can be used by creating a new instance and passing to its constructor the callback to execute when the asynchronous task ends and other data needed for the computation. Once created, the only other action needed is to call the `Napi::AsyncProgressWorker::Queue` method that will queue the created worker for execution. Lastly, the following Javascript (ES6+) code would be associated the above example: ```js const { nativeAddon } = require('binding.node'); const exampleCallback = (errorResponse, okResponse, progressData) => { // Use the data accordingly // ... }; // Call our native addon with the paramters of a string and a function nativeAddon.echo("example", exampleCallback); ``` # AsyncProgressQueueWorker `Napi::AsyncProgressQueueWorker` acts exactly like `Napi::AsyncProgressWorker` except that each progress committed by `Napi::AsyncProgressQueueWorker::ExecutionProgress::Send` during `Napi::AsyncProgressQueueWorker::Execute` is guaranteed to be processed by `Napi::AsyncProgressQueueWorker::OnProgress` on the JavaScript thread in the order it was committed. For the most basic use, only the `Napi::AsyncProgressQueueWorker::Execute` and `Napi::AsyncProgressQueueWorker::OnProgress` method must be implemented in a subclass. # AsyncProgressQueueWorker::ExecutionProcess A bridge class created before the worker thread execution of `Napi::AsyncProgressQueueWorker::Execute`. ## Methods ### Send `Napi::AsyncProgressQueueWorker::ExecutionProcess::Send` takes two arguments, a pointer to a generic type of data, and a `size_t` to indicate how many items the pointer is pointing to. The data pointed to will be copied to internal slots of `Napi::AsyncProgressQueueWorker` so after the call to `Napi::AsyncProgressQueueWorker::ExecutionProcess::Send` the data can be safely released. `Napi::AsyncProgressQueueWorker::ExecutionProcess::Send` guarantees invocation of `Napi::AsyncProgressQueueWorker::OnProgress`, which means multiple `Send` call will result in the in-order invocation of `Napi::AsyncProgressQueueWorker::OnProgress` with each data item. ```cpp void Napi::AsyncProgressQueueWorker::ExecutionProcess::Send(const T* data, size_t count) const; ``` ## Example The code below show an example of the `Napi::AsyncProgressQueueWorker` implementation, but also demonsrates how to use multiple `Napi::Function`'s if you wish to provide multiple callback functions for more object oriented code: ```cpp #include #include #include using namespace Napi; class EchoWorker : public AsyncProgressQueueWorker { public: EchoWorker(Function& okCallback, Function& errorCallback, Function& progressCallback, std::string& echo) : AsyncProgressQueueWorker(okCallback), echo(echo) { // Set our function references to use them below this->errorCallback.Reset(errorCallback, 1); this->progressCallback.Reset(progressCallback, 1); } ~EchoWorker() {} // This code will be executed on the worker thread void Execute(const ExecutionProgress& progress) { // Need to simulate cpu heavy task to demonstrate that // every call to Send() will trigger an OnProgress function call for (uint32_t i = 0; i < 100; ++i) { progress.Send(&i, 1); } } void OnOK() { HandleScope scope(Env()); // Call our onOkCallback in javascript with the data we were given originally Callback().Call({String::New(Env(), echo)}); } void OnError(const Error &e) { HandleScope scope(Env()); // We call our callback provided in the constructor with 2 parameters if (!this->errorCallback.IsEmpty()) { // Call our onErrorCallback in javascript with the error message this->errorCallback.Call(Receiver().Value(), {String::New(Env(), e.Message())}); } } void OnProgress(const uint32_t* data, size_t /* count */) { HandleScope scope(Env()); if (!this->progressCallback.IsEmpty()) { // Call our onProgressCallback in javascript with each integer from 0 to 99 (inclusive) // as this function is triggered from the above Send() calls this->progressCallback.Call(Receiver().Value(), {Number::New(Env(), *data)}); } } private: std::string echo; FunctionReference progressCallback; FunctionReference errorCallback; }; ``` The `EchoWorker`'s constructor calls the base class' constructor to pass in the callback that the `Napi::AsyncProgressQueueWorker` base class will store persistently. When the work on the `Napi::AsyncProgressQueueWorker::Execute` method is done the `Napi::AsyncProgressQueueWorker::OnOk` method is called and the results are returned back to JavaScript when the stored callback is invoked with its associated environment. The following code shows an example of how to create and use an `Napi::AsyncProgressQueueWorker`. ```cpp #include // Include EchoWorker class // .. using namespace Napi; Value Echo(const CallbackInfo& info) { // We need to validate the arguments here. std::string in = info[0].As(); Function errorCb = info[1].As(); Function okCb = info[2].As(); Function progressCb = info[3].As(); EchoWorker* wk = new EchoWorker(okCb, errorCb, progressCb, in); wk->Queue(); return info.Env().Undefined(); } // Register the native method for JS to access Object Init(Env env, Object exports) { exports.Set(String::New(env, "echo"), Function::New(env, Echo)); return exports; } // Register our native addon NODE_API_MODULE(nativeAddon, Init) ``` The implementation of a `Napi::AsyncProgressQueueWorker` can be used by creating a new instance and passing to its constructor the callback to execute when the asynchronous task ends and other data needed for the computation. Once created, the only other action needed is to call the `Napi::AsyncProgressQueueWorker::Queue` method that will queue the created worker for execution. Lastly, the following Javascript (ES6+) code would be associated the above example: ```js const { nativeAddon } = require('binding.node'); const onErrorCallback = (msg) => { // Use the data accordingly // ... }; const onOkCallback = (echo) => { // Use the data accordingly // ... }; const onProgressCallback = (num) => { // Use the data accordingly // ... }; // Call our native addon with the paramters of a string and three callback functions nativeAddon.echo("example", onErrorCallback, onOkCallback, onProgressCallback); ``` [`Napi::AsyncWorker`]: ./async_worker.md # BigInt Class `Napi::Bigint` inherits from class [`Napi::Value`][]. A JavaScript BigInt value. ## Methods ### New ```cpp static Napi::BigInt Napi::BigInt::New(Napi::Env env, int64_t value); static Napi::BigInt Napi::BigInt::New(Napi::Env env, uint64_t value); ``` - `[in] env`: The environment in which to construct the `Napi::BigInt` object. - `[in] value`: The value the JavaScript `BigInt` will contain These APIs convert the C `int64_t` and `uint64_t` types to the JavaScript `BigInt` type. ```cpp static Napi::BigInt Napi::BigInt::New(Napi::Env env, int sign_bit, size_t word_count, const uint64_t* words); ``` - `[in] env`: The environment in which to construct the `Napi::BigInt` object. - `[in] sign_bit`: Determines if the resulting `BigInt` will be positive or negative. - `[in] word_count`: The length of the words array. - `[in] words`: An array of `uint64_t` little-endian 64-bit words. This API converts an array of unsigned 64-bit words into a single `BigInt` value. The resulting `BigInt` is calculated as: (–1)`sign_bit` (`words[0]` × (264)0 + `words[1]` × (264)1 + …) Returns a new JavaScript `BigInt`. ### Constructor ```cpp Napi::BigInt(); ``` Returns a new empty JavaScript `Napi::BigInt`. ### Int64Value ```cpp int64_t Napi::BigInt::Int64Value(bool* lossless) const; ``` - `[out] lossless`: Indicates whether the `BigInt` value was converted losslessly. Returns the C `int64_t` primitive equivalent of the given JavaScript `BigInt`. If needed it will truncate the value, setting lossless to false. ### Uint64Value ```cpp uint64_t Napi::BigInt::Uint64Value(bool* lossless) const; ``` - `[out] lossless`: Indicates whether the `BigInt` value was converted losslessly. Returns the C `uint64_t` primitive equivalent of the given JavaScript `BigInt`. If needed it will truncate the value, setting lossless to false. ### WordCount ```cpp size_t Napi::BigInt::WordCount() const; ``` Returns the number of words needed to store this `BigInt` value. ### ToWords ```cpp void Napi::BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words); ``` - `[out] sign_bit`: Integer representing if the JavaScript `BigInt` is positive or negative. - `[in/out] word_count`: Must be initialized to the length of the words array. Upon return, it will be set to the actual number of words that would be needed to store this `BigInt`. - `[out] words`: Pointer to a pre-allocated 64-bit word array. Returns a single `BigInt` value into a sign bit, 64-bit little-endian array, and the number of elements in the array. [`Napi::Value`]: ./value.md # Boolean Class `Napi::Boolean` inherits from class [`Napi::Value`][]. `Napi::Boolean` class is a representation of the JavaScript `Boolean` object. The `Napi::Boolean` class inherits its behavior from the `Napi::Value` class (for more info see: [`Napi::Value`](value.md)). ## Methods ### Constructor Creates a new empty instance of an `Napi::Boolean` object. ```cpp Napi::Boolean::Boolean(); ``` Returns a new _empty_ `Napi::Boolean` object. ### Constructor Creates a new instance of the `Napi::Boolean` object. ```cpp Napi::Boolean(napi_env env, napi_value value); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Boolean` object. - `[in] value`: The `napi_value` which is a handle for a JavaScript `Boolean`. Returns a non-empty `Napi::Boolean` object. ### New Initializes a new instance of the `Napi::Boolean` object. ```cpp Napi::Boolean Napi::Boolean::New(napi_env env, bool value); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Boolean` object. - `[in] value`: The primitive boolean value (`true` or `false`). Returns a new instance of the `Napi::Boolean` object. ### Value Converts a `Napi::Boolean` value to a boolean primitive. ```cpp bool Napi::Boolean::Value() const; ``` Returns the boolean primitive type of the corresponding `Napi::Boolean` object. ## Operators ### operator bool Converts a `Napi::Boolean` value to a boolean primitive. ```cpp Napi::Boolean::operator bool() const; ``` Returns the boolean primitive type of the corresponding `Napi::Boolean` object. [`Napi::Value`]: ./value.md # Buffer Class `Napi::Buffer` inherits from class [`Napi::Uint8Array`][]. The `Napi::Buffer` class creates a projection of raw data that can be consumed by script. ## Methods ### New Allocates a new `Napi::Buffer` object with a given length. ```cpp static Napi::Buffer Napi::Buffer::New(napi_env env, size_t length); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] length`: The number of `T` elements to allocate. Returns a new `Napi::Buffer` object. ### New Wraps the provided external data into a new `Napi::Buffer` object. The `Napi::Buffer` object does not assume ownership for the data and expects it to be valid for the lifetime of the object. Since the `Napi::Buffer` is subject to garbage collection this overload is only suitable for data which is static and never needs to be freed. ```cpp static Napi::Buffer Napi::Buffer::New(napi_env env, T* data, size_t length); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] data`: The pointer to the external data to expose. - `[in] length`: The number of `T` elements in the external data. Returns a new `Napi::Buffer` object. ### New Wraps the provided external data into a new `Napi::Buffer` object. The `Napi::Buffer` object does not assume ownership for the data and expects it to be valid for the lifetime of the object. The data can only be freed once the `finalizeCallback` is invoked to indicate that the `Napi::Buffer` has been released. ```cpp template static Napi::Buffer Napi::Buffer::New(napi_env env, T* data, size_t length, Finalizer finalizeCallback); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] data`: The pointer to the external data to expose. - `[in] length`: The number of `T` elements in the external data. - `[in] finalizeCallback`: The function to be called when the `Napi::Buffer` is destroyed. It must implement `operator()`, accept a `T*` (which is the external data pointer), and return `void`. Returns a new `Napi::Buffer` object. ### New Wraps the provided external data into a new `Napi::Buffer` object. The `Napi::Buffer` object does not assume ownership for the data and expects it to be valid for the lifetime of the object. The data can only be freed once the `finalizeCallback` is invoked to indicate that the `Napi::Buffer` has been released. ```cpp template static Napi::Buffer Napi::Buffer::New(napi_env env, T* data, size_t length, Finalizer finalizeCallback, Hint* finalizeHint); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] data`: The pointer to the external data to expose. - `[in] length`: The number of `T` elements in the external data. - `[in] finalizeCallback`: The function to be called when the `Napi::Buffer` is destroyed. It must implement `operator()`, accept a `T*` (which is the external data pointer) and `Hint*`, and return `void`. - `[in] finalizeHint`: The hint to be passed as the second parameter of the finalize callback. Returns a new `Napi::Buffer` object. ### Copy Allocates a new `Napi::Buffer` object and copies the provided external data into it. ```cpp static Napi::Buffer Napi::Buffer::Copy(napi_env env, const T* data, size_t length); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] data`: The pointer to the external data to copy. - `[in] length`: The number of `T` elements in the external data. Returns a new `Napi::Buffer` object containing a copy of the data. ### Constructor Initializes an empty instance of the `Napi::Buffer` class. ```cpp Napi::Buffer::Buffer(); ``` ### Constructor Initializes the `Napi::Buffer` object using an existing Uint8Array. ```cpp Napi::Buffer::Buffer(napi_env env, napi_value value); ``` - `[in] env`: The environment in which to create the `Napi::Buffer` object. - `[in] value`: The Uint8Array reference to wrap. ### Data ```cpp T* Napi::Buffer::Data() const; ``` Returns a pointer the external data. ### Length ```cpp size_t Napi::Buffer::Length() const; ``` Returns the number of `T` elements in the external data. [`Napi::Uint8Array`]: ./typed_array_of.md # CallbackScope There are cases (for example, resolving promises) where it is necessary to have the equivalent of the scope associated with a callback in place when making certain N-API calls. ## Methods ### Constructor Creates a new callback scope on the stack. ```cpp Napi::CallbackScope::CallbackScope(napi_env env, napi_callback_scope scope); ``` - `[in] env`: The environment in which to create the `Napi::CallbackScope`. - `[in] scope`: The pre-existing `napi_callback_scope` or `Napi::CallbackScope`. ### Constructor Creates a new callback scope on the stack. ```cpp Napi::CallbackScope::CallbackScope(napi_env env, napi_async_context context); ``` - `[in] env`: The environment in which to create the `Napi::CallbackScope`. - `[in] async_context`: The pre-existing `napi_async_context` or `Napi::AsyncContext`. ### Destructor Deletes the instance of `Napi::CallbackScope` object. ```cpp virtual Napi::CallbackScope::~CallbackScope(); ``` ### Env ```cpp Napi::Env Napi::CallbackScope::Env() const; ``` Returns the `Napi::Env` associated with the `Napi::CallbackScope`. ## Operator ```cpp Napi::CallbackScope::operator napi_callback_scope() const; ``` Returns the N-API `napi_callback_scope` wrapped by the `Napi::CallbackScope` object. This can be used to mix usage of the C N-API and node-addon-api. # CallbackInfo The object representing the components of the JavaScript request being made. The `Napi::CallbackInfo` object is usually created and passed by the Node.js runtime or node-addon-api infrastructure. The `Napi::CallbackInfo` object contains the arguments passed by the caller. The number of arguments is returned by the `Length` method. Each individual argument can be accessed using the `operator[]` method. The `SetData` and `Data` methods are used to set and retrieve the data pointer contained in the `Napi::CallbackInfo` object. ## Methods ### Constructor ```cpp Napi::CallbackInfo::CallbackInfo(napi_env env, napi_callback_info info); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::CallbackInfo` object. - `[in] info`: The `napi_callback_info` data structure from which to construct the `Napi::CallbackInfo` object. ### Env ```cpp Napi::Env Napi::CallbackInfo::Env() const; ``` Returns the `Env` object in which the request is being made. ### NewTarget ```cpp Napi::Value Napi::CallbackInfo::NewTarget() const; ``` Returns the `new.target` value of the constructor call. If the function that was invoked (and for which the `Napi::NCallbackInfo` was passed) is not a constructor call, a call to `IsEmpty()` on the returned value returns true. ### IsConstructCall ```cpp bool Napi::CallbackInfo::IsConstructCall() const; ``` Returns a `bool` indicating if the function that was invoked (and for which the `Napi::CallbackInfo` was passed) is a constructor call. ### Length ```cpp size_t Napi::CallbackInfo::Length() const; ``` Returns the number of arguments passed in the `Napi::CallbackInfo` object. ### operator [] ```cpp const Napi::Value operator [](size_t index) const; ``` - `[in] index`: The zero-based index of the requested argument. Returns a `Napi::Value` object containing the requested argument. ### This ```cpp Napi::Value Napi::CallbackInfo::This() const; ``` Returns the JavaScript `this` value for the call ### Data ```cpp void* Napi::CallbackInfo::Data() const; ``` Returns the data pointer for the callback. ### SetData ```cpp void Napi::CallbackInfo::SetData(void* data); ``` - `[in] data`: The new data pointer to associate with this `Napi::CallbackInfo` object. Returns `void`. ### Not documented here ```cpp Napi::CallbackInfo::~CallbackInfo(); // Disallow copying to prevent multiple free of _dynamicArgs Napi::CallbackInfo::CallbackInfo(CallbackInfo const &) = delete; void Napi::CallbackInfo::operator=(CallbackInfo const &) = delete; ``` # Checker Tool **node-addon-api** provides a [checker tool][] that will inspect a given directory tree, identifying all Node.js native addons therein, and further indicating for each addon whether it is an N-API addon. ## To use the checker tool: 1. Install the application with `npm install`. 2. If the application does not depend on **node-addon-api**, copy the checker tool into the application's directory. 3. If the application does not depend on **node-addon-api**, run the checker tool from the application's directory: ```sh node ./check-napi.js ``` Otherwise, the checker tool can be run from the application's `node_modules/` subdirectory: ```sh node ./node_modules/node-addon-api/tools/check-napi.js ``` The tool accepts the root directory from which to start checking for Node.js native addons as a single optional command line parameter. If omitted it will start checking from the current directory (`.`). [checker tool]: ../tools/check-napi.js # Class property and descriptor Property descriptor for use with `Napi::ObjectWrap::DefineClass()`. This is different from the standalone `Napi::PropertyDescriptor` because it is specific to each `Napi::ObjectWrap` subclass. This prevents using descriptors from a different class when defining a new class (preventing the callbacks from having incorrect `this` pointers). ## Example ```cpp #include class Example : public Napi::ObjectWrap { public: static Napi::Object Init(Napi::Env env, Napi::Object exports); Example(const Napi::CallbackInfo &info); private: static Napi::FunctionReference constructor; double _value; Napi::Value GetValue(const Napi::CallbackInfo &info); void SetValue(const Napi::CallbackInfo &info, const Napi::Value &value); }; Napi::Object Example::Init(Napi::Env env, Napi::Object exports) { Napi::Function func = DefineClass(env, "Example", { // Register a class instance accessor with getter and setter functions. InstanceAccessor<&Example::GetValue, &Example::SetValue>("value"), // We can also register a readonly accessor by omitting the setter. InstanceAccessor<&Example::GetValue>("readOnlyProp") }); constructor = Napi::Persistent(func); constructor.SuppressDestruct(); exports.Set("Example", func); return exports; } Example::Example(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { Napi::Env env = info.Env(); // ... Napi::Number value = info[0].As(); this->_value = value.DoubleValue(); } Napi::FunctionReference Example::constructor; Napi::Value Example::GetValue(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); return Napi::Number::New(env, this->_value); } void Example::SetValue(const Napi::CallbackInfo &info, const Napi::Value &value) { Napi::Env env = info.Env(); // ... Napi::Number arg = value.As(); this->_value = arg.DoubleValue(); } // Initialize native add-on Napi::Object Init (Napi::Env env, Napi::Object exports) { Example::Init(env, exports); return exports; } // Register and initialize native add-on NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) ``` The above code can be used from JavaScript as follows: ```js 'use strict'; const { Example } = require('bindings')('addon'); const example = new Example(11); console.log(example.value); // It prints 11 example.value = 19; console.log(example.value); // It prints 19 example.readOnlyProp = 500; console.log(example.readOnlyProp); // Unchanged. It prints 19 ``` ## Methods ### Constructor Creates new instance of `Napi::ClassPropertyDescriptor` descriptor object. ```cpp Napi::ClassPropertyDescriptor(napi_property_descriptor desc) : _desc(desc) {} ``` - `[in] desc`: The `napi_property_descriptor` Returns new instance of `Napi::ClassPropertyDescriptor` that is used as property descriptor inside the `Napi::ObjectWrap` class. ### Operator ```cpp operator napi_property_descriptor&() { return _desc; } ``` Returns the original N-API `napi_property_descriptor` wrapped inside the `Napi::ClassPropertyDescriptor` ```cpp operator const napi_property_descriptor&() const { return _desc; } ``` Returns the original N-API `napi_property_descriptor` wrapped inside the `Napi::ClassPropertyDescriptor` # CMake.js [**CMake.js**](https://github.com/cmake-js/cmake-js) is a build tool that allow native addon developers to compile their C or C++ code into executable form. It works like **[node-gyp](node-gyp.md)** but instead of Google's [**gyp**](https://gyp.gsrc.io) tool it is based on the [**CMake**](https://cmake.org) build system. ## Quick Start ### Install CMake CMake.js requires that CMake be installed. Installers for a variety of platforms can be found on the [CMake website](https://cmake.org). ### Install CMake.js For developers, CMake.js is typically installed as a global package: ```bash npm install -g cmake-js cmake-js --help ``` > For *users* of your native addon, CMake.js should be configured as a dependency in your `package.json` as described in the [CMake.js documentation](https://github.com/cmake-js/cmake-js). ### CMakeLists.txt Your project will require a `CMakeLists.txt` file. The [CMake.js README file](https://github.com/cmake-js/cmake-js#usage) shows what's necessary. ### NAPI_VERSION When building N-API addons, it's crucial to specify the N-API version your code is designed to work with. With CMake.js, this information is specified in the `CMakeLists.txt` file: ``` add_definitions(-DNAPI_VERSION=3) ``` Since N-API is ABI-stable, your N-API addon will work, without recompilation, with the N-API version you specify in `NAPI_VERSION` and all subsequent N-API versions. In the absence of a need for features available only in a specific N-API version, version 3 is a good choice as it is the version of N-API that was active when N-API left experimental status. ### NAPI_EXPERIMENTAL The following line in the `CMakeLists.txt` file will enable N-API experimental features if your code requires them: ``` add_definitions(-DNAPI_EXPERIMENTAL) ``` ### node-addon-api If your N-API native add-on uses the optional [**node-addon-api**](https://github.com/nodejs/node-addon-api#node-addon-api-module) C++ wrapper, the `CMakeLists.txt` file requires additional configuration information as described on the [CMake.js README file](https://github.com/cmake-js/cmake-js#n-api-and-node-addon-api). ## Example A working example of an N-API native addon built using CMake.js can be found on the [node-addon-examples repository](https://github.com/nodejs/node-addon-examples/tree/master/build_with_cmake#building-n-api-addons-using-cmakejs). ## **CMake** Reference - [Installation](https://github.com/cmake-js/cmake-js#installation) - [How to use](https://github.com/cmake-js/cmake-js#usage) - [Using N-API and node-addon-api](https://github.com/cmake-js/cmake-js#n-api-and-node-addon-api) - [Tutorials](https://github.com/cmake-js/cmake-js#tutorials) - [Use case in the works - ArrayFire.js](https://github.com/cmake-js/cmake-js#use-case-in-the-works---arrayfirejs) Sometimes finding the right settings is not easy so to accomplish at most complicated task please refer to: - [CMake documentation](https://cmake.org/) - [CMake.js wiki](https://github.com/cmake-js/cmake-js/wiki) # Conversion Tool To make the migration to **node-addon-api** easier, we have provided a script to help complete some tasks. ## To use the conversion script: 1. Go to your module directory ``` cd [module_path] ``` 2. Install node-addon-api module ``` npm install node-addon-api ``` 3. Run node-addon-api conversion script ``` node ./node_modules/node-addon-api/tools/conversion.js ./ ``` 4. While this script makes conversion easier, it still cannot fully convert the module. The next step is to try to build the module and complete the remaining conversions necessary to allow it to compile and pass all of the module's tests.# Creating a release Only collaborators in npm for **node-addon-api** can create releases. If you want to be able to do releases ask one of the existing collaborators to add you. If necessary you can ask the build Working Group who manages the Node.js npm user to add you if there are no other active collaborators. ## Prerequisites Before to start creating a new release check if you have installed the following tools: * [Changelog maker](https://www.npmjs.com/package/changelog-maker) If not please follow the instruction reported in the tool's documentation to install it. ## Publish new release These are the steps to follow to create a new release: * Open an issue in the **node-addon-api** repo documenting the intent to create a new release. Give people some time to comment or suggest PRs that should land first. * Validate all tests pass by running npm test on master. * Update the version in **package.json** appropriately. * Update the [README.md](https://github.com/nodejs/node-addon-api/blob/master/README.md) to show the new version as the latest. * Generate the changelog for the new version using **changelog maker** tool. From the route folder of the repo launch the following command: ```bash > changelog-maker ``` * Use the output generated by **changelog maker** to update the [CHANGELOG.md](https://github.com/nodejs/node-addon-api/blob/master/CHANGELOG.md) following the style used in publishing the previous release. * Add any new contributors to the "contributors" section in the package.json * Validate all tests pass by running npm test on master. * Use **[CI](https://ci.nodejs.org/view/x%20-%20Abi%20stable%20module%20API/job/node-test-node-addon-api-new/)** to validate tests pass (note there are still some issues on SmartOS and Windows in the testing). * Do a clean checkout of node-addon-api. * Login and then run `npm publish`. * Create a release in Github (look at existing releases for an example). * Validate that you can run `npm install node-addon-api` successfully and that the correct version is installed. * Comment on the issue opened in the first step that the release has been created and close the issue. * Tweet that the release has been created. # DataView Class `Napi::DataView` inherits from class [`Napi::Object`][]. The `Napi::DataView` class corresponds to the [JavaScript `DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) class. ## Methods ### New Allocates a new `Napi::DataView` instance with a given `Napi::ArrayBuffer`. ```cpp static Napi::DataView Napi::DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer); ``` - `[in] env`: The environment in which to create the `Napi::DataView` instance. - `[in] arrayBuffer` : `Napi::ArrayBuffer` underlying the `Napi::DataView`. Returns a new `Napi::DataView` instance. ### New Allocates a new `Napi::DataView` instance with a given `Napi::ArrayBuffer`. ```cpp static Napi::DataView Napi::DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset); ``` - `[in] env`: The environment in which to create the `Napi::DataView` instance. - `[in] arrayBuffer` : `Napi::ArrayBuffer` underlying the `Napi::DataView`. - `[in] byteOffset` : The byte offset within the `Napi::ArrayBuffer` from which to start projecting the `Napi::DataView`. Returns a new `Napi::DataView` instance. ### New Allocates a new `Napi::DataView` instance with a given `Napi::ArrayBuffer`. ```cpp static Napi::DataView Napi::DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer, size_t byteOffset, size_t byteLength); ``` - `[in] env`: The environment in which to create the `Napi::DataView` instance. - `[in] arrayBuffer` : `Napi::ArrayBuffer` underlying the `Napi::DataView`. - `[in] byteOffset` : The byte offset within the `Napi::ArrayBuffer` from which to start projecting the `Napi::DataView`. - `[in] byteLength` : Number of elements in the `Napi::DataView`. Returns a new `Napi::DataView` instance. ### Constructor Initializes an empty instance of the `Napi::DataView` class. ```cpp Napi::DataView(); ``` ### Constructor Initializes a wrapper instance of an existing `Napi::DataView` instance. ```cpp Napi::DataView(napi_env env, napi_value value); ``` - `[in] env`: The environment in which to create the `Napi::DataView` instance. - `[in] value`: The `Napi::DataView` reference to wrap. ### ArrayBuffer ```cpp Napi::ArrayBuffer Napi::DataView::ArrayBuffer() const; ``` Returns the backing array buffer. ### ByteOffset ```cpp size_t Napi::DataView::ByteOffset() const; ``` Returns the offset into the `Napi::DataView` where the array starts, in bytes. ### ByteLength ```cpp size_t Napi::DataView::ByteLength() const; ``` Returns the length of the array, in bytes. ### GetFloat32 ```cpp float Napi::DataView::GetFloat32(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a signed 32-bit float (float) at the specified byte offset from the start of the `Napi::DataView`. ### GetFloat64 ```cpp double Napi::DataView::GetFloat64(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a signed 64-bit float (double) at the specified byte offset from the start of the `Napi::DataView`. ### GetInt8 ```cpp int8_t Napi::DataView::GetInt8(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a signed 8-bit integer (byte) at the specified byte offset from the start of the `Napi::DataView`. ### GetInt16 ```cpp int16_t Napi::DataView::GetInt16(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a signed 16-bit integer (short) at the specified byte offset from the start of the `Napi::DataView`. ### GetInt32 ```cpp int32_t Napi::DataView::GetInt32(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a signed 32-bit integer (long) at the specified byte offset from the start of the `Napi::DataView`. ### GetUint8 ```cpp uint8_t Napi::DataView::GetUint8(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a unsigned 8-bit integer (unsigned byte) at the specified byte offset from the start of the `Napi::DataView`. ### GetUint16 ```cpp uint16_t Napi::DataView::GetUint16(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a unsigned 16-bit integer (unsigned short) at the specified byte offset from the start of the `Napi::DataView`. ### GetUint32 ```cpp uint32_t Napi::DataView::GetUint32(size_t byteOffset) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. Returns a unsigned 32-bit integer (unsigned long) at the specified byte offset from the start of the `Napi::DataView`. ### SetFloat32 ```cpp void Napi::DataView::SetFloat32(size_t byteOffset, float value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetFloat64 ```cpp void Napi::DataView::SetFloat64(size_t byteOffset, double value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetInt8 ```cpp void Napi::DataView::SetInt8(size_t byteOffset, int8_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetInt16 ```cpp void Napi::DataView::SetInt16(size_t byteOffset, int16_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetInt32 ```cpp void Napi::DataView::SetInt32(size_t byteOffset, int32_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetUint8 ```cpp void Napi::DataView::SetUint8(size_t byteOffset, uint8_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetUint16 ```cpp void Napi::DataView::SetUint16(size_t byteOffset, uint16_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. ### SetUint32 ```cpp void Napi::DataView::SetUint32(size_t byteOffset, uint32_t value) const; ``` - `[in] byteOffset`: The offset, in byte, from the start of the view where to read the data. - `[in] value`: The value to set. [`Napi::Object`]: ./object.md # Date `Napi::Date` class is a representation of the JavaScript `Date` object. The `Napi::Date` class inherits its behavior from the `Napi::Value` class (for more info see [`Napi::Value`](value.md)). ## Methods ### Constructor Creates a new _empty_ instance of a `Napi::Date` object. ```cpp Napi::Date::Date(); ``` Creates a new _non-empty_ instance of a `Napi::Date` object. ```cpp Napi::Date::Date(napi_env env, napi_value value); ``` - `[in] env`: The environment in which to construct the `Napi::Date` object. - `[in] value`: The `napi_value` which is a handle for a JavaScript `Date`. ### New Creates a new instance of a `Napi::Date` object. ```cpp static Napi::Date Napi::Date::New(Napi::Env env, double value); ``` - `[in] env`: The environment in which to construct the `Napi::Date` object. - `[in] value`: The time value the JavaScript `Date` will contain represented as the number of milliseconds since 1 January 1970 00:00:00 UTC. Returns a new instance of `Napi::Date` object. ### ValueOf ```cpp double Napi::Date::ValueOf() const; ``` Returns the time value as `double` primitive represented as the number of milliseconds since 1 January 1970 00:00:00 UTC. ## Operators ### operator double Converts a `Napi::Date` value to a `double` primitive. ```cpp Napi::Date::operator double() const; ``` ### Example The following shows an example of casting a `Napi::Date` value to a `double` primitive. ```cpp double operatorVal = Napi::Date::New(Env(), 0); // Napi::Date to double // or auto instanceVal = info[0].As().ValueOf(); ``` # Env The opaque data structure containing the environment in which the request is being run. The Env object is usually created and passed by the Node.js runtime or node-addon-api infrastructure. ## Methods ### Constructor ```cpp Napi::Env::Env(napi_env env); ``` - `[in] env`: The `napi_env` environment from which to construct the `Napi::Env` object. ### napi_env ```cpp operator napi_env() const; ``` Returns the `napi_env` opaque data structure representing the environment. ### Global ```cpp Napi::Object Napi::Env::Global() const; ``` Returns the `Napi::Object` representing the environment's JavaScript Global Object. ### Undefined ```cpp Napi::Value Napi::Env::Undefined() const; ``` Returns the `Napi::Value` representing the environment's JavaScript Undefined Object. ### Null ```cpp Napi::Value Napi::Env::Null() const; ``` Returns the `Napi::Value` representing the environment's JavaScript Null Object. ### IsExceptionPending ```cpp bool Napi::Env::IsExceptionPending() const; ``` Returns a `bool` indicating if an exception is pending in the environment. ### GetAndClearPendingException ```cpp Napi::Error Napi::Env::GetAndClearPendingException(); ``` Returns an `Napi::Error` object representing the environment's pending exception, if any. ### RunScript ```cpp Napi::Value Napi::Env::RunScript(____ script); ``` - `[in] script`: A string containing JavaScript code to execute. Runs JavaScript code contained in a string and returns its result. The `script` can be any of the following types: - [`Napi::String`](string.md) - `const char *` - `const std::string &` ### GetInstanceData ```cpp template T* GetInstanceData(); ``` Returns the instance data that was previously associated with the environment, or `nullptr` if none was associated. ### SetInstanceData ```cpp template using Finalizer = void (*)(Env, T*); template fini = Env::DefaultFini> void SetInstanceData(T* data); ``` - `[template] fini`: A function to call when the instance data is to be deleted. Accepts a function of the form `void CleanupData(Napi::Env env, T* data)`. If not given, the default finalizer will be used, which simply uses the `delete` operator to destroy `T*` when the addon instance is unloaded. - `[in] data`: A pointer to data that will be associated with the instance of the addon for the duration of its lifecycle. Associates a data item stored at `T* data` with the current instance of the addon. The item will be passed to the function `fini` which gets called when an instance of the addon is unloaded. ### SetInstanceData ```cpp template using FinalizerWithHint = void (*)(Env, DataType*, HintType*); template fini = Env::DefaultFiniWithHint> void SetInstanceData(DataType* data, HintType* hint); ``` - `[template] fini`: A function to call when the instance data is to be deleted. Accepts a function of the form `void CleanupData(Napi::Env env, DataType* data, HintType* hint)`. If not given, the default finalizer will be used, which simply uses the `delete` operator to destroy `T*` when the addon instance is unloaded. - `[in] data`: A pointer to data that will be associated with the instance of the addon for the duration of its lifecycle. - `[in] hint`: A pointer to data that will be associated with the instance of the addon for the duration of its lifecycle and will be passed as a hint to `fini` when the addon instance is unloaded. Associates a data item stored at `T* data` with the current instance of the addon. The item will be passed to the function `fini` which gets called when an instance of the addon is unloaded. This overload accepts an additional hint to be passed to `fini`. # Error Class `Napi::Error` inherits from class [`Napi::ObjectReference`][] and class [`std::exception`][]. The `Napi::Error` class is a representation of the JavaScript `Error` object that is thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions. The `Napi::Error` class is a persistent reference to a JavaScript error object thus inherits its behavior from the `Napi::ObjectReference` class (for more info see: [`Napi::ObjectReference`](object_reference.md)). If C++ exceptions are enabled (for more info see: [Setup](setup.md)), then the `Napi::Error` class extends `std::exception` and enables integrated error-handling for C++ exceptions and JavaScript exceptions. For more details about error handling refer to the section titled [Error handling](error_handling.md). ## Methods ### New Creates empty instance of an `Napi::Error` object for the specified environment. ```cpp Napi::Error::New(Napi::Env env); ``` - `[in] env`: The environment in which to construct the `Napi::Error` object. Returns an instance of `Napi::Error` object. ### New Creates instance of an `Napi::Error` object. ```cpp Napi::Error::New(Napi::Env env, const char* message); ``` - `[in] env`: The environment in which to construct the `Napi::Error` object. - `[in] message`: Null-terminated string to be used as the message for the `Napi::Error`. Returns instance of an `Napi::Error` object. ### New Creates instance of an `Napi::Error` object ```cpp Napi::Error::New(Napi::Env env, const std::string& message); ``` - `[in] env`: The environment in which to construct the `Napi::Error` object. - `[in] message`: Reference string to be used as the message for the `Napi::Error`. Returns instance of an `Napi::Error` object. ### Fatal In case of an unrecoverable error in a native module, a fatal error can be thrown to immediately terminate the process. ```cpp static NAPI_NO_RETURN void Napi::Error::Fatal(const char* location, const char* message); ``` The function call does not return, the process will be terminated. ### Constructor Creates empty instance of an `Napi::Error`. ```cpp Napi::Error::Error(); ``` Returns an instance of `Napi::Error` object. ### Constructor Initializes an `Napi::Error` instance from an existing JavaScript error object. ```cpp Napi::Error::Error(napi_env env, napi_value value); ``` - `[in] env`: The environment in which to construct the error object. - `[in] value`: The `Napi::Error` reference to wrap. Returns instance of an `Napi::Error` object. ### Message ```cpp std::string& Napi::Error::Message() const NAPI_NOEXCEPT; ``` Returns the reference to the string that represent the message of the error. ### ThrowAsJavaScriptException Throw the error as JavaScript exception. ```cpp void Napi::Error::ThrowAsJavaScriptException() const; ``` Throws the error as a JavaScript exception. ### what ```cpp const char* Napi::Error::what() const NAPI_NOEXCEPT override; ``` Returns a pointer to a null-terminated string that is used to identify the exception. This method can be used only if the exception mechanism is enabled. [`Napi::ObjectReference`]: ./object_reference.md [`std::exception`]: https://cplusplus.com/reference/exception/exception/ # Error handling Error handling represents one of the most important considerations when implementing a Node.js native add-on. When an error occurs in your C++ code you have to handle and dispatch it correctly. **node-addon-api** uses return values and JavaScript exceptions for error handling. You can choose return values or exception handling based on the mechanism that works best for your add-on. The `Napi::Error` is a persistent reference (for more info see: [`Napi::ObjectReference`](object_reference.md)) to a JavaScript error object. Use of this class depends on whether C++ exceptions are enabled at compile time. If C++ exceptions are enabled (for more info see: [Setup](setup.md)), then the `Napi::Error` class extends `std::exception` and enables integrated error-handling for C++ exceptions and JavaScript exceptions. The following sections explain the approach for each case: - [Handling Errors With C++ Exceptions](#exceptions) - [Handling Errors Without C++ Exceptions](#noexceptions) In most cases when an error occurs, the addon should do whatever clean is possible and then return to JavaScript so that they error can be propagated. In less frequent cases the addon may be able to recover from the error, clear the error and then continue. ## Handling Errors With C++ Exceptions When C++ exceptions are enabled try/catch can be used to catch exceptions thrown from calls to JavaScript and then they can either be handled or rethrown before returning from a native method. If a node-addon-api call fails without executing any JavaScript code (for example due to an invalid argument), then node-addon-api automatically converts and throws the error as a C++ exception of type `Napi::Error`. If a JavaScript function called by C++ code via node-addon-api throws a JavaScript exception, then node-addon-api automatically converts and throws it as a C++ exception of type `Napi:Error` on return from the JavaScript code to the native method. If a C++ exception of type `Napi::Error` escapes from a N-API C++ callback, then the N-API wrapper automatically converts and throws it as a JavaScript exception. On return from a native method, node-addon-api will automatically convert a pending C++ exception to a JavaScript exception. When C++ exceptions are enabled try/catch can be used to catch exceptions thrown from calls to JavaScript and then they can either be handled or rethrown before returning from a native method. ## Examples with C++ exceptions enabled ### Throwing a C++ exception ```cpp Env env = ... throw Napi::Error::New(env, "Example exception"); // other C++ statements // ... ``` The statements following the throw statement will not be executed. The exception will bubble up as a C++ exception of type `Napi::Error`, until it is either caught while still in C++, or else automatically propagated as a JavaScript exception when returning to JavaScript. ### Propagating a N-API C++ exception ```cpp Napi::Function jsFunctionThatThrows = someObj.As(); Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); // other C++ statements // ... ``` The C++ statements following the call to the JavaScript function will not be executed. The exception will bubble up as a C++ exception of type `Napi::Error`, until it is either caught while still in C++, or else automatically propagated as a JavaScript exception when returning to JavaScript. ### Handling a N-API C++ exception ```cpp Napi::Function jsFunctionThatThrows = someObj.As(); Napi::Value result; try { result = jsFunctionThatThrows({ arg1, arg2 }); } catch (const Error& e) { cerr << "Caught JavaScript exception: " + e.what(); } ``` Since the exception was caught here, it will not be propagated as a JavaScript exception. ## Handling Errors Without C++ Exceptions If C++ exceptions are disabled (for more info see: [Setup](setup.md)), then the `Napi::Error` class does not extend `std::exception`. This means that any calls to node-addon-api function do not throw a C++ exceptions. Instead, it raises _pending_ JavaScript exceptions and returns an _empty_ `Napi::Value`. The calling code should check `env.IsExceptionPending()` before attempting to use a returned value, and may use methods on the `Napi::Env` class to check for, get, and clear a pending JavaScript exception (for more info see: [Env](env.md)). If the pending exception is not cleared, it will be thrown when the native code returns to JavaScript. ## Examples with C++ exceptions disabled ### Throwing a JS exception ```cpp Napi::Env env = ... Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException(); return; ``` After throwing a JavaScript exception, the code should generally return immediately from the native callback, after performing any necessary cleanup. ### Propagating a N-API JS exception ```cpp Napi::Env env = ... Napi::Function jsFunctionThatThrows = someObj.As(); Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); if (env.IsExceptionPending()) { Error e = env.GetAndClearPendingException(); return e.Value(); } ``` If env.IsExceptionPending() returns true a JavaScript exception is pending. To let the exception propagate, the code should generally return immediately from the native callback, after performing any necessary cleanup. ### Handling a N-API JS exception ```cpp Napi::Env env = ... Napi::Function jsFunctionThatThrows = someObj.As(); Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); if (env.IsExceptionPending()) { Napi::Error e = env.GetAndClearPendingException(); cerr << "Caught JavaScript exception: " + e.Message(); } ``` Since the exception was cleared here, it will not be propagated as a JavaScript exception after the native callback returns. ## Calling N-API directly from a **node-addon-api** addon **node-addon-api** provides macros for throwing errors in response to non-OK `napi_status` results when calling [N-API](https://nodejs.org/docs/latest/api/n-api.html) functions from within a native addon. These macros are defined differently depending on whether C++ exceptions are enabled or not, but are available for use in either case. ### `NAPI_THROW(e, ...)` This macro accepts a `Napi::Error`, throws it, and returns the value given as the last parameter. If C++ exceptions are enabled (by defining `NAPI_CPP_EXCEPTIONS` during the build), the return value will be ignored. ### `NAPI_THROW_IF_FAILED(env, status, ...)` This macro accepts a `Napi::Env` and a `napi_status`. It constructs an error from the `napi_status`, throws it, and returns the value given as the last parameter. If C++ exceptions are enabled (by defining `NAPI_CPP_EXCEPTIONS` during the build), the return value will be ignored. ### `NAPI_THROW_IF_FAILED_VOID(env, status)` This macro accepts a `Napi::Env` and a `napi_status`. It constructs an error from the `napi_status`, throws it, and returns. ### `NAPI_FATAL_IF_FAILED(status, location, message)` This macro accepts a `napi_status`, a C string indicating the location where the error occurred, and a second C string for the message to display. # EscapableHandleScope The `Napi::EscapableHandleScope` class is used to manage the lifetime of object handles which are created through the use of node-addon-api. These handles keep an object alive in the heap in order to ensure that the objects are not collected by the garbage collector while native code is using them. A handle may be created when any new node-addon-api Value or one of its subclasses is created or returned. The `Napi::EscapableHandleScope` is a special type of `Napi::HandleScope` which allows a single handle to be "promoted" to an outer scope. For more details refer to the section titled [Object lifetime management](object_lifetime_management.md). ## Methods ### Constructor Creates a new escapable handle scope. ```cpp Napi::EscapableHandleScope Napi::EscapableHandleScope::New(Napi:Env env); ``` - `[in] Env`: The environment in which to construct the `Napi::EscapableHandleScope` object. Returns a new `Napi::EscapableHandleScope` ### Constructor Creates a new escapable handle scope. ```cpp Napi::EscapableHandleScope Napi::EscapableHandleScope::New(napi_env env, napi_handle_scope scope); ``` - `[in] env`: napi_env in which the scope passed in was created. - `[in] scope`: pre-existing napi_handle_scope. Returns a new `Napi::EscapableHandleScope` instance which wraps the napi_escapable_handle_scope handle passed in. This can be used to mix usage of the C N-API and node-addon-api. operator EscapableHandleScope::napi_escapable_handle_scope ```cpp operator Napi::EscapableHandleScope::napi_escapable_handle_scope() const ``` Returns the N-API napi_escapable_handle_scope wrapped by the `Napi::EscapableHandleScope` object. This can be used to mix usage of the C N-API and node-addon-api by allowing the class to be used be converted to a napi_escapable_handle_scope. ### Destructor ```cpp Napi::EscapableHandleScope::~EscapableHandleScope(); ``` Deletes the `Napi::EscapableHandleScope` instance and allows any objects/handles created in the scope to be collected by the garbage collector. There is no guarantee as to when the garbage collector will do this. ### Escape ```cpp napi::Value Napi::EscapableHandleScope::Escape(napi_value escapee); ``` - `[in] escapee`: Napi::Value or napi_env to promote to the outer scope Returns `Napi::Value` which can be used in the outer scope. This method can be called at most once on a given `Napi::EscapableHandleScope`. If it is called more than once an exception will be thrown. ### Env ```cpp Napi::Env Napi::EscapableHandleScope::Env() const; ``` Returns the `Napi::Env` associated with the `Napi::EscapableHandleScope`. # External (template) Class `Napi::External` inherits from class [`Napi::Value`][]. The `Napi::External` template class implements the ability to create a `Napi::Value` object with arbitrary C++ data. It is the user's responsibility to manage the memory for the arbitrary C++ data. `Napi::External` objects can be created with an optional Finalizer function and optional Hint value. The Finalizer function, if specified, is called when your `Napi::External` object is released by Node's garbage collector. It gives your code the opportunity to free any dynamically created data. If you specify a Hint value, it is passed to your Finalizer function. ## Methods ### New ```cpp template static Napi::External Napi::External::New(napi_env env, T* data); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::External` object. - `[in] data`: The arbitrary C++ data to be held by the `Napi::External` object. Returns the created `Napi::External` object. ### New ```cpp template static Napi::External Napi::External::New(napi_env env, T* data, Finalizer finalizeCallback); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::External` object. - `[in] data`: The arbitrary C++ data to be held by the `Napi::External` object. - `[in] finalizeCallback`: A function called when the `Napi::External` object is released by the garbage collector accepting a T* and returning void. Returns the created `Napi::External` object. ### New ```cpp template static Napi::External Napi::External::New(napi_env env, T* data, Finalizer finalizeCallback, Hint* finalizeHint); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::External` object. - `[in] data`: The arbitrary C++ data to be held by the `Napi::External` object. - `[in] finalizeCallback`: A function called when the `Napi::External` object is released by the garbage collector accepting T* and Hint* parameters and returning void. - `[in] finalizeHint`: A hint value passed to the `finalizeCallback` function. Returns the created `Napi::External` object. ### Data ```cpp T* Napi::External::Data() const; ``` Returns a pointer to the arbitrary C++ data held by the `Napi::External` object. [`Napi::Value`]: ./value.md # Function The `Napi::Function` class provides a set of methods for creating a function object in native code that can later be called from JavaScript. The created function is not automatically visible from JavaScript. Instead it needs to be part of the add-on's module exports or be returned by one of the module's exported functions. In addition the `Napi::Function` class also provides methods that can be used to call functions that were created in JavaScript and passed to the native add-on. The `Napi::Function` class inherits its behavior from the `Napi::Object` class (for more info see: [`Napi::Object`](object.md)). > For callbacks that will be called with asynchronous events from a > non-JavaScript thread, please refer to [`Napi::ThreadSafeFunction`][] for more > examples. ## Example ```cpp #include using namespace Napi; Value Fn(const CallbackInfo& info) { Env env = info.Env(); // ... return String::New(env, "Hello World"); } Object Init(Env env, Object exports) { exports.Set(String::New(env, "fn"), Function::New(env)); return exports; } NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) ``` The above code can be used from JavaScript as follows: ```js const addon = require('./addon'); addon.fn(); ``` With the `Napi::Function` class it is possible to call a JavaScript function object from a native add-on with two different methods: `Call` and `MakeCallback`. The API of these two methods is very similar, but they are used in different contexts. The `MakeCallback` method is used to call from native code back into JavaScript after returning from an [asynchronous operation](async_operations.md) and in general in situations which don't have an existing JavaScript function on the stack. The `Call` method is used when there is already a JavaScript function on the stack (for example when running a native method called from JavaScript). ## Type definitions ### Napi::Function::VoidCallback This is the type describing a callback returning `void` that will be invoked from JavaScript. ```cpp typedef void (*VoidCallback)(const Napi::CallbackInfo& info); ``` ### Napi::Function::Callback This is the type describing a callback returning a value that will be invoked from JavaScript. ```cpp typedef Value (*Callback)(const Napi::CallbackInfo& info); ``` ## Methods ### Constructor Creates a new empty instance of `Napi::Function`. ```cpp Napi::Function::Function(); ``` ### Constructor Creates a new instance of the `Napi::Function` object. ```cpp Napi::Function::Function(napi_env env, napi_value value); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] value`: The `napi_value` which is a handle for a JavaScript function. Returns a non-empty `Napi::Function` instance. ### New Creates an instance of a `Napi::Function` object. ```cpp template static Napi::Function New(napi_env env, const char* utf8name = nullptr, void* data = nullptr); ``` - `[template] cb`: The native function to invoke when the JavaScript function is invoked. - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] utf8name`: Null-terminated string to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New Creates an instance of a `Napi::Function` object. ```cpp template static Napi::Function New(napi_env env, const char* utf8name = nullptr, void* data = nullptr); ``` - `[template] cb`: The native function to invoke when the JavaScript function is invoked. - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] utf8name`: Null-terminated string to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New Creates an instance of a `Napi::Function` object. ```cpp template static Napi::Function New(napi_env env, const std::string& utf8name, void* data = nullptr); ``` - `[template] cb`: The native function to invoke when the JavaScript function is invoked. - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] utf8name`: String to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New Creates an instance of a `Napi::Function` object. ```cpp template static Napi::Function New(napi_env env, const std::string& utf8name, void* data = nullptr); ``` - `[template] cb`: The native function to invoke when the JavaScript function is invoked. - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] utf8name`: String to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New Creates an instance of a `Napi::Function` object. ```cpp template static Napi::Function Napi::Function::New(napi_env env, Callable cb, const char* utf8name = nullptr, void* data = nullptr); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] cb`: Object that implements `Callable`. - `[in] utf8name`: Null-terminated string to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New ```cpp template static Napi::Function Napi::Function::New(napi_env env, Callable cb, const std::string& utf8name, void* data = nullptr); ``` - `[in] env`: The `napi_env` environment in which to construct the `Napi::Function` object. - `[in] cb`: Object that implements `Callable`. - `[in] utf8name`: String to be used as the name of the function. - `[in] data`: User-provided data context. This will be passed back into the function when invoked later. Returns an instance of a `Napi::Function` object. ### New Creates a new JavaScript value from one that represents the constructor for the object. ```cpp Napi::Object Napi::Function::New(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the constructor function. Returns a new JavaScript object. ### New Creates a new JavaScript value from one that represents the constructor for the object. ```cpp Napi::Object Napi::Function::New(const std::vector& args) const; ``` - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the constructor function. Returns a new JavaScript object. ### New Creates a new JavaScript value from one that represents the constructor for the object. ```cpp Napi::Object Napi::Function::New(size_t argc, const napi_value* args) const; ``` - `[in] argc`: The number of the arguments passed to the constructor function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the constructor function. Returns a new JavaScript object. ### Call Calls a Javascript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### Call Calls a JavaScript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(const std::vector& args) const; ``` - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### Call Calls a Javascript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(size_t argc, const napi_value* args) const; ``` - `[in] argc`: The number of the arguments passed to the function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### Call Calls a Javascript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(napi_value recv, const std::initializer_list& args) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### Call Calls a Javascript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(napi_value recv, const std::vector& args) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### Call Calls a Javascript function from a native add-on. ```cpp Napi::Value Napi::Function::Call(napi_value recv, size_t argc, const napi_value* args) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] argc`: The number of the arguments passed to the function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the function. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### MakeCallback Calls a Javascript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::Function::MakeCallback(napi_value recv, const std::initializer_list& args, napi_async_context context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### MakeCallback Calls a Javascript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::Function::MakeCallback(napi_value recv, const std::vector& args, napi_async_context context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] args`: List of JavaScript values as `napi_value` representing the arguments of the function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript value returned by the function. ### MakeCallback Calls a Javascript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::Function::MakeCallback(napi_value recv, size_t argc, const napi_value* args, napi_async_context context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the called function. - `[in] argc`: The number of the arguments passed to the function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript value returned by the function. ## Operator ```cpp Napi::Value Napi::Function::operator ()(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of JavaScript values as `napi_value`. Returns a `Napi::Value` representing the JavaScript value returned by the function. [`Napi::ThreadSafeFunction`]: ./threadsafe_function.md # FunctionReference `Napi::FunctionReference` is a subclass of [`Napi::Reference`](reference.md), and is equivalent to an instance of `Napi::Reference`. This means that a `Napi::FunctionReference` holds a [`Napi::Function`](function.md), and a count of the number of references to that `Napi::Function`. When the count is greater than 0, a `Napi::FunctionReference` is not eligible for garbage collection. This ensures that the `Function` will remain accessible, even if the original reference to it is no longer available. `Napi::FunctionReference` allows the referenced JavaScript function object to be called from a native add-on with two different methods: `Call` and `MakeCallback`. See the documentation for [`Napi::Function`](function.md) for when `Call` should be used instead of `MakeCallback` and vice-versa. The `Napi::FunctionReference` class inherits its behavior from the `Napi::Reference` class (for more info see: [`Napi::Reference`](reference.md)). ## Methods ### Weak Creates a "weak" reference to the value, in that the initial reference count is set to 0. ```cpp static Napi::FunctionReference Napi::Weak(const Napi::Function& value); ``` - `[in] value`: The value which is to be referenced. Returns the newly created reference. ### Persistent Creates a "persistent" reference to the value, in that the initial reference count is set to 1. ```cpp static Napi::FunctionReference Napi::Persistent(const Napi::Function& value); ``` - `[in] value`: The value which is to be referenced. Returns the newly created reference. ### Constructor Creates a new empty instance of `Napi::FunctionReference`. ```cpp Napi::FunctionReference::FunctionReference(); ``` ### Constructor Creates a new instance of the `Napi::FunctionReference`. ```cpp Napi::FunctionReference::FunctionReference(napi_env env, napi_ref ref); ``` - `[in] env`: The environment in which to construct the `Napi::FunctionReference` object. - `[in] ref`: The N-API reference to be held by the `Napi::FunctionReference`. Returns a newly created `Napi::FunctionReference` object. ### New Constructs a new instance by calling the constructor held by this reference. ```cpp Napi::Object Napi::FunctionReference::New(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the constructor function. Returns a new JavaScript object. ### New Constructs a new instance by calling the constructor held by this reference. ```cpp Napi::Object Napi::FunctionReference::New(const std::vector& args) const; ``` - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the constructor function. Returns a new JavaScript object. ### Call Calls a referenced Javascript function from a native add-on. ```cpp Napi::Value Napi::FunctionReference::Call(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the referenced function. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### Call Calls a referenced JavaScript function from a native add-on. ```cpp Napi::Value Napi::FunctionReference::Call(const std::vector& args) const; ``` - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the referenced function. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### Call Calls a referenced JavaScript function from a native add-on. ```cpp Napi::Value Napi::FunctionReference::Call(napi_value recv, const std::initializer_list& args) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the referenced function. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### Call Calls a referenced JavaScript function from a native add-on. ```cpp Napi::Value Napi::FunctionReference::Call(napi_value recv, const std::vector& args) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the referenced function. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### Call Calls a referenced JavaScript function from a native add-on. ```cpp Napi::Value Napi::FunctionReference::Call(napi_value recv, size_t argc, const napi_value* args) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] argc`: The number of arguments passed to the referenced function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the referenced function. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### MakeCallback Calls a referenced JavaScript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::FunctionReference::MakeCallback(napi_value recv, const std::initializer_list& args, napi_async_context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] args`: Initializer list of JavaScript values as `napi_value` representing the arguments of the referenced function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### MakeCallback Calls a referenced JavaScript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::FunctionReference::MakeCallback(napi_value recv, const std::vector& args, napi_async_context context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] args`: Vector of JavaScript values as `napi_value` representing the arguments of the referenced function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ### MakeCallback Calls a referenced JavaScript function from a native add-on after an asynchronous operation. ```cpp Napi::Value Napi::FunctionReference::MakeCallback(napi_value recv, size_t argc, const napi_value* args, napi_async_context context = nullptr) const; ``` - `[in] recv`: The `this` object passed to the referenced function when it's called. - `[in] argc`: The number of arguments passed to the referenced function. - `[in] args`: Array of JavaScript values as `napi_value` representing the arguments of the referenced function. - `[in] context`: Context for the async operation that is invoking the callback. This should normally be a value previously obtained from [Napi::AsyncContext](async_context.md). However `nullptr` is also allowed, which indicates the current async context (if any) is to be used for the callback. Returns a `Napi::Value` representing the JavaScript object returned by the referenced function. ## Operator ```cpp Napi::Value operator ()(const std::initializer_list& args) const; ``` - `[in] args`: Initializer list of reference to JavaScript values as `napi_value` Returns a `Napi::Value` representing the JavaScript value returned by the referenced function. # Generator ## What is generator **[generator-napi-module](https://www.npmjs.com/package/generator-napi-module)** is a module to quickly generate a skeleton module using **N-API**, the new API for Native addons. This module automatically sets up your **gyp file** to use **node-addon-api**, the C++ wrappers for N-API and generates a wrapper JS module. Optionally, it can even configure the generated project to use **TypeScript** instead. ## **generator-napi-module** reference - [Installation and usage](https://www.npmjs.com/package/generator-napi-module#installation) # HandleScope The HandleScope class is used to manage the lifetime of object handles which are created through the use of node-addon-api. These handles keep an object alive in the heap in order to ensure that the objects are not collected while native code is using them. A handle may be created when any new node-addon-api Value or one of its subclasses is created or returned. For more details refer to the section titled [Object lifetime management](object_lifetime_management.md). ## Methods ### Constructor Creates a new handle scope on the stack. ```cpp Napi::HandleScope::HandleScope(Napi::Env env); ``` - `[in] env`: The environment in which to construct the `Napi::HandleScope` object. Returns a new `Napi::HandleScope` ### Constructor Creates a new handle scope on the stack. ```cpp Napi::HandleScope::HandleScope(Napi::Env env, Napi::HandleScope scope); ``` - `[in] env`: `Napi::Env` in which the scope passed in was created. - `[in] scope`: pre-existing `Napi::HandleScope`. Returns a new `Napi::HandleScope` instance which wraps the napi_handle_scope handle passed in. This can be used to mix usage of the C N-API and node-addon-api. operator HandleScope::napi_handle_scope ```cpp operator Napi::HandleScope::napi_handle_scope() const ``` Returns the N-API napi_handle_scope wrapped by the `Napi::EscapableHandleScope` object. This can be used to mix usage of the C N-API and node-addon-api by allowing the class to be used be converted to a napi_handle_scope. ### Destructor ```cpp Napi::HandleScope::~HandleScope(); ``` Deletes the `Napi::HandleScope` instance and allows any objects/handles created in the scope to be collected by the garbage collector. There is no guarantee as to when the garbage collector will do this. ### Env ```cpp Napi::Env Napi::HandleScope::Env() const; ``` Returns the `Napi::Env` associated with the `Napi::HandleScope`. # Full Class Hierarchy | Class | Parent Class(es) | |---|---| | [`Napi::Addon`][] | [`Napi::InstanceWrap`][] | | [`Napi::Array`][] | [`Napi::Object`][] | | [`Napi::ArrayBuffer`][] | [`Napi::Object`][] | | [`Napi::AsyncContext`][] | | | [`Napi::AsyncProgressQueueWorker`][] | `Napi::AsyncProgressWorkerBase` | | [`Napi::AsyncProgressWorker`][] | `Napi::AsyncProgressWorkerBase` | | [`Napi::AsyncWorker`][] | | | [`Napi::BigInt`][] | [`Napi::Value`][] | | [`Napi::Boolean`][] | [`Napi::Value`][] | | [`Napi::Buffer`][] | [`Napi::Uint8Array`][] | | [`Napi::CallbackInfo`][] | | | [`Napi::CallbackScope`][] | | | [`Napi::ClassPropertyDescriptor`][] | | | [`Napi::DataView`][] | [`Napi::Object`][] | | [`Napi::Date`][] | [`Napi::Value`][] | | [`Napi::Env`][] | | | [`Napi::Error`][] | [`Napi::ObjectReference`][], [`std::exception`][] | | [`Napi::EscapableHandleScope`][] | | | [`Napi::External`][] | [`Napi::Value`][] | | [`Napi::Function`][] | [`Napi::Object`][] | | [`Napi::FunctionReference`][] | [`Napi::Reference`][] | | [`Napi::HandleScope`][] | | | [`Napi::InstanceWrap`][] | | | [`Napi::MemoryManagement`][] | | | [`Napi::Name`][] | [`Napi::Value`][] | | [`Napi::Number`][] | [`Napi::Value`][] | | [`Napi::Object`][] | [`Napi::Value`][] | | [`Napi::ObjectReference`][] | [`Napi::Reference`][] | | [`Napi::ObjectWrap`][] | [`Napi::InstanceWrap`][], [`Napi::Reference`][] | | [`Napi::Promise`][] | [`Napi::Object`][] | | [`Napi::PropertyDescriptor`][] | | | [`Napi::RangeError`][] | [`Napi::Error`][] | | [`Napi::Reference`] | | | [`Napi::String`][] | [`Napi::Name`][] | | [`Napi::Symbol`][] | [`Napi::Name`][] | | [`Napi::ThreadSafeFunction`][] | | | [`Napi::TypeError`][] | [`Napi::Error`][] | | [`Napi::TypedArray`][] | [`Napi::Object`][] | | [`Napi::TypedArrayOf`][] | [`Napi::TypedArray`][] | | [`Napi::Value`][] | | | [`Napi::VersionManagement`][] | | [`Napi::Addon`]: ./addon.md [`Napi::Array`]: ./array.md [`Napi::ArrayBuffer`]: ./array_buffer.md [`Napi::AsyncContext`]: ./async_context.md [`Napi::AsyncProgressQueueWorker`]: ./async_worker_variants.md#asyncprogressqueueworker [`Napi::AsyncProgressWorker`]: ./async_worker_variants.md#asyncprogressworker [`Napi::AsyncWorker`]: ./async_worker.md [`Napi::BigInt`]: ./bigint.md [`Napi::Boolean`]: ./boolean.md [`Napi::Buffer`]: ./buffer.md [`Napi::CallbackInfo`]: ./callbackinfo.md [`Napi::CallbackScope`]: ./callback_scope.md [`Napi::ClassPropertyDescriptor`]: ./class_property_descriptor.md [`Napi::DataView`]: ./dataview.md [`Napi::Date`]: ./date.md [`Napi::Env`]: ./env.md [`Napi::Error`]: ./error.md [`Napi::EscapableHandleScope`]: ./escapable_handle_scope.md [`Napi::External`]: ./external.md [`Napi::Function`]: ./function.md [`Napi::FunctionReference`]: ./function_reference.md [`Napi::HandleScope`]: ./handle_scope.md [`Napi::InstanceWrap`]: ./instance_wrap.md [`Napi::MemoryManagement`]: ./memory_management.md [`Napi::Name`]: ./name.md [`Napi::Number`]: ./number.md [`Napi::Object`]: ./object.md [`Napi::ObjectReference`]: ./object_reference.md [`Napi::ObjectWrap`]: ./object_wrap.md [`Napi::Promise`]: ./promise.md [`Napi::PropertyDescriptor`]: ./property_descriptor.md [`Napi::RangeError`]: ./range_error.md [`Napi::Reference`]: ./reference.md [`Napi::Reference`]: ./reference.md [`Napi::Reference`]: ./reference.md [`Napi::String`]: ./string.md [`Napi::Symbol`]: ./symbol.md [`Napi::ThreadSafeFunction`]: ./thread_safe_function.md [`Napi::TypeError`]: ./type_error.md [`Napi::TypedArray`]: ./typed_array.md [`Napi::TypedArrayOf`]: ./typed_array_of.md [`Napi::Uint8Array`]: ./typed_array_of.md [`Napi::Value`]: ./value.md [`Napi::VersionManagement`]: ./version_management.md [`std::exception`]: https://cplusplus.com/reference/exception/exception/ # InstanceWrap This class serves as the base class for [`Napi::ObjectWrap`][] and [`Napi::Addon`][]. In the case of [`Napi::Addon`][] it provides the methods for exposing functions to JavaScript on instances of an add-on. As a base class for [`Napi::ObjectWrap`][] it provides the methods for exposing instance methods of JavaScript objects instantiated from the JavaScript class corresponding to the subclass of [`Napi::ObjectWrap`][]. ## Methods ### InstanceMethod Creates a property descriptor that represents a method exposed on JavaScript instances of this class. ```cpp template static Napi::ClassPropertyDescriptor Napi::InstanceWrap::InstanceMethod(const char* utf8name, InstanceVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); ``` - `[in] utf8name`: Null-terminated string that represents the name of the method provided by instances of the class. - `[in] method`: The native function that represents a method provided by the add-on. - `[in] attributes`: The attributes associated with the property. One or more of `napi_property_attributes`. - `[in] data`: User-provided data passed into the method when it is invoked. Returns a `Napi::ClassPropertyDescriptor` object that represents a method provided by instances of the class. The method must be of the form ```cpp void MethodName(const Napi::CallbackInfo& info); ``` ### InstanceMethod Creates a property descriptor that represents a method exposed on JavaScript instances of this class. ```cpp template static Napi::ClassPropertyDescriptor Napi::InstanceWrap::InstanceMethod(const char* utf8name, InstanceMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); ``` - `[in] utf8name`: Null-terminated string that represents the name of the method provided by instances of the class. - `[in] method`: The native function that represents a method provided by the add-on. - `[in] attributes`: The attributes associated with the property. One or more of `napi_property_attributes`. - `[in] data`: User-provided data passed into the method when it is invoked. Returns a `Napi::ClassPropertyDescriptor` object that represents a method provided by instances of the class. The method must be of the form ```cpp Napi::Value MethodName(const Napi::CallbackInfo& info); ``` ### InstanceMethod Creates a property descriptor that represents a method exposed on JavaScript instances of this class. ```cpp template static Napi::ClassPropertyDescriptor Napi::InstanceWrap::InstanceMethod(Napi::Symbol name, InstanceVoidMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); ``` - `[in] name`: JavaScript symbol that represents the name of the method provided by instances of the class. - `[in] method`: The native function that represents a method provided by the add-on. - `[in] attributes`: The attributes associated with the property. One or more of `napi_property_attributes`. - `[in] data`: User-provided data passed into the method when it is invoked. Returns a `Napi::ClassPropertyDescriptor` object that represents a method provided by instances of the class. The method must be of the form ```cpp void MethodName(const Napi::CallbackInfo& info); ``` ### InstanceMethod Creates a property descriptor that represents a method exposed on JavaScript instances of this class. ```cpp template static Napi::ClassPropertyDescriptor Napi::InstanceWrap::InstanceMethod(Napi::Symbol name, InstanceMethodCallback method, napi_property_attributes attributes = napi_default, void* data = nullptr); ``` - `[in] name`: JavaScript symbol that represents the name of the method provided by instances of the class. - `[in] method`: The native function that represents a method provided by the add-on. - `[in] attributes`: The attributes associated with the property. One or more of `napi_property_attributes`. - `[in] data`: User-provided data passed into the method when it is invoked. Returns a `Napi::ClassPropertyDescriptor` object that represents a method provided by instances of the class. The method must be of the form ```cpp Napi::Value MethodName(const Napi::CallbackInfo& info); ``` ### InstanceMethod Creates a property descriptor that represents a method exposed on JavaScript instances of this class. ```cpp