@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.
@@ -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
- // Sessão do integrador: grava onde o bundle procura o token.
139
- if (!p || !p.token) throw new Error('token ausente')
140
- return new Promise(function (resolve) {
141
- chrome.storage.local.set({ vxToken: p.token }, function () {
142
- chrome.storage.sync.set({ vxToken: p.token }, function () { resolve({ ok: true }) })
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(['vxToken'], function () {
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.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
- /** Token de sessão do usuário, emitido pelo backend do integrador. */
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(token: string): Promise<{ ok: true }>
198
+ setAuth(session: BravophoneSession | string): Promise<{ ok: true }>
159
199
  logout(): Promise<{ ok: true }>
160
200
 
161
201
  on<K extends keyof BravophoneEvents>(