@beworke/pixel 0.1.0-rc.13 → 0.1.0-rc.15

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/browser/index.cjs.js +1 -1
  3. package/dist/browser/index.cjs.js.map +1 -1
  4. package/dist/browser/index.esm.js +1 -1
  5. package/dist/browser/index.esm.js.map +1 -1
  6. package/dist/browser/pixel.buygoods-checkout.global.js +1 -1
  7. package/dist/browser/pixel.buygoods-checkout.global.js.map +1 -1
  8. package/dist/browser/pixel.buygoods-landing.global.js +1 -1
  9. package/dist/browser/pixel.buygoods-landing.global.js.map +1 -1
  10. package/dist/browser/pixel.global.js +1 -1
  11. package/dist/browser/pixel.global.js.map +1 -1
  12. package/dist/browser/pixel.internal-checkout.global.js +1 -1
  13. package/dist/browser/pixel.internal-checkout.global.js.map +1 -1
  14. package/dist/events/index.cjs.js +1 -1
  15. package/dist/events/index.esm.js +1 -1
  16. package/dist/examples/html-script/README.md +11 -0
  17. package/dist/examples/html-script/customer/README.md +29 -0
  18. package/dist/examples/html-script/customer/example-customer-css.html +383 -0
  19. package/dist/examples/html-script/customer/example-customer-defaults.html +408 -0
  20. package/dist/examples/html-script/customer/example-customer-events.html +428 -0
  21. package/dist/examples/html-script/customer/example-customer-extra-fields.html +385 -0
  22. package/dist/index.cjs.js +1 -1
  23. package/dist/index.cjs.js.map +1 -1
  24. package/dist/index.esm.js +1 -1
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/runtime/index.cjs.js +1 -1
  27. package/dist/runtime/index.cjs.js.map +1 -1
  28. package/dist/runtime/index.esm.js +1 -1
  29. package/dist/runtime/index.esm.js.map +1 -1
  30. package/dist/services/index.cjs.js +1 -1
  31. package/dist/services/index.cjs.js.map +1 -1
  32. package/dist/services/index.esm.js +1 -1
  33. package/dist/services/index.esm.js.map +1 -1
  34. package/dist/v2/global.global.js +1 -1
  35. package/dist/v2/global.global.js.map +1 -1
  36. package/dist/v2/index.cjs.js +1 -1
  37. package/dist/v2/index.cjs.js.map +1 -1
  38. package/dist/v2/index.esm.js +1 -1
  39. package/dist/v2/index.esm.js.map +1 -1
  40. package/docs/public/configuration/commerce.md +3 -1
  41. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
1
  /* Pixel v2 — SDK de analytics e conversão */
2
- "use strict";var c=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var h=(r,e)=>{for(var n in e)c(r,n,{get:e[n],enumerable:!0})},v=(r,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of g(e))!E.call(r,s)&&s!==n&&c(r,s,{get:()=>e[s],enumerable:!(a=y(e,s))||a.enumerable});return r};var C=r=>v(c({},"__esModule",{value:!0}),r);var S={};h(S,{BaseEventBuilder:()=>o});module.exports=C(S);function i(r){return r?Object.values(r).some(e=>typeof e=="string"&&e.trim().length>0):!1}var o=class{constructor(e,n,a,s){this.metadataService=e,this.attribution=n??null,this.urlContext=a??null,this.customerIdentity=s??null}build(e){let n=this.metadataService.getMetadata(),a=this.attribution?.getSnapshot(),s=a!==void 0&&Object.keys(a).some(f=>{let u=a[f];return u!=null&&u!==""}),t=this.urlContext?.isEnabled()?this.urlContext.getSnapshot():null,d=t!==null&&Object.keys(t.queryParams).length>0,l=t!==null&&(t.urlContext.managed&&Object.keys(t.urlContext.managed).length>0||t.urlContext.forwarded&&Object.keys(t.urlContext.forwarded).length>0||t.urlContext.source&&Object.keys(t.urlContext.source).length>0),p=this.customerIdentity?.getSnapshot()??null,m=e.customer??p;return{...e,timestamp:Date.now(),path:n.path,url:n.url,hostname:n.hostname,language:n.language,timezone:n.timezone,...s?{identifiers:a}:{},...d?{queryParams:{...t.queryParams}}:{},...l?{urlContext:{...t.urlContext.managed?{managed:{...t.urlContext.managed}}:{},...t.urlContext.forwarded?{forwarded:{...t.urlContext.forwarded}}:{},...t.urlContext.source?{source:{...t.urlContext.source}}:{}}}:{},...i(m)?{customer:{...m}}:{}}}};0&&(module.exports={BaseEventBuilder});
2
+ "use strict";var u=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var h=(r,e)=>{for(var n in e)u(r,n,{get:e[n],enumerable:!0})},_=(r,e,n,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of g(e))!y.call(r,a)&&a!==n&&u(r,a,{get:()=>e[a],enumerable:!(s=E(e,a))||s.enumerable});return r};var x=r=>_(u({},"__esModule",{value:!0}),r);var S={};h(S,{BaseEventBuilder:()=>i});module.exports=x(S);function o(r){return r?Object.values(r).some(e=>typeof e=="string"&&e.trim().length>0):!1}var i=class{constructor(e,n,s,a){this.metadataService=e,this.attribution=n??null,this.urlContext=s??null,this.customerIdentity=a??null}build(e){let n=this.metadataService.getMetadata(),s=this.attribution?.getSnapshot(),a=s!==void 0&&Object.keys(s).some(f=>{let d=s[f];return d!=null&&d!==""}),t=this.urlContext?.isEnabled()?this.urlContext.getSnapshot():null,l=t!==null&&Object.keys(t.queryParams).length>0,m=t!==null&&(t.urlContext.managed&&Object.keys(t.urlContext.managed).length>0||t.urlContext.forwarded&&Object.keys(t.urlContext.forwarded).length>0||t.urlContext.source&&Object.keys(t.urlContext.source).length>0),p=this.customerIdentity?.getSnapshot()??null,c=e.customer??p;return{...e,timestamp:Date.now(),path:n.path,url:n.url,hostname:n.hostname,language:n.language,timezone:n.timezone,...a?{identifiers:s}:{},...l?{queryParams:{...t.queryParams}}:{},...m?{urlContext:{...t.urlContext.managed?{managed:{...t.urlContext.managed}}:{},...t.urlContext.forwarded?{forwarded:{...t.urlContext.forwarded}}:{},...t.urlContext.source?{source:{...t.urlContext.source}}:{}}}:{},...o(c)?{customer:{...c}}:{}}}};0&&(module.exports={BaseEventBuilder});
3
3
  //# sourceMappingURL=index.cjs.js.map
@@ -1,3 +1,3 @@
1
1
  /* Pixel v2 — SDK de analytics e conversão */
2
- function a(o){return o?Object.values(o).some(t=>typeof t=="string"&&t.trim().length>0):!1}var s=class{constructor(t,n,r,i){this.metadataService=t,this.attribution=n??null,this.urlContext=r??null,this.customerIdentity=i??null}build(t){let n=this.metadataService.getMetadata(),r=this.attribution?.getSnapshot(),i=r!==void 0&&Object.keys(r).some(p=>{let u=r[p];return u!=null&&u!==""}),e=this.urlContext?.isEnabled()?this.urlContext.getSnapshot():null,m=e!==null&&Object.keys(e.queryParams).length>0,d=e!==null&&(e.urlContext.managed&&Object.keys(e.urlContext.managed).length>0||e.urlContext.forwarded&&Object.keys(e.urlContext.forwarded).length>0||e.urlContext.source&&Object.keys(e.urlContext.source).length>0),l=this.customerIdentity?.getSnapshot()??null,c=t.customer??l;return{...t,timestamp:Date.now(),path:n.path,url:n.url,hostname:n.hostname,language:n.language,timezone:n.timezone,...i?{identifiers:r}:{},...m?{queryParams:{...e.queryParams}}:{},...d?{urlContext:{...e.urlContext.managed?{managed:{...e.urlContext.managed}}:{},...e.urlContext.forwarded?{forwarded:{...e.urlContext.forwarded}}:{},...e.urlContext.source?{source:{...e.urlContext.source}}:{}}}:{},...a(c)?{customer:{...c}}:{}}}};export{s as BaseEventBuilder};
2
+ function s(i){return i?Object.values(i).some(t=>typeof t=="string"&&t.trim().length>0):!1}var a=class{constructor(t,n,r,o){this.metadataService=t,this.attribution=n??null,this.urlContext=r??null,this.customerIdentity=o??null}build(t){let n=this.metadataService.getMetadata(),r=this.attribution?.getSnapshot(),o=r!==void 0&&Object.keys(r).some(p=>{let d=r[p];return d!=null&&d!==""}),e=this.urlContext?.isEnabled()?this.urlContext.getSnapshot():null,c=e!==null&&Object.keys(e.queryParams).length>0,l=e!==null&&(e.urlContext.managed&&Object.keys(e.urlContext.managed).length>0||e.urlContext.forwarded&&Object.keys(e.urlContext.forwarded).length>0||e.urlContext.source&&Object.keys(e.urlContext.source).length>0),m=this.customerIdentity?.getSnapshot()??null,u=t.customer??m;return{...t,timestamp:Date.now(),path:n.path,url:n.url,hostname:n.hostname,language:n.language,timezone:n.timezone,...o?{identifiers:r}:{},...c?{queryParams:{...e.queryParams}}:{},...l?{urlContext:{...e.urlContext.managed?{managed:{...e.urlContext.managed}}:{},...e.urlContext.forwarded?{forwarded:{...e.urlContext.forwarded}}:{},...e.urlContext.source?{source:{...e.urlContext.source}}:{}}}:{},...s(u)?{customer:{...u}}:{}}}};export{a as BaseEventBuilder};
3
3
  //# sourceMappingURL=index.esm.js.map
@@ -21,6 +21,17 @@ Os HTMLs referenciam o IIFE em:
21
21
 
22
22
  Após o build, abra os `.html` no navegador (servidor estático local recomendado).
23
23
 
24
+ ## Customer
25
+
26
+ Snapshot automático do form em todos os eventos. Exemplos isolados:
27
+
28
+ ```text
29
+ customer/example-customer-defaults.html
30
+ customer/example-customer-extra-fields.html
31
+ customer/example-customer-css.html
32
+ customer/example-customer-events.html
33
+ ```
34
+
24
35
  ## AutoTrack — source `link`
25
36
 
26
37
  Nova source do Core: observa o **destino** de um `<a href>` (não a URL da página).
@@ -0,0 +1,29 @@
1
+ # Pixel — Customer (cenários isolados)
2
+
3
+ Cada HTML valida **um** comportamento. Abra um de cada vez.
4
+
5
+ O observer lê o form no `input`/`change` e grava o snapshot. O próximo evento
6
+ leva `customer` no payload (e em `data.customer`).
7
+
8
+ | # | Arquivo | O que valida |
9
+ |---|---------|--------------|
10
+ | 1 | [`example-customer-defaults.html`](./example-customer-defaults.html) | Names/ids padrão (`email`, `phone`, `first_name`, `cep`…) |
11
+ | 2 | [`example-customer-extra-fields.html`](./example-customer-extra-fields.html) | `commerce.customer.fields` com name/id extras (defaults continuam) |
12
+ | 3 | [`example-customer-css.html`](./example-customer-css.html) | Extras por CSS (`#contato-email`, `.campo-telefone`, `[data-cep]`) |
13
+ | 4 | [`example-customer-events.html`](./example-customer-events.html) | PAGE_VIEW vazio → depois ATC / pay / HEARTBEAT com customer |
14
+
15
+ ## Campos do snapshot
16
+
17
+ `email`, `phone`, `name`, `firstName`, `lastName`, `address`, `address2`, `city`, `state`, `postalCode`, `country`.
18
+
19
+ CEP no payload é **`postalCode`**. No DOM ainda aceita `cep`, `zip`, `zipcode`, etc.
20
+
21
+ ## Como abrir
22
+
23
+ 1. Na raiz: `pnpm --filter @beworke/pixel build`
24
+ 2. Abra o HTML (live server na raiz do monorepo)
25
+ 3. Script: `../../../packages/pixel/dist/browser/pixel.global.js`
26
+
27
+ ## Ordem sugerida
28
+
29
+ `defaults → extra name/id → CSS → eventos`
@@ -0,0 +1,383 @@
1
+ <!doctype html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Pixel — Customer CSS selectors</title>
7
+ <style>
8
+ :root {
9
+ --bg: #f8fafc; --card: #fff; --border: #e2e8f0; --text: #0f172a;
10
+ --muted: #64748b; --accent: #0f766e; --accent-soft: #ccfbf1;
11
+ }
12
+ * { box-sizing: border-box; }
13
+ body {
14
+ margin: 0;
15
+ font-family: "Segoe UI", system-ui, sans-serif;
16
+ background:
17
+ radial-gradient(circle at top left, #ecfeff 0%, transparent 40%),
18
+ linear-gradient(180deg, #f8fafc 0%, #eef2ff 100%);
19
+ color: var(--text); line-height: 1.45;
20
+ }
21
+ .wrap { max-width: 980px; margin: 0 auto; padding: 1.5rem; }
22
+ h1 { font-size: 1.5rem; margin: 0 0 0.35rem; letter-spacing: -0.02em; }
23
+ h2 { font-size: 1.05rem; margin: 0 0 0.75rem; }
24
+ .sub { color: var(--muted); margin: 0 0 1rem; font-size: 0.92rem; }
25
+ .nav { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1rem; }
26
+ .nav a {
27
+ text-decoration: none; border: 1px solid var(--border); background: #fff;
28
+ color: var(--text); border-radius: 999px; padding: 0.3rem 0.7rem; font-size: 0.78rem;
29
+ }
30
+ .nav a.active { background: var(--accent); border-color: var(--accent); color: #fff; }
31
+ .grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 1rem; }
32
+ @media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
33
+ .card {
34
+ background: var(--card); border: 1px solid var(--border); border-radius: 12px;
35
+ padding: 1rem; margin-bottom: 1rem; box-shadow: 0 1px 0 rgba(15,23,42,.03);
36
+ }
37
+ .hint {
38
+ background: var(--accent-soft); border: 1px solid #99f6e4; border-radius: 10px;
39
+ padding: 0.85rem 1rem; font-size: 0.9rem; margin-bottom: 1rem;
40
+ }
41
+ .actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
42
+ button {
43
+ appearance: none; border: 1px solid var(--border); background: #fff; color: var(--text);
44
+ border-radius: 8px; padding: 0.5rem 0.85rem; cursor: pointer; font: inherit;
45
+ }
46
+ button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
47
+ button.danger { background: #7f1d1d; border-color: #7f1d1d; color: #fff; }
48
+ label { display: block; font-size: 0.8rem; color: var(--muted); margin-bottom: 0.25rem; }
49
+ input {
50
+ width: 100%; border: 1px solid var(--border); border-radius: 8px;
51
+ padding: 0.55rem 0.7rem; font: inherit; background: #fff;
52
+ }
53
+ .row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
54
+ @media (max-width: 560px) { .row { grid-template-columns: 1fr; } }
55
+ .status, pre {
56
+ background: #0f172a; color: #e2e8f0; border-radius: 8px; padding: 0.75rem;
57
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
58
+ font-size: 0.78rem; white-space: pre-wrap; word-break: break-word;
59
+ max-height: 260px; overflow: auto;
60
+ }
61
+ .pill {
62
+ display: inline-block; border-radius: 999px; padding: 0.15rem 0.55rem;
63
+ font-size: 0.72rem; background: #e2e8f0; color: #334155; margin-left: 0.35rem;
64
+ }
65
+ .pill.ok { background: #bbf7d0; color: #166534; }
66
+ .checklist { margin: 0; padding-left: 1.1rem; font-size: 0.88rem; color: var(--muted); }
67
+ .checklist li { margin: 0.35rem 0; }
68
+ .ctx {
69
+ border-left: 3px solid var(--accent); padding-left: 0.75rem; margin-bottom: 0.85rem;
70
+ color: var(--muted); font-size: 0.88rem;
71
+ }
72
+ code { font-size: 0.85em; }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="wrap">
77
+ <h1>Customer — CSS <span class="pill" id="init-pill">offline</span></h1>
78
+ <p class="sub">
79
+ Inputs sem name padrão. O extrator acha por seletor CSS extra.
80
+ </p>
81
+ <div class="nav">
82
+ <a href="example-customer-defaults.html">1. Defaults</a>
83
+ <a href="example-customer-extra-fields.html">2. Extra name/id</a>
84
+ <a href="example-customer-css.html" class="active">3. CSS</a>
85
+ <a href="example-customer-events.html">4. Eventos</a>
86
+ </div>
87
+ <div class="hint">
88
+ <code>email: '#contato-email'</code>,
89
+ <code>phone: '.campo-telefone'</code>,
90
+ <code>name: '#nome-cliente'</code>,
91
+ <code>postalCode: '[data-cep]'</code>.
92
+ Os <code>name</code> do form são opacos (<code>x_mail</code>, …).
93
+ </div>
94
+
95
+ <div class="card">
96
+ <h2>Lifecycle</h2>
97
+ <div class="actions">
98
+ <button id="btn-reinit" class="primary" type="button">Reinitialize</button>
99
+ <button id="btn-destroy" class="danger" type="button">Destroy</button>
100
+ <button id="btn-fill" type="button">Preencher demo</button>
101
+ <button id="btn-clear" type="button">Clear logs</button>
102
+ </div>
103
+ <div class="status" id="runtime-status">Aguardando init...</div>
104
+ </div>
105
+
106
+ <div class="grid">
107
+ <div>
108
+ <div class="card">
109
+ <h2>Form só com CSS</h2>
110
+ <div class="ctx">
111
+ ATC quando <code>#contato-email</code> e
112
+ <code>#campo-telefone</code> estão preenchidos.
113
+ </div>
114
+ <form id="customer-form">
115
+ <div class="row">
116
+ <div>
117
+ <label for="contato-email">#contato-email</label>
118
+ <input id="contato-email" name="x_mail" type="text" />
119
+ </div>
120
+ <div>
121
+ <label for="campo-telefone">.campo-telefone</label>
122
+ <input id="campo-telefone" class="campo-telefone" name="x_phone" type="text" />
123
+ </div>
124
+ </div>
125
+ <div class="row">
126
+ <div>
127
+ <label for="nome-cliente">#nome-cliente</label>
128
+ <input id="nome-cliente" name="x_name" type="text" />
129
+ </div>
130
+ <div>
131
+ <label for="cep-attr">[data-cep]</label>
132
+ <input id="cep-attr" name="x_cep" type="text" data-cep />
133
+ </div>
134
+ </div>
135
+ </form>
136
+ </div>
137
+ <div class="card">
138
+ <h2>Checklist</h2>
139
+ <ul class="checklist">
140
+ <li>[ ] Sem extras no config → estes names não viram customer</li>
141
+ <li>[ ] Com CSS extras → email/phone/name/postalCode no snapshot</li>
142
+ <li>[ ] Email + phone via CSS → <code>ADD_TO_CART</code> com customer</li>
143
+ </ul>
144
+ </div>
145
+ </div>
146
+ <div>
147
+ <div class="card">
148
+ <h2>Customer snapshot</h2>
149
+ <pre id="customer-snap">null</pre>
150
+ </div>
151
+ <div class="card">
152
+ <h2>Event counts</h2>
153
+ <div class="status" id="event-counts">Nenhum evento ainda</div>
154
+ </div>
155
+ <div class="card">
156
+ <h2>Last event.customer</h2>
157
+ <pre id="last-customer">null</pre>
158
+ </div>
159
+ <div class="card">
160
+ <h2>Last event JSON</h2>
161
+ <pre id="last-event">null</pre>
162
+ </div>
163
+ <div class="card">
164
+ <h2>Event log</h2>
165
+ <pre id="logs">Aguardando eventos...</pre>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <script src="../../../browser/pixel.global.js"></script>
172
+ <script>
173
+ const PIXEL_ID = 'pix_7315610';
174
+ const API_ENDPOINT =
175
+ 'https://micro-service-pixel-production-4826.up.railway.app';
176
+
177
+ const els = {
178
+ logs: document.getElementById('logs'),
179
+ last: document.getElementById('last-event'),
180
+ lastCustomer: document.getElementById('last-customer'),
181
+ customer: document.getElementById('customer-snap'),
182
+ counts: document.getElementById('event-counts'),
183
+ runtime: document.getElementById('runtime-status'),
184
+ pill: document.getElementById('init-pill'),
185
+ };
186
+
187
+ let pixel = null;
188
+ let unsubscribe = null;
189
+ let initCount = 0;
190
+ let destroyCount = 0;
191
+ const counts = {};
192
+
193
+ function disabledDetector() {
194
+ return { enabled: false, sources: [] };
195
+ }
196
+
197
+ function buildSettings() {
198
+ return {
199
+ identity: { pixelId: PIXEL_ID },
200
+ app: { source: 'custom', environment: 'development', debug: true },
201
+ transport: {
202
+ enabled: true,
203
+ sender: { mode: 'internal', baseUrl: API_ENDPOINT },
204
+ },
205
+ commerce: {
206
+ enabled: true,
207
+ currency: 'BRL',
208
+ catalog: {
209
+ products: [
210
+ { id: 'main_offer', name: 'Oferta Principal', type: 'main', price: 197, currency: 'BRL', quantity: 1 },
211
+ ],
212
+ },
213
+ cart: {
214
+ mode: 'single_product',
215
+ initialItems: [{ productId: 'main_offer', quantity: 1 }],
216
+ },
217
+ customer: {
218
+ fields: {
219
+ email: '#contato-email',
220
+ phone: '.campo-telefone',
221
+ name: '#nome-cliente',
222
+ postalCode: '[data-cep]',
223
+ },
224
+ },
225
+ },
226
+ modules: {
227
+ core: {
228
+ pageView: { enabled: false, trackInitialPageView: false, spa: false },
229
+ },
230
+ behavior: { enabled: false },
231
+ conversion: {
232
+ enabled: true,
233
+ auto: {
234
+ enabled: true,
235
+ detectors: {
236
+ lead: disabledDetector(),
237
+ purchase: disabledDetector(),
238
+ removeFromCart: disabledDetector(),
239
+ initiateCheckout: disabledDetector(),
240
+ addPaymentInfo: disabledDetector(),
241
+ search: disabledDetector(),
242
+ viewContent: disabledDetector(),
243
+ addToCart: {
244
+ enabled: true,
245
+ sources: [
246
+ {
247
+ name: 'customer-form',
248
+ type: 'form',
249
+ selectorForm: {
250
+ fields: ['contato-email', 'campo-telefone'],
251
+ mode: 'all',
252
+ formSelector: '#customer-form',
253
+ trigger: 'auto',
254
+ debounceMs: 300,
255
+ fireOnce: true,
256
+ },
257
+ selector: ['#customer-form'],
258
+ selectorType: 'css',
259
+ },
260
+ ],
261
+ },
262
+ },
263
+ },
264
+ },
265
+ },
266
+ };
267
+ }
268
+
269
+ function appendLog(message) {
270
+ const line = '[' + new Date().toISOString() + '] ' + message;
271
+ const prev = els.logs.textContent;
272
+ els.logs.textContent =
273
+ prev === 'Aguardando eventos...' ? line : line + '\n' + prev;
274
+ }
275
+
276
+ function renderCounts() {
277
+ const lines = Object.keys(counts)
278
+ .sort()
279
+ .map(function (type) { return type + ': ' + counts[type]; });
280
+ els.counts.textContent =
281
+ lines.length > 0 ? lines.join('\n') : 'Nenhum evento ainda';
282
+ }
283
+
284
+ function eventCustomer(event) {
285
+ if (event && event.customer) return event.customer;
286
+ if (event && event.data && event.data.customer) return event.data.customer;
287
+ return null;
288
+ }
289
+
290
+ function renderCustomer() {
291
+ const services = pixel && pixel.getDebugServices ? pixel.getDebugServices() : null;
292
+ const snap =
293
+ services && services.customerIdentity
294
+ ? services.customerIdentity.getSnapshot()
295
+ : null;
296
+ els.customer.textContent = snap ? JSON.stringify(snap, null, 2) : 'null';
297
+ }
298
+
299
+ function renderDebug() {
300
+ els.runtime.textContent =
301
+ 'initialized: ' +
302
+ (pixel ? pixel.isInitialized() : false) +
303
+ '\ninit count: ' +
304
+ initCount +
305
+ '\ndestroy count: ' +
306
+ destroyCount +
307
+ '\npixelId: ' +
308
+ PIXEL_ID +
309
+ '\nscenario: customer CSS';
310
+ els.pill.textContent =
311
+ pixel && pixel.isInitialized() ? 'ready' : 'offline';
312
+ els.pill.className =
313
+ 'pill' + (pixel && pixel.isInitialized() ? ' ok' : '');
314
+ renderCustomer();
315
+ }
316
+
317
+ function onEvent(event) {
318
+ counts[event.type] = (counts[event.type] || 0) + 1;
319
+ renderCounts();
320
+ els.last.textContent = JSON.stringify(event, null, 2);
321
+ const customer = eventCustomer(event);
322
+ els.lastCustomer.textContent = customer
323
+ ? JSON.stringify(customer, null, 2)
324
+ : 'null';
325
+ appendLog(event.type + ' customer=' + JSON.stringify(customer));
326
+ renderDebug();
327
+ }
328
+
329
+ async function boot() {
330
+ if (unsubscribe) { unsubscribe(); unsubscribe = null; }
331
+ if (pixel) {
332
+ await pixel.destroy();
333
+ destroyCount += 1;
334
+ pixel = null;
335
+ }
336
+ pixel = await Pixel.create(buildSettings());
337
+ initCount += 1;
338
+ const services = pixel.getDebugServices();
339
+ if (services && services.dispatcher) {
340
+ unsubscribe = services.dispatcher.subscribe(onEvent);
341
+ }
342
+ appendLog('Pixel initialized — customer CSS');
343
+ renderDebug();
344
+ }
345
+
346
+ async function destroyPixel() {
347
+ if (unsubscribe) { unsubscribe(); unsubscribe = null; }
348
+ if (pixel) {
349
+ await pixel.destroy();
350
+ destroyCount += 1;
351
+ pixel = null;
352
+ }
353
+ appendLog('Pixel destroyed');
354
+ renderDebug();
355
+ }
356
+
357
+ document.getElementById('btn-reinit').onclick = function () { boot(); };
358
+ document.getElementById('btn-destroy').onclick = function () { destroyPixel(); };
359
+ document.getElementById('btn-clear').onclick = function () {
360
+ els.logs.textContent = 'Aguardando eventos...';
361
+ els.last.textContent = 'null';
362
+ els.lastCustomer.textContent = 'null';
363
+ Object.keys(counts).forEach(function (k) { delete counts[k]; });
364
+ renderCounts();
365
+ };
366
+ document.getElementById('btn-fill').onclick = function () {
367
+ document.getElementById('contato-email').value = 'css@exemplo.com';
368
+ document.getElementById('campo-telefone').value = '11977776666';
369
+ document.getElementById('nome-cliente').value = 'Rita CSS';
370
+ document.getElementById('cep-attr').value = '01311-000';
371
+ document.getElementById('customer-form').querySelectorAll('input').forEach(function (input) {
372
+ input.dispatchEvent(new Event('input', { bubbles: true }));
373
+ });
374
+ };
375
+
376
+ document.getElementById('customer-form').addEventListener('input', function () {
377
+ setTimeout(renderCustomer, 250);
378
+ });
379
+
380
+ boot();
381
+ </script>
382
+ </body>
383
+ </html>