@bravophone/webphone 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -5
- package/dist/bravophone.mjs +306 -273
- package/dist/bravophone.umd.js +40 -21
- package/host/js/bravophone-route-selector.js +1 -1
- package/host/popup.js +3 -3
- package/host/shim/guest-bridge.js +37 -8
- package/package.json +2 -2
- package/types/index.d.ts +42 -2
|
@@ -134,21 +134,50 @@
|
|
|
134
134
|
|
|
135
135
|
// --- comandos aceitos do site hospedeiro ---
|
|
136
136
|
var commands = {
|
|
137
|
+
// As chaves saem do bpSaveSession do bundle — é ele quem define os nomes.
|
|
138
|
+
// Gravar 'vxToken' não serve para nada: ninguém lê essa chave.
|
|
137
139
|
auth: function (p) {
|
|
138
|
-
|
|
139
|
-
if (!
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
var s = (p && p.session) || (p && p.token ? { vxToken: p.token } : null)
|
|
141
|
+
if (!s || !s.vxToken) throw new Error('sessão ausente (precisa ao menos de vxToken)')
|
|
142
|
+
|
|
143
|
+
var dados = {
|
|
144
|
+
bravophoneVxToken: s.vxToken,
|
|
145
|
+
bravophoneVxTokenExpiresAt: s.expiresIn
|
|
146
|
+
? Date.now() + 1000 * Number(s.expiresIn) : null,
|
|
147
|
+
bravophoneSip: s.sip || null,
|
|
148
|
+
bravophoneTenant: s.tenant || null,
|
|
149
|
+
bravophoneRamal: s.ramal || null,
|
|
150
|
+
bravophoneClienteId: s.clienteId || null,
|
|
151
|
+
bravophoneRamaisUrl: s.ramaisUrl || null,
|
|
152
|
+
}
|
|
153
|
+
Object.keys(dados).forEach(function (k) { if (dados[k] === null) delete dados[k] })
|
|
154
|
+
|
|
155
|
+
return new Promise(function (resolve, reject) {
|
|
156
|
+
chrome.storage.local.set(dados, function () {
|
|
157
|
+
// O ramal NÃO vai para o storage: o bundle o mantém apenas no store
|
|
158
|
+
// Vuex (mutation addExtension), em memória. E o checkToken exige as
|
|
159
|
+
// DUAS metades — `vxToken` da sessão E `extension` com username e
|
|
160
|
+
// password. Só a sessão deixa o app na tela de login.
|
|
161
|
+
if (!s.extension) return resolve({ ok: true, extension: false })
|
|
162
|
+
|
|
163
|
+
waitFor(findStore, 20000).then(function (store) {
|
|
164
|
+
// Depois da sessão gravada, de propósito: a mutation relê o
|
|
165
|
+
// storage para decidir se está logado.
|
|
166
|
+
store.commit('addExtension', s.extension)
|
|
167
|
+
resolve({ ok: true, extension: true })
|
|
168
|
+
}).catch(function (err) {
|
|
169
|
+
reject(new Error('sessão gravada, mas o ramal não pôde ser aplicado: ' + err.message))
|
|
170
|
+
})
|
|
143
171
|
})
|
|
144
172
|
})
|
|
145
173
|
},
|
|
146
174
|
|
|
147
175
|
logout: function () {
|
|
176
|
+
var CHAVES = ['bravophoneVxToken', 'bravophoneVxTokenExpiresAt', 'bravophoneSip',
|
|
177
|
+
'bravophoneTenant', 'bravophoneRamal', 'bravophoneClienteId',
|
|
178
|
+
'bravophoneRamaisUrl']
|
|
148
179
|
return new Promise(function (resolve) {
|
|
149
|
-
chrome.storage.local.remove(
|
|
150
|
-
chrome.storage.sync.remove(['vxToken'], function () { resolve({ ok: true }) })
|
|
151
|
-
})
|
|
180
|
+
chrome.storage.local.remove(CHAVES, function () { resolve({ ok: true }) })
|
|
152
181
|
})
|
|
153
182
|
},
|
|
154
183
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bravophone/webphone",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Webphone BRAVOPHONE embutível em qualquer página web. Renderiza uma janela flutuante arrastável com todas as funcionalidades do softphone.",
|
|
5
5
|
"main": "./dist/bravophone.umd.js",
|
|
6
6
|
"module": "./dist/bravophone.mjs",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dev": "node scripts/dev-server.mjs",
|
|
28
28
|
"build": "vite build",
|
|
29
29
|
"build:host": "npm run sync && vite build --config vite.host.config.js",
|
|
30
|
-
"test": "node scripts/smoke-shim.mjs && node scripts/smoke-geometry.mjs && node scripts/smoke-launcher.mjs && node scripts/smoke-package.mjs",
|
|
30
|
+
"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",
|
|
31
31
|
"start": "node scripts/dev-server.mjs",
|
|
32
32
|
"audit:theme": "node scripts/audit-theme.mjs",
|
|
33
33
|
"prepublishOnly": "npm run build && npm test",
|
package/types/index.d.ts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
export type LauncherIcon = 'phone-waves' | 'waveform' | 'headset' | 'chat-phone'
|
|
2
2
|
|
|
3
|
+
/** Resposta do `/api/voxfree/login`, repassada como está. */
|
|
4
|
+
export interface BravophoneSession {
|
|
5
|
+
vxToken: string
|
|
6
|
+
/** Segundos até expirar; vira `bravophoneVxTokenExpiresAt`. */
|
|
7
|
+
expiresIn?: number
|
|
8
|
+
sip?: string
|
|
9
|
+
tenant?: string
|
|
10
|
+
ramal?: string
|
|
11
|
+
clienteId?: string
|
|
12
|
+
ramaisUrl?: string
|
|
13
|
+
/**
|
|
14
|
+
* O ramal SIP, como vem do `/api/voxfree/login`. **Obrigatório para
|
|
15
|
+
* registrar**: o `checkToken` do webphone exige as duas metades — o
|
|
16
|
+
* `vxToken` da sessão E um `extension` com `username` e `password`. Só a
|
|
17
|
+
* sessão deixa o app parado na tela de login.
|
|
18
|
+
*
|
|
19
|
+
* Onde ele fica: o SDK o envia apenas pela ponte (postMessage) e o aplica
|
|
20
|
+
* no store em memória do webphone. Nunca entra no HTML do iframe nem no
|
|
21
|
+
* localStorage — a credencial SIP não fica legível no DOM da sua página.
|
|
22
|
+
*/
|
|
23
|
+
extension?: {
|
|
24
|
+
username: string
|
|
25
|
+
password: string
|
|
26
|
+
server?: string
|
|
27
|
+
authID?: string
|
|
28
|
+
displayName?: string
|
|
29
|
+
label?: string
|
|
30
|
+
[k: string]: unknown
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
3
34
|
export interface BravophoneOptions {
|
|
4
35
|
/** Origem do webphone hospedado. Só usado com `mode: 'hosted'`. */
|
|
5
36
|
hostUrl?: string
|
|
@@ -23,7 +54,16 @@ export interface BravophoneOptions {
|
|
|
23
54
|
* assets de um espelho próprio.
|
|
24
55
|
*/
|
|
25
56
|
hostBase?: string
|
|
26
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Sessão do `/api/voxfree/login`, repassada inteira. É o caminho correto:
|
|
59
|
+
* o webphone precisa de `sip` e `ramal` para registrar.
|
|
60
|
+
*/
|
|
61
|
+
session?: BravophoneSession
|
|
62
|
+
/**
|
|
63
|
+
* Atalho para `{ vxToken: token }`. **Sozinho não basta** — sem `sip` e
|
|
64
|
+
* `ramal` o webphone carrega, não registra, e o RouteSelector avisa
|
|
65
|
+
* "faça login pelo webphone".
|
|
66
|
+
*/
|
|
27
67
|
token?: string
|
|
28
68
|
/** Canto inicial da janela. Padrão: 'bottom-right'. */
|
|
29
69
|
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
|
|
@@ -155,7 +195,7 @@ export interface BravophoneAPI {
|
|
|
155
195
|
sendDTMF(tone: string): Promise<{ ok: true }>
|
|
156
196
|
transfer(to: string): Promise<{ ok: true }>
|
|
157
197
|
getStatus(): Promise<PhoneStatus>
|
|
158
|
-
setAuth(
|
|
198
|
+
setAuth(session: BravophoneSession | string): Promise<{ ok: true }>
|
|
159
199
|
logout(): Promise<{ ok: true }>
|
|
160
200
|
|
|
161
201
|
on<K extends keyof BravophoneEvents>(
|