{"_id":"@bravophone/webphone","_rev":"12-44c0767d56115414b0475e16f13e08cd","name":"@bravophone/webphone","dist-tags":{"latest":"0.7.1"},"versions":{"0.1.0":{"name":"@bravophone/webphone","version":"0.1.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.1.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"0b01e2341947555379632b2c554f0d9a0df51bc0","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.1.0.tgz","fileCount":5,"integrity":"sha512-zpPYbkVjL80+Qa3cpr69tp6naZ6i/4Y8D8UUtn2Sx8pvA9bI9XixLD+eod3orCzaU+RKXFcmrxNWpmoi6sFc0A==","signatures":[{"sig":"MEQCIEYjQtDcddk9KFFs1hwNx6XPvEKp8Gny44A9T6KZekIfAiA0qd+VBdD21l3WqCsJcZdymFvCoAAK+ObGvE8+wmq1Zw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88416},"main":"./dist/bravophone.umd.cjs","type":"module","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.cjs","module":"./dist/bravophone.js","browser":"./dist/bravophone.umd.cjs","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.js","require":"./dist/bravophone.umd.cjs"},"./style.css":"./dist/bravophone.css"},"gitHead":"dca43360d3801cb44c1a777a3e1dd5e9e5461191","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs","build":"vite build","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.cjs","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.1.0_1788037587372_0.6186962641672247","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bravophone/webphone","version":"0.1.1","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.1.1","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"331c22d34e078510f645891804c0514817f6b01d","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.1.1.tgz","fileCount":5,"integrity":"sha512-tzZUBNMBns8NSgPLzs4Z+vVx1K6CuzRpytb0e4vj7nDHbL/rS98qNClh0CQTKiiR4XYmcQY0Dxt+PZRRUnZihg==","signatures":[{"sig":"MEUCIQDuW2m7pvTeszA+NWVmjU+An5G2+ph2x5S2agXdagAzRQIgUwn5ANfqBrAl6JN6fR+Fg/+ZCt1LXS+33oavl/ptQEw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88387},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"daae872bace556835577bcb9b38701d32a6b736c","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs","build":"vite build","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.1.1_1788039422208_0.7829457280872598","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@bravophone/webphone","version":"0.1.2","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.1.2","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"20626eb7f50323d8a5b4f024cd481ff8faff4526","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.1.2.tgz","fileCount":5,"integrity":"sha512-sPZmmoHtSMsnACv9uN9yqN/vOImnquEvxZxszN9+owLFs0kkGZokB+wlioFIEzDn/XntsDXtqcxDlMTgD9C7GA==","signatures":[{"sig":"MEUCIQDcYz2DYQ/s12bP2UV3AVuRjxIbkoiDIG3eIig/hjOgfgIgU5QlG7UEIhacKje3RCmtEddIkMJwmBDsrJWqJZ1unxU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88468},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"b141f75549ced32903745f59600f3bb8027e0204","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs","build":"vite build","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.1.2_1788039801983_0.14453335599490846","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bravophone/webphone","version":"0.2.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.2.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"566961c8fb7a4680be84aee89d5bf074e69cd889","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.2.0.tgz","fileCount":84,"integrity":"sha512-/2Stwp/hpq/CMzmRoiSHdfLN/zkChkMdrN8Um5luu/UVOVbOnAxAg1T3NpDrycd99imzVDkeUTgFwJbzM4zXkA==","signatures":[{"sig":"MEYCIQCI7KzIxb+LJrvQNyfbJyI67fH4ZzUBvQA0wvnHeIEu6wIhAP5TgPKdRFChTHe18lh7tiBgAvI6J6+ei7Hy7veqBKXr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3668754},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"868a2923a3efa8f7721dba232a9c1eaafaa390ab","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs","build":"vite build","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.2.0_1788042738962_0.6751573140168519","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bravophone/webphone","version":"0.2.1","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.2.1","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"5b8b6b06143341d0a9bb9cb8be08f6bb21bdac8d","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.2.1.tgz","fileCount":84,"integrity":"sha512-m064M+u/5DPP4T/HAn7zjVjNN2nB5MeZDzbyi3/DTnvjt9eUi1fMycGLZP5s63AWTB80dwnDfemYJ4NTA6dMNg==","signatures":[{"sig":"MEUCIFBw3NxXSIW3Y9HfYR9O/UoIqFJ4mBcuysaOPvLgCGejAiEAob/krxru6rbkyJlcjjLX1I7zk0dlpE/72flLQCQPGgc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3673838},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"8dc00c892802899354c3eb21a52fc980e3b20409","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs","build":"vite build","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.2.1_1788045987795_0.6874489614806902","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bravophone/webphone","version":"0.3.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.3.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"89dd37eda456ff5e34a20629a59eddc425ea8684","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.3.0.tgz","fileCount":84,"integrity":"sha512-YEsox4WCTM2PHkkIb3OKf3NGyAX6IIlAq5EdPtpj6bVAvvtfoQaDRSrBpnGyuQmUJd0KMZWTb5dfijV4raPG0Q==","signatures":[{"sig":"MEUCIHFl6t/eCkBQZ9pSuvyV6KH00a5VugufuWl2V7QOMSSTAiEAxOfS7LCvigg+tddxgp7Gv3+FqriJKOENT6oL3XXuE08=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3677127},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"fc6acdd368a8ec9819f6e58f5c55cdf4e1c0f24f","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.3.0_1788055252061_0.15163167501587949","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@bravophone/webphone","version":"0.4.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.4.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"24acfd43c970ea13a83f1e8659238424b877838a","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.4.0.tgz","fileCount":84,"integrity":"sha512-Lol4frLLs9q5EJ4nNqHkgSGCNKWhfUo3YjIdk0zXPRCp4SvRODJUOg9A+09xiksp6J31VxmKa9SgRAV1Z9cYdw==","signatures":[{"sig":"MEUCIQCGwQt9B7hbSzR7zYlitp6Z2fxCdAAyUDzk0sYensRNlAIgV0q7/q2JbX5hMBHLBsv36mrqbEmH5tllmK6ASYjSB/A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3682858},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"d63f28860bbe91e71e2a7e79da960e1a7e42fe5d","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.4.0_1788059604824_0.8093875104265147","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@bravophone/webphone","version":"0.4.1","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.4.1","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"c0c9c351d3c96e3c3920ac4116be6c995e38edf7","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.4.1.tgz","fileCount":84,"integrity":"sha512-ISGy24o1XHluJPZMChHE3xp9qwhIyFr0AXpHnd5LetQl7Jq0AX4Eizgo9fa4A85qUDFpLQHEDRULgplKf2odEQ==","signatures":[{"sig":"MEUCIQCltoMOpfCP0uGxVBNYiZ0/WXfuwF4umh35XOSV2i9r2QIgX+sAm8BafYLI7KP7nGEt5CJzNRipLGHxYp76xK0fjWU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3684932},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"3866a8f5f503c9682ab39c657788d4483115d395","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.4.1_1788061254309_0.3781216783903161","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bravophone/webphone","version":"0.5.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.5.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"9741e55bc1b2a5e31651a909a8fcd503a2be6e90","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.5.0.tgz","fileCount":87,"integrity":"sha512-ny3PlUAfB7zUd09yk8G2lCwcOVK/Ownvv8aZ93s4dMS4jC2dKCSQ6IxFks/dHP95npu1AK1nnCSzpCwM+F+jQw==","signatures":[{"sig":"MEUCIQCrJXwc7q3RFeMm2zMjxnEGoWi43ZVv5FjybWtuH1CnBgIgDdH38bw2Z/0kp5K3NqlVXdp02/jxP0K6Eag1sfoCGII=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3810873},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"d3c2be1c09d8ea2775f56e9be49a57f275bd8dd8","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-teclado.mjs && node scripts/smoke-campo.mjs && node scripts/smoke-presenca.mjs && node scripts/smoke-acoes.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.5.0_1788136409430_0.16548239726088565","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@bravophone/webphone","version":"0.6.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.6.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"22095103881b88f59d2b99ff967c7ee5301e5b31","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.6.0.tgz","fileCount":88,"integrity":"sha512-0ihcaCVpZUQ1qQdsgroF3QvCfQ0vaMuYHXtErp1M6tdKEqTqx8u5/A1BEppkK0YSBdO1GZFWS7v/jFXM8ntFFg==","signatures":[{"sig":"MEYCIQDy2ZAFUVK58Lo64wx6m8YxKKZHb9RVGGShBThn7NEakQIhAO5tAD6WF+SlxTwX+YW09bS7XkdQuEaOR5EpQml7Yhbr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3841810},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"eefeffc6e4eb88762a2f991b5b4a5a12c6967cfd","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-teclado.mjs && node scripts/smoke-campo.mjs && node scripts/smoke-presenca.mjs && node scripts/smoke-acoes.mjs && node scripts/smoke-audio.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.6.0_1788144027353_0.2345688389257794","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@bravophone/webphone","version":"0.7.0","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"author":{"name":"BravoTech"},"license":"UNLICENSED","_id":"@bravophone/webphone@0.7.0","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"dist":{"shasum":"ab2177f95406e8227427538945409a955d35ecb6","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.7.0.tgz","fileCount":89,"integrity":"sha512-i1NyJ0Y3ewwfMnJ+JDahlhZWkt0ZyUKJosP2LK0Yk1RnpUA4RE9Pnf8KogQsEkouJAnvmP1desr3WRBXL6vpsg==","signatures":[{"sig":"MEUCIQCJZm1XZvYwqRf2oTQZso9sg7Mni99R2AaZGPe8TBLVWQIgUe4ls990JfKzAzy4Oq8ZUOerVBGVf0zkFoUgU3jcbC8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":3850638},"main":"./dist/bravophone.umd.js","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","browser":"./dist/bravophone.umd.js","engines":{"node":">=18"},"exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"gitHead":"6c0f687c296fac96cce576f744e3706ef404fb45","scripts":{"dev":"node scripts/dev-server.mjs","sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-teclado.mjs && node scripts/smoke-campo.mjs && node scripts/smoke-presenca.mjs && node scripts/smoke-acoes.mjs && node scripts/smoke-audio.mjs && node scripts/smoke-janela.mjs && node scripts/smoke-package.mjs","build":"vite build","purge":"node scripts/purge-cdn.mjs","start":"node scripts/dev-server.mjs","build:host":"npm run sync && vite build --config vite.host.config.js","audit:theme":"node scripts/audit-theme.mjs","postpublish":"node scripts/purge-cdn.mjs","prepare:host":"node scripts/sync-from-extension.mjs --cdn","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"jsdelivr":"./dist/bravophone.umd.js","repository":{"url":"git+https://github.com/teambravotech/bravophone-sdk.git","type":"git"},"_npmVersion":"10.9.3","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/webphone_0.7.0_1788146969504_0.746663107214705","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"@bravophone/webphone","version":"0.7.1","description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","main":"./dist/bravophone.umd.js","module":"./dist/bravophone.mjs","types":"./types/index.d.ts","unpkg":"./dist/bravophone.umd.js","jsdelivr":"./dist/bravophone.umd.js","exports":{".":{"types":"./types/index.d.ts","import":"./dist/bravophone.mjs","require":"./dist/bravophone.umd.js"}},"sideEffects":false,"scripts":{"sync":"node scripts/sync-from-extension.mjs && node scripts/audit-theme.mjs","dev":"node scripts/dev-server.mjs","build":"vite build","build:host":"npm run sync && vite build --config vite.host.config.js","test":"node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-sessao.mjs && node scripts/smoke-teclado.mjs && node scripts/smoke-campo.mjs && node scripts/smoke-presenca.mjs && node scripts/smoke-acoes.mjs && node scripts/smoke-audio.mjs && node scripts/smoke-janela.mjs && node scripts/smoke-tema.mjs && node scripts/smoke-qualidade.mjs && node scripts/smoke-package.mjs","start":"node scripts/dev-server.mjs","audit:theme":"node scripts/audit-theme.mjs","prepublishOnly":"npm run prepare:host && npm run build && npm test","prepare:host":"node scripts/sync-from-extension.mjs --cdn","purge":"node scripts/purge-cdn.mjs","postpublish":"node scripts/purge-cdn.mjs"},"keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"license":"UNLICENSED","publishConfig":{"access":"public"},"devDependencies":{"vite":"^5.4.0"},"author":{"name":"BravoTech"},"homepage":"https://github.com/teambravotech/bravophone-sdk#readme","repository":{"type":"git","url":"git+https://github.com/teambravotech/bravophone-sdk.git"},"bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"engines":{"node":">=18"},"browser":"./dist/bravophone.umd.js","_id":"@bravophone/webphone@0.7.1","gitHead":"b852298fddf0e7bbaf0da83e174247c2ca15eb2e","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-LnD+jXKGvnsd0GidbVKIVdjntYSTFjUd0rB9q2nveY049E3zeOu2pi1NSPhIzJnXiORhQWdSK7TJ14jmyXVzfw==","shasum":"01720633f00d4f3f824a2a4c355192b34f771289","tarball":"https://registry.npmjs.org/@bravophone/webphone/-/webphone-0.7.1.tgz","fileCount":94,"unpackedSize":3912637,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAgFcf/gr3KVVz737pZqoJTmxxS1Uh0gqRXU/j/0tb1iAiEAjf0AdTV7cNz0fsyy99Y24A3Vk5L6AXSAa05BsRUIJmE="}]},"_npmUser":{"name":"leo_amaro","email":"la95112@gmail.com"},"directories":{},"maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webphone_0.7.1_1788321928213_0.046032336070139346"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-29T21:06:27.184Z","modified":"2026-09-02T04:05:28.625Z","0.1.0":"2026-08-29T21:06:27.507Z","0.1.1":"2026-08-29T21:37:02.361Z","0.1.2":"2026-08-29T21:43:22.112Z","0.2.0":"2026-08-29T22:32:19.183Z","0.2.1":"2026-08-29T23:26:27.979Z","0.3.0":"2026-08-30T02:00:52.231Z","0.4.0":"2026-08-30T03:13:25.011Z","0.4.1":"2026-08-30T03:40:54.472Z","0.5.0":"2026-08-31T00:33:29.591Z","0.6.0":"2026-08-31T02:40:27.502Z","0.7.0":"2026-08-31T03:29:29.729Z","0.7.1":"2026-09-02T04:05:28.445Z"},"bugs":{"url":"https://github.com/teambravotech/bravophone-sdk/issues"},"author":{"name":"BravoTech"},"license":"UNLICENSED","homepage":"https://github.com/teambravotech/bravophone-sdk#readme","keywords":["webphone","softphone","sip","webrtc","voip","bravophone","widget"],"repository":{"type":"git","url":"git+https://github.com/teambravotech/bravophone-sdk.git"},"description":"Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.","maintainers":[{"name":"leo_amaro","email":"la95112@gmail.com"}],"readme":"# @bravophone/webphone\n\nWebphone BRAVOPHONE embutível em qualquer página web: o softphone aparece como\numa janela flutuante arrastável, com as mesmas funcionalidades da extensão de\nnavegador.\n\n```html\n<script>\n// Resolve a versão publicada e carrega o bundle dela.\n// Duas etapas de propósito: a consulta tem 5 min de cache, o bundle é\n// immutable. Assim as correções chegam em minutos, sem revalidar 30 kB a cada\n// visita — e sem os 7 dias de cache que a URL sem versão carrega.\n// cache:'no-store' na CONSULTA (~1 kB): sem ele, a resposta fica até 5 min\n// no navegador e uma publicação recém-saída não aparece — foi o que exigiu\n// Ctrl+Shift+R nos testes. O bundle continua vindo de cache immutable, então\n// o custo é uma requisição pequena por carregamento, não 30 kB.\nfetch('https://data.jsdelivr.com/v1/packages/npm/@bravophone/webphone/resolved',\n      { cache: 'no-store' })\n  .then((r) => r.json())\n  .then(({ version }) => {\n    const s = document.createElement('script')\n    s.src = `https://cdn.jsdelivr.net/npm/@bravophone/webphone@${version}/dist/bravophone.umd.js`\n    s.onload = () => Bravophone.init({ session: SESSAO_DO_LOGIN })\n    s.onerror = () => console.error('Bravophone: falha ao carregar do CDN')\n    document.head.appendChild(s)\n  })\n</script>\n```\n\nCole **inline**, não como arquivo externo — um arquivo externo teria o mesmo\nproblema de cache que este trecho existe para evitar.\nDetalhes em [Manter o cliente sempre atualizado](#manter-o-cliente-sempre-atualizado).\n\nPara travar numa versão (integração de terceiros, ou build com SRI):\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/@bravophone/webphone@0.3.0/dist/bravophone.umd.js\"></script>\n<script>Bravophone.init({ token: TOKEN_DO_USUARIO })</script>\n```\n\n```js\n// ou via npm\nimport Bravophone from '@bravophone/webphone'\n\nBravophone.init({ token })\nBravophone.on('call:incoming', ({ number }) => console.log('ligação de', number))\nawait Bravophone.call('11987654321')\n```\n\n---\n\n## A decisão de arquitetura\n\nO ponto de partida é uma restrição concreta: **`popup.js` tem 932 KB de build Vue\nminificado e o código-fonte não está disponível.** Recompilar não é uma opção, então\no projeto foi desenhado para **reaproveitar o bundle exatamente como está**.\n\nO levantamento do uso de `chrome.*` no bundle mostrou que isso é viável — a\nsuperfície é pequena e concentrada:\n\n| API | Usos | Tratamento |\n|---|---|---|\n| `chrome.storage.sync` | 58 | shim → `localStorage` |\n| `chrome.storage.local` | 10 | shim → `localStorage` |\n| `chrome.storage.onChanged` | 4 | shim → emissor próprio |\n| `chrome.runtime.onMessage` | 3 | shim → barramento local |\n| `chrome.tabs.create` | 3 | shim → `window.open` |\n| `chrome.windows.*` | 6 | shim → delega ao widget via bridge |\n\nSão **três superfícies reais**, todas sem estado remoto. Um shim de ~230 linhas cobre\ntodas — é o [`host/shim/chrome-shim.js`](host/shim/chrome-shim.js).\n\n### Dois artefatos, não um\n\n```\n┌─ SITE DO CLIENTE (qualquer origem) ────────────────────────┐\n│                                                             │\n│   <script src=\"cdn.../@bravophone/webphone\">                │\n│            │                                                │\n│            ▼                                                │\n│   ┌─ SDK (11 KB) ──────────────────────┐                    │\n│   │  Shadow DOM · janela arrastável    │                    │\n│   │  API pública · ponte postMessage   │                    │\n│   │                                    │                    │\n│   │   ┌─ <iframe srcdoc> ───────────┐  │                    │\n│   │   │  origem: a do próprio site  │  │                    │\n│   │   │  arquivos: CDN (jsDelivr)   │  │                    │\n│   │   │                             │  │                    │\n│   │   │  chrome-shim.js             │  │                    │\n│   │   │  libwebphone.js   (604 KB)  │  │                    │\n│   │   │  popup.js         (932 KB)  │  │  ← bundle intacto  │\n│   │   │  guest-bridge.js            │  │                    │\n│   │   └─────────────────────────────┘  │                    │\n│   └────────────────────────────────────┘                    │\n└─────────────────────────────────────────────────────────────┘\n```\n\n**O SDK no npm/CDN é leve (11 KB / 4,6 KB gzip).** Todo o peso do webphone fica no\nhost e carrega sob demanda, quando o usuário abre a janela.\n\n### Por que iframe, e não montar o Vue direto na página\n\nTestei mentalmente as duas rotas; o iframe ganha em quatro frentes de uma vez:\n\n1. **CSS.** O bundle traz Tailwind + `dark-theme.css` globais. Injetado na página do\n   cliente, ele quebraria o site do cliente — e o CSS do cliente quebraria o webphone.\n2. **CORS, e este é o argumento decisivo.** Dentro do iframe, todo request para\n   `pabx.teambravotech.com` e `devices.wavoip.com` sai com\n   `Origin: https://webphone.bravophone.com` — **uma origem só, fixa**. Sem iframe,\n   cada cliente novo exigiria liberar mais uma origem no CORS de três backends. Com\n   iframe, a lista de origens do backend nunca cresce.\n3. **Microfone.** `allow=\"microphone\"` no iframe é um contrato explícito e auditável.\n4. **Atualização.** Corrigiu algo no webphone? Republique o host. Todos os clientes\n   recebem sem trocar a versão do pacote npm.\n\n---\n\n## O que muda em relação à extensão\n\n### Login: o ponto que exige decisão de produto\n\nEste é o único item que **não** tem solução puramente técnica, e vale ler antes de\ncomeçar.\n\nDesde o Chrome 115, o *storage partitioning* é padrão: o `localStorage` de um iframe\ncross-origin é **particionado pelo site que o contém**. Na prática, um usuário logado\nno webphone em `clienteA.com` **não** estará logado em `clienteB.com` — mesmo sendo o\nmesmo iframe, o mesmo usuário e a mesma origem. A extensão nunca teve esse problema\nporque tinha um storage único.\n\nTrês caminhos, em ordem de recomendação:\n\n1. **Token do integrador (recomendado).** O backend do cliente emite um token de sessão\n   e passa em `Bravophone.init({ token })`. O SDK entrega ao iframe pela ponte e o\n   `guest-bridge` grava onde o bundle já procura (`vxToken`). Sem tela de login, sem\n   depender de cookie de terceiros, e é o modelo que Intercom/Twilio usam. Combina bem\n   com o fato de que [o `vxToken` é eterno](#) — só logout explícito o encerra.\n2. **Login em popup window.** `window.open` para a origem do webphone (contexto\n   *first-party*, sem partição), token volta por `postMessage`. Bom se não houver\n   backend do lado do cliente.\n3. **Storage Access API.** Exige gesto do usuário e o suporte varia entre navegadores.\n   Serve como *fallback*, não como plano principal.\n\nO SDK já implementa o caminho 1 de ponta a ponta.\n\n### Funcionalidades que não portam\n\nOs ~25 `content-script-*.js` (Pipedrive, HubSpot, Kommo, Salesforce…) injetam\nclick-to-call em CRMs de terceiros. **Isso é território exclusivo de extensão** — uma\nbiblioteca só roda onde foi incluída.\n\nA substituição é a inversão do controle: em vez de o Bravophone entrar no CRM, o CRM\nchama o Bravophone.\n\n```js\ndocument.querySelectorAll('[data-phone]').forEach((el) => {\n  el.onclick = () => Bravophone.call(el.dataset.phone, { source: 'crm', id: el.dataset.id })\n})\n```\n\nTambém ficam de fora `contextMenus` (menu de contexto do navegador), `devtools.js` e a\nleitura de clipboard sem gesto do usuário.\n\n### O que se mantém idêntico\n\nRegistro SIP, áudio WebRTC, supressão de ruído, seleção de rota, histórico, contatos,\ntransferência, DTMF, e a **normalização de número** — inclusive a regra de\n[nunca inserir o 9º dígito](#): `dialpad.call()` continua sendo o funil único de\nligações, então toda essa lógica é exatamente a mesma da extensão.\n\n---\n\n## Estrutura\n\n```\nBravophone-SDK/\n├── src/                    ← vira o pacote npm (11 KB)\n│   ├── index.js              API pública + registro de eventos\n│   ├── widget.js             Shadow DOM, iframe, launcher\n│   ├── draggable.js          arraste/resize com Pointer Events + persistência\n│   ├── bridge.js             RPC postMessage (lado host)\n│   └── styles.js             CSS isolado do widget\n│\n├── host/                   ← vira webphone.bravophone.com (RAIZ do domínio)\n│   ├── index.html            gerado pelo sync (ordem de scripts importa)\n│   ├── shim/chrome-shim.js   emula chrome.* para o bundle\n│   ├── shim/guest-bridge.js  RPC (lado iframe) + eventos + arraste interno\n│   ├── allowed-origins.json  origens autorizadas a embutir\n│   ├── popup.js  js/  css/   ┐ copiados da extensão pelo sync,\n│   ├── fonts/  images/       ┘ na RAIZ — não versionados (ver abaixo)\n│   ├── mock.html             ┐ só desenvolvimento:\n│   └── mock-webphone.js      ┘ webphone falso, sem SIP nem backend\n│\n├── scripts/\n│   ├── sync-from-extension.mjs   copia os assets da extensão\n│   ├── dev-server.mjs            duas origens locais (5173 / 5174)\n│   └── smoke-shim.mjs            testes do chrome-shim\n├── types/index.d.ts\n└── examples/\n    ├── test.html             painel de teste completo (usa o build UMD)\n    └── basic.html            exemplo mínimo de integração\n```\n\n**A extensão é a fonte da verdade.** Nada copiado é editado à mão. Quando a extensão\nfor atualizada:\n\n```bash\nnpm run sync          # host servido de um domínio próprio (public path \"/\")\nnpm run prepare:host  # host servido do CDN — é o que vai no pacote publicado\n```\n\nO `prepare:host` reescreve o `public_path` do bundle para\n`cdn.jsdelivr.net/npm/@bravophone/webphone@<versão>/host/`. **Rode-o depois de\ncada bump de versão e antes de publicar**: se a URL apontar para outra versão,\no pacote busca assets que podem não existir. O `npm test` recusa esse\ndescompasso.\n\nO script recusa rodar se um asset obrigatório sumir, em vez de gerar um host quebrado\nsilenciosamente.\n\n### Por que os assets ficam na raiz de `host/`, e não num `vendor/`\n\nO bundle foi buildado com `__webpack_public_path__ = \"/\"`. Duas fontes são resolvidas\npor esse caminho absoluto:\n\n```js\nn.p + \"fonts/Audiowide-Regular.ttf\"   // Audiowide — a fonte da marca\nn.p + \"fonts/Seguiemj.ttf\"            // SegoeUIEmoji — os emojis\n```\n\nSob um subdiretório, esses dois pedidos dão 404 e o navegador cai no fallback\nsilenciosamente — sem erro visível, só a tipografia errada, e justamente **depois do\nlogin**, que é onde a Audiowide aparece. Replicar o layout de URL da extensão faz tudo\nresolver sem tocar no bundle: `npm run sync` termina verificando que as duas fontes\naterrissaram em `/fonts/`, e falha alto se não.\n\n**Consequência de deploy:** o host precisa ficar na **raiz** de um domínio ou\nsubdomínio. Para servir sob um subpath, use\n`npm run sync -- --public-path=/embed/` — troca só essa constante no bundle, de forma\ndeterminística e refeita a cada sync (e aborta se não encontrar exatamente uma\nocorrência, em vez de adivinhar).\n\n---\n\n## Desenvolvimento\n\n### Pré-requisito: a extensão ao lado\n\nEste repositório **não versiona o webphone** — só o SDK e a camada que faz o bundle da\nextensão rodar fora dela. O `popup.js` (932 KB), o `libwebphone.js`, as fontes e os\n`_locales` são copiados da extensão pelo `npm run sync` e ficam fora do git.\n\nClone os dois como irmãos:\n\n```\nalgum-diretorio/\n├── Bravophone/       ← a extensão (fonte da verdade do webphone)\n└── bravophone-sdk/   ← este repositório\n```\n\n```bash\ngit clone https://github.com/teambravotech/bravophone-sdk.git\ncd bravophone-sdk\nnpm install\nnpm run sync      # copia os assets da extensão irmã\nnpm run build     # gera dist/ (ESM + UMD + sourcemaps)\nnpm start         # sobe as duas origens de teste\n```\n\nSe a extensão estiver em outro lugar, passe o caminho:\n`npm run sync -- /caminho/para/Bravophone`.\n\nSem o `sync`, o host não tem o que servir — `npm start` sobe, mas o webphone real não\ncarrega (o mock em `?host=mock` continua funcionando).\n\n### Scripts\n\n| Script | O que faz |\n|---|---|\n| `npm run sync` | Copia os assets da extensão, gera `host/index.html` e `shim/messages.js`, e roda a auditoria de tema |\n| `npm run build` | Gera `dist/` — o que vai para o npm |\n| `npm start` | Sobe as duas origens locais (5173 site, 5174 host) |\n| `npm test` | 100 asserções: shim, geometria da janela e aba de abertura |\n| `npm run audit:theme` | Procura texto invisível no tema escuro |\n| `npm run purge` | Limpa o cache do CDN nas URLs sem versão fixa (roda sozinho após o publish) |\n\nAbra **http://localhost:5173/**.\n\nO `npm start` sobe duas portas de propósito — origens diferentes fazem o teste\nexercitar o postMessage cross-origin de verdade, incluindo a validação de origem:\n\n| Porta | Papel | Serve |\n|---|---|---|\n| 5173 | site do cliente | `examples/test.html`, carrega `dist/bravophone.umd.js` por `<script>`, como no CDN |\n| 5174 | host do webphone | `host/mock.html`, com os headers `frame-ancestors` e `Permissions-Policy` de produção |\n\n### Testar sem SIP nem backend\n\nO `host/mock.html` carrega **o `chrome-shim.js` e o `guest-bridge.js` reais** e troca\nsó o bundle por [`host/mock-webphone.js`](host/mock-webphone.js), que expõe os mesmos\ndois handles que o guest-bridge procura (`window.dialpad` e `window.libwebphone`).\nOu seja: o caminho testado é o de produção, sem depender de registro SIP.\n\nDá para verificar ponta a ponta o arraste e o resize, a persistência da posição, os\ncomandos (`call`/`hangup`/`mute`/`transfer`…), os eventos de volta, uma chamada\nentrante abrindo a janela sozinha, e o `init({ token })` chegando ao storage via shim —\no painel do mock mostra o `vxToken` gravado.\n\nPara testar contra o **webphone real**, rode `npm run sync` e aponte o `hostUrl` do\n`examples/test.html` para `http://localhost:5174/index.html` em vez de `mock.html`.\n\n```bash\nnpm test          # 18 asserções sobre o chrome-shim, sem browser\n```\n\n---\n\n## Deploy\n\n### 1. Host — `webphone.bravophone.com` (raiz)\n\nEstático (S3+CloudFront, Vercel, nginx). Três headers importam:\n\n```\nContent-Security-Policy: frame-ancestors 'self' https://clienteA.com https://clienteB.com;\nPermissions-Policy: microphone=(self)\nCross-Origin-Opener-Policy: same-origin-allow-popups\n```\n\n`frame-ancestors` é o que impede qualquer site de embutir o webphone — deve ser gerado\na partir de `allowed-origins.json`. É a mesma disciplina de\n[autorização por origem](#) que a extensão já adota; não troque por `*`.\n\nCache: `popup.js`, `js/*`, `fonts/*` com `max-age=31536000` (invalide o CDN a cada\nsync, ou versione por query string); `index.html` sempre com `no-cache`.\n\n### 2. Backends — CORS\n\nLiberar **uma única origem** em `api.bravophone.com`, `pabx.teambravotech.com` e\n`devices.wavoip.com`:\n\n```\nAccess-Control-Allow-Origin: https://webphone.bravophone.com\nAccess-Control-Allow-Credentials: true\n```\n\nComo o iframe tem origem fixa, essa lista não cresce com o número de clientes.\n\n### 3. npm\n\n```bash\nnpm publish --access public\n```\n\nDisponível em `cdn.jsdelivr.net/npm/@bravophone/webphone` e `unpkg.com` logo após.\nRecomende aos integradores a versão travada — `@bravophone/webphone@0.1` — para que\num major não quebre a página deles.\n\n---\n\n## Manter o cliente sempre atualizado\n\nA intuição diz para usar a URL sem versão. **É a pior escolha para isso**, e os\nheaders do CDN mostram por quê:\n\n```\nsem versão / @0.2   →  max-age=604800   (7 dias no navegador do usuário)\n@0.2.1 exata        →  immutable        (eterno, mas fixo)\n```\n\nA URL sem versão é entregue com sete dias de cache **na máquina de quem\nacessa**. Publicar uma correção não alcança essa pessoa: `npm run purge` limpa\nas bordas do CDN, não o cache que já está no navegador dela.\n\nO caminho que resolve é [`examples/loader-latest.js`](examples/loader-latest.js),\nque separa as duas coisas:\n\n1. pergunta ao CDN qual é a versão atual — resposta com **5 min** de cache;\n2. carrega o bundle daquela versão **exata** — URL imutável, cache eterno.\n\nUma publicação chega em até cinco minutos, e o arquivo pesado vem de um cache\nque nunca precisa ser revalidado. O custo é uma requisição de ~1 kB antes do\nbundle, quase sempre servida do cache.\n\n```js\nconst { version } = await (await fetch(\n  'https://data.jsdelivr.com/v1/packages/npm/@bravophone/webphone/resolved'\n)).json()\n\nconst s = document.createElement('script')\ns.src = `https://cdn.jsdelivr.net/npm/@bravophone/webphone@${version}/dist/bravophone.umd.js`\ndocument.head.appendChild(s)\n```\n\nCole isso **inline** na página, não como arquivo externo — um arquivo externo\nteria o mesmo problema de cache que estamos evitando.\n\n### Se uma publicação não aparecer\n\nTrês caches diferentes, do mais provável ao menos:\n\n| O que está velho | Como saber | Solução |\n|---|---|---|\n| **A consulta de versão** | `Bravophone.version` mostra a anterior | Já resolvido: o snippet usa `cache: 'no-store'` |\n| **A página do integrador** | o próprio snippet mudou e não teve efeito | Não sirva o HTML com `max-age` longo |\n| **O bundle** | — | Não acontece: a URL é versionada e `immutable` |\n\nDurante o desenvolvimento, `Ctrl+Shift+R` limpa os três de uma vez — foi o que\nfuncionou nos primeiros testes. Em produção não há como pedir isso ao usuário,\ne é por isso que o `no-store` está na consulta: sem ele, quem carregou a página\nnos últimos cinco minutos continua na versão anterior.\n\nSe ainda assim algo ficar para trás, `npm run purge` limpa as bordas do CDN —\nmas lembre que ele não alcança o navegador de ninguém.\n\nOs assets do webphone acompanham automaticamente: o `public_path` é gravado com\na versão do pacote, então carregar o SDK 0.2.1 carrega o host 0.2.1.\n\n## A sessão que o webphone espera\n\n`init()` recebe a resposta do `/api/voxfree/login` inteira:\n\n```js\nBravophone.init({\n  session: {\n    vxToken:    '…',   // obrigatório\n    expiresIn:  3600,  // segundos\n    sip:        '…',   // sem isto o webphone não registra\n    ramal:      '…',   // idem\n    tenant:     '…',\n    clienteId:  '…',\n    ramaisUrl:  '…',\n\n    // A segunda metade: sem ela o app fica na tela de login, mesmo com o\n    // vxToken válido. O checkToken do webphone exige as duas.\n    extension: { username: '…', password: '…', server: '…' },\n  },\n})\n```\n\n**Onde a credencial SIP fica.** O `extension` viaja apenas pela ponte\n(`postMessage`) e é aplicado no store em memória do webphone. Ele **não** entra\nno HTML do iframe nem no `localStorage` — a senha não fica legível no DOM da sua\npágina. As outras sete chaves são pré-gravadas no storage, porque é de lá que o\nbundle as lê.\n\nO SDK grava essas chaves onde o bundle as procura, **antes** dele avaliar — a\nsessão já sobe autenticada, sem piscar a tela de login.\n\n`token: '…'` continua aceito como atalho para `{ vxToken }`, mas **sozinho não\nbasta**: o webphone carrega, não registra, e o RouteSelector avisa \"faça login\npelo webphone\" — justamente o que a auto-autenticação existe para evitar.\n\n## Documentação\n\n| Documento | Para quem |\n|---|---|\n| [`docs/api.html`](docs/api.html) | Referência completa da API — abra no navegador |\n| [`docs/PARA-IA.md`](docs/PARA-IA.md) | Contexto para um agente de IA implementar a integração |\n| [`examples/integracao.html`](examples/integracao.html) | Exemplo pronto para colar numa página |\n| [`examples/loader.js`](examples/loader.js) | Carregar o SDK por JavaScript (SPA, Tag Manager) |\n\n## API\n\n### `Bravophone.init(options)`\n\n| Opção | Tipo | Padrão | Descrição |\n|---|---|---|---|\n| `token` | `string` | — | Token de sessão emitido pelo seu backend |\n| `mode` | `'srcdoc' \\| 'hosted'` | `'srcdoc'` | Como o webphone é carregado — ver abaixo |\n| `hostUrl` | `string` | `https://webphone.bravophone.com/` | Origem do webphone (só no modo `hosted`) |\n| `position` | `string` | `'bottom-right'` | Canto inicial |\n| `open` | `boolean` | `false` | Abrir já visível |\n| `launcher` | `boolean` | `true` | Exibir a aba lateral de abertura |\n| `launcherSide` | `'right' \\| 'left'` | `'right'` | Lado em que a aba fica colada |\n| `frame` | `'none' \\| 'bar'` | `'none'` | Moldura da janela — ver abaixo |\n| `dockTop` | `'max' \\| 'top-half'` | `'max'` | O que arrastar até a borda superior faz |\n| `title` | `string` | `'BRAVOPHONE'` | Texto da barra (só com `frame: 'bar'`) |\n\n### Moldura: preservando 100% da UI\n\nPor padrão (`frame: 'none'`) **não há barra de título** — a UI do `popup.js` ocupa a\njanela inteira, exatamente como na extensão. Nenhum pixel é tomado.\n\nO arraste continua funcionando porque a detecção do gesto acontece **dentro** do\niframe, no `guest-bridge.js`: o host é cross-origin e não pode tocar naquele DOM, então\no gesto viaja como delta pela ponte. Qualquer área que não seja botão, campo ou link\narrasta a janela; o resto continua clicável, e uma seleção de texto em andamento nunca\né sequestrada. As coordenadas usam `screenX/screenY` — absolutas na tela, imunes ao\nfato de o próprio iframe estar se movendo durante o arraste.\n\nUm botão de fechar aparece sobreposto no canto ao passar o mouse, sem empurrar o\nconteúdo. Recolher para o launcher faz o papel de minimizar.\n\nUse `frame: 'bar'` se preferir a barra com título, indicador de estado e controles.\n\n### Métodos\n\n**Janela** — `show()` · `hide()` · `toggle()` · `minimize(force?)` · `move(x, y)` ·\n`resize(w, h)` · `dock(zone)` · `destroy()` · `isOpen` · `geometry`\n\n### Dois modos de carregar o webphone\n\n```js\nBravophone.init({ token })                     // hospedado (padrão)\nBravophone.init({ token, mode: 'srcdoc' })     // na origem do próprio site\n```\n\n| | `srcdoc` (padrão) | `hosted` |\n|---|---|---|\n| Onde o iframe roda | `webphone.bravophone.com` | origem do próprio site |\n| De onde vêm os arquivos | do host | do CDN, travados nesta versão |\n| CORS dos backends | uma origem fixa, não cresce | **uma entrada por integrador** |\n| Iframe de terceiro | sim — sujeito a bloqueador e política | não |\n| Storage particionado | sim (login por site do cliente) | não |\n| Você precisa manter | o domínio do host | nada |\n\n**Antes de oferecer o `srcdoc` a um cliente, a origem dele precisa estar na\nallowlist de CORS de `api.bravophone.com`, `pabx.teambravotech.com` e\n`devices.wavoip.com`.** Sem isso o webphone carrega, aparece na tela e não\nregistra — o navegador descarta as respostas. Isso é trabalho no **nosso**\nbackend: o integrador não tem como liberar CORS de um servidor que não é dele.\n\nHá requests com `withCredentials`, então `Access-Control-Allow-Origin: *` não\nserve: a resposta precisa ecoar a origem exata mais\n`Access-Control-Allow-Credentials: true`. O caminho sustentável é a allowlist\nsair de banco, para entrar um cliente ser um registro e não um deploy em três\nserviços.\n\nDo lado do integrador, o único requisito é o CSP admitir `cdn.jsdelivr.net` em\n`script-src`, `style-src` e `font-src` — a maioria dos sites não tem CSP\nrestritivo e não precisa fazer nada.\n\nO que foi verificado em navegador (`examples/srcdoc-validation.html`):\n`getUserMedia` funciona dentro do `srcdoc` **sem `allow=`**, a permissão é\nherdada do topo, `enumerateDevices` traz os rótulos, `localStorage` funciona,\n`document.baseURI` resolve para a página pai e `@font-face` com URL absoluta do\nCDN carrega.\n\n### A aba de abertura\n\nCom a janela fechada, o webphone fica acessível por uma **aba colada na lateral** da\nviewport — não um botão circular solto no canto. Ela é arrastável na vertical e\nguarda a posição entre sessões.\n\nNo repouso mostra só o ícone. No **hover** (ou com foco de teclado) ela expande e\nrevela a alça de pontinhos, sinalizando que dá para arrastar.\n\nUm detalhe que decide se o componente é agradável ou irritante: **arrastar não abre o\nwebphone**. O gesto vira arraste depois de 4px percorridos; abaixo disso continua sendo\nclique. Sem esse limiar, uma tremida de mouse no clique abriria a janela sem querer —\nou pior, todo arraste terminaria abrindo.\n\nA aba também responde a teclado (`Enter` / `Espaço`) e, numa chamada entrante, pulsa em\nvermelho com o contador — visível mesmo com a janela fechada.\n\n```js\nBravophone.init({ launcherSide: 'left' })   // cola do outro lado\nBravophone.setLauncherSide('right')         // troca em runtime\nBravophone.init({ launcher: false })        // sem aba: você controla com show()\n```\n\n### Redimensionar e encaixar\n\nA janela redimensiona por **qualquer borda ou canto** — as alças laterais são o que\npermite alargar a janela para o histórico de chamadas respirar. O teto é a viewport,\nnão um valor fixo.\n\nDois comportamentos de encaixe, ambos com o mesmo vocabulário do Canva:\n\n**Arrastando**, encostar numa região da viewport mostra uma prévia azul do encaixe\nantes de soltar:\n\n| Onde o cursor chega | Encaixe |\n|---|---|\n| borda esquerda / direita | altura cheia, largura mantida |\n| **borda inferior** | **metade inferior, largura cheia** |\n| borda superior | maximizado (configurável) |\n| os quatro cantos | meia tela esquerda/direita |\n| qualquer outro lugar | segue flutuando |\n\n```\n left-half │    max     │ right-half\n ──────────┼────────────┼──────────\n   left    │  (flutua)  │   right\n ──────────┼────────────┼──────────\n left-half │bottom-half │ right-half\n```\n\nA borda superior é a única disputada: `max` é o gesto universal (Windows, macOS), mas\nquem trabalha com metades verticais costuma preferir a metade de cima ali. Daí a opção\n`dockTop`:\n\n```js\nBravophone.init({ dockTop: 'top-half' })   // topo encaixa na metade superior\n```\n\nCom ela, o máximo continua acessível por `dock('max')`.\n\nArrastar uma janela encaixada de volta para o meio a solta e devolve o tamanho que ela\ntinha antes — e a janela nasce **sob o cursor**, proporcional a onde você a pegou, em\nvez de saltar.\n\n**Redimensionando**, chegar a ~32px de uma borda da viewport completa até ela\nsozinha — o \"completamento sugestivo\".\n\nProgramaticamente:\n\n```js\nBravophone.dock('right')        // altura cheia à direita, largura mantida\nBravophone.dock('right-half')   // metade direita  (W/2 × altura cheia)\nBravophone.dock('bottom-half')  // metade inferior (largura cheia × H/2)\nBravophone.dock('top-half')     // metade superior\nBravophone.dock('bottom')       // metade inferior, mantendo a largura atual\nBravophone.dock('max')          // maximiza\nBravophone.dock('float')        // solta e restaura o tamanho anterior\n\nBravophone.on('resize', ({ width, height, dock }) => { /* … */ })\n```\n\nO encaixe persiste entre sessões e é **recalculado para a viewport atual** ao recarregar\n— uma janela docada ontem numa tela larga não volta com a geometria de ontem.\n\n**Telefonia** — todos retornam `Promise`:\n`call(number, meta?)` · `hangup()` · `answer()` · `mute(on?)` · `hold(on?)` ·\n`sendDTMF(tone)` · `transfer(to)` · `getStatus()` · `setAuth(token)` · `logout()`\n\n### Eventos\n\n```js\nconst off = Bravophone.on('call:incoming', (call) => { /* … */ })\noff()  // remove o listener\n```\n\n`ready` · `state` · `call:dialing` · `call:incoming` · `call:answered` ·\n`call:ended` · `resize` · `reveal` · `open` · `close` · `error`.\nUse `'*'` para receber todos como `{ event, payload }`.\n\nUma chamada que não completa chega como `call:ended`: o estado do bundle não\ndistingue desligar de falhar.\n\n---\n\n## Requisitos\n\n- **HTTPS obrigatório** no site do cliente — `getUserMedia` só existe em *secure\n  context*. `localhost` funciona no desenvolvimento; o SDK avisa no console se detectar\n  contexto inseguro.\n- Navegadores com WebRTC e Shadow DOM: Chrome/Edge 88+, Firefox 90+, Safari 14+.\n- O site do cliente **não** pode ter um CSP `frame-src` que bloqueie\n  `webphone.bravophone.com` — vale documentar isso no onboarding.\n\n---\n\n## Licença\n\nSoftware proprietário da **BravoTech**. Todos os direitos reservados.\nO pacote npm é publicado para consumo pelos integradores; o código deste repositório\nnão é open source.\n","readmeFilename":"README.md"}