@beworke/pixel 0.1.0-rc.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +163 -0
  3. package/RELEASE_CANDIDATE.md +256 -0
  4. package/dist/PixelLogger-B21lEjep.d.mts +8 -0
  5. package/dist/PixelLogger-B21lEjep.d.ts +8 -0
  6. package/dist/StorageFactory-BhpbB6Jj.d.mts +8 -0
  7. package/dist/StorageFactory-CAkJJqVD.d.ts +8 -0
  8. package/dist/config/index.cjs.js +3 -0
  9. package/dist/config/index.cjs.js.map +1 -0
  10. package/dist/config/index.d.mts +19 -0
  11. package/dist/config/index.d.ts +19 -0
  12. package/dist/config/index.esm.js +3 -0
  13. package/dist/config/index.esm.js.map +1 -0
  14. package/dist/events/index.cjs.js +3 -0
  15. package/dist/events/index.cjs.js.map +1 -0
  16. package/dist/events/index.d.mts +1 -0
  17. package/dist/events/index.d.ts +1 -0
  18. package/dist/events/index.esm.js +3 -0
  19. package/dist/events/index.esm.js.map +1 -0
  20. package/dist/examples/html-script/README.md +71 -0
  21. package/dist/examples/html-script/RELEASE_CANDIDATE.md +121 -0
  22. package/dist/examples/html-script/add-payment-info/README.md +46 -0
  23. package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-autocomplete.html +494 -0
  24. package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-disabled.html +478 -0
  25. package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-fields.html +486 -0
  26. package/dist/examples/html-script/add-payment-info/example-add-payment-info-data-track.html +479 -0
  27. package/dist/examples/html-script/add-payment-info/example-add-payment-info-dedupe.html +492 -0
  28. package/dist/examples/html-script/add-payment-info/example-add-payment-info-manual.html +495 -0
  29. package/dist/examples/html-script/add-payment-info/example-add-payment-info-rules-card.html +469 -0
  30. package/dist/examples/html-script/add-payment-info/example-add-payment-info-security.html +489 -0
  31. package/dist/examples/html-script/add-to-cart/README.md +36 -0
  32. package/dist/examples/html-script/add-to-cart/example-add-to-cart-attribute.html +517 -0
  33. package/dist/examples/html-script/add-to-cart/example-add-to-cart-auto.html +512 -0
  34. package/dist/examples/html-script/add-to-cart/example-add-to-cart-click.html +519 -0
  35. package/dist/examples/html-script/add-to-cart/example-add-to-cart-dedupe.html +514 -0
  36. package/dist/examples/html-script/add-to-cart/example-add-to-cart-manual.html +517 -0
  37. package/dist/examples/html-script/add-to-cart/example-add-to-cart-order-bump.html +527 -0
  38. package/dist/examples/html-script/add-to-cart/example-add-to-cart-text.html +524 -0
  39. package/dist/examples/html-script/example-basic.html +350 -0
  40. package/dist/examples/html-script/example-behavior.html +435 -0
  41. package/dist/examples/html-script/example-conversion.html +479 -0
  42. package/dist/examples/html-script/example-integration.html +709 -0
  43. package/dist/examples/html-script/example-transport.html +748 -0
  44. package/dist/examples/html-script/initiate-checkout/README.md +38 -0
  45. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-attribute.html +485 -0
  46. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-auto.html +491 -0
  47. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-click.html +493 -0
  48. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-manual.html +494 -0
  49. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-snapshot.html +497 -0
  50. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-submit.html +502 -0
  51. package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-text.html +496 -0
  52. package/dist/examples/html-script/lead/README.md +25 -0
  53. package/dist/examples/html-script/lead/example-lead-trigger-attribute.html +594 -0
  54. package/dist/examples/html-script/lead/example-lead-trigger-auto.html +431 -0
  55. package/dist/examples/html-script/lead/example-lead-trigger-click.html +587 -0
  56. package/dist/examples/html-script/release-candidate.html +726 -0
  57. package/dist/examples/html-script/remove-from-cart/README.md +36 -0
  58. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-attribute.html +532 -0
  59. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-css.html +524 -0
  60. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-dedupe.html +540 -0
  61. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-manual.html +533 -0
  62. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-multi.html +557 -0
  63. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-state.html +539 -0
  64. package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-text.html +524 -0
  65. package/dist/examples/html-script/search/README.md +41 -0
  66. package/dist/examples/html-script/search/example-search-attribute.html +454 -0
  67. package/dist/examples/html-script/search/example-search-button-sync.html +455 -0
  68. package/dist/examples/html-script/search/example-search-dedupe.html +466 -0
  69. package/dist/examples/html-script/search/example-search-input.html +456 -0
  70. package/dist/examples/html-script/search/example-search-manual.html +473 -0
  71. package/dist/examples/html-script/search/example-search-submit.html +450 -0
  72. package/dist/examples/html-script/search/example-search-text.html +441 -0
  73. package/dist/examples/html-script/view-content/README.md +48 -0
  74. package/dist/examples/html-script/view-content/example-view-content-attribute.html +488 -0
  75. package/dist/examples/html-script/view-content/example-view-content-css.html +467 -0
  76. package/dist/examples/html-script/view-content/example-view-content-dedupe.html +485 -0
  77. package/dist/examples/html-script/view-content/example-view-content-empty.html +469 -0
  78. package/dist/examples/html-script/view-content/example-view-content-manual.html +496 -0
  79. package/dist/examples/html-script/view-content/example-view-content-product-card.html +478 -0
  80. package/dist/examples/html-script/view-content/example-view-content-text.html +473 -0
  81. package/dist/examples/release-candidate/README.md +14 -0
  82. package/dist/examples/v2/README.md +33 -0
  83. package/dist/index-DUfFzniE.d.mts +274 -0
  84. package/dist/index-DUfFzniE.d.ts +274 -0
  85. package/dist/index.cjs.js +3 -0
  86. package/dist/index.cjs.js.map +1 -0
  87. package/dist/index.d.mts +364 -0
  88. package/dist/index.d.ts +364 -0
  89. package/dist/index.esm.js +3 -0
  90. package/dist/index.esm.js.map +1 -0
  91. package/dist/logger/index.cjs.js +3 -0
  92. package/dist/logger/index.cjs.js.map +1 -0
  93. package/dist/logger/index.d.mts +12 -0
  94. package/dist/logger/index.d.ts +12 -0
  95. package/dist/logger/index.esm.js +3 -0
  96. package/dist/logger/index.esm.js.map +1 -0
  97. package/dist/pixel-CbeF25mD.d.mts +555 -0
  98. package/dist/pixel-CbeF25mD.d.ts +555 -0
  99. package/dist/pixel-default-config-1VgLFOiL.d.mts +5 -0
  100. package/dist/pixel-default-config-Bxb-Vdd8.d.ts +5 -0
  101. package/dist/runtime/index.cjs.js +3 -0
  102. package/dist/runtime/index.cjs.js.map +1 -0
  103. package/dist/runtime/index.d.mts +48 -0
  104. package/dist/runtime/index.d.ts +48 -0
  105. package/dist/runtime/index.esm.js +3 -0
  106. package/dist/runtime/index.esm.js.map +1 -0
  107. package/dist/services/index.cjs.js +3 -0
  108. package/dist/services/index.cjs.js.map +1 -0
  109. package/dist/services/index.d.mts +169 -0
  110. package/dist/services/index.d.ts +169 -0
  111. package/dist/services/index.esm.js +3 -0
  112. package/dist/services/index.esm.js.map +1 -0
  113. package/dist/types-CTpRvFKZ.d.ts +71 -0
  114. package/dist/types-DGlBdsAy.d.mts +71 -0
  115. package/dist/v2/global.global.js +3 -0
  116. package/dist/v2/global.global.js.map +1 -0
  117. package/dist/v2/index.cjs.js +3 -0
  118. package/dist/v2/index.cjs.js.map +1 -0
  119. package/dist/v2/index.d.mts +7 -0
  120. package/dist/v2/index.d.ts +7 -0
  121. package/dist/v2/index.esm.js +3 -0
  122. package/dist/v2/index.esm.js.map +1 -0
  123. package/package.json +101 -0
@@ -0,0 +1,36 @@
1
+ # Pixel v2 — REMOVE_FROM_CART (cenários isolados)
2
+
3
+ Cada HTML valida **um** comportamento. Abra um de cada vez.
4
+
5
+ > **Nota:** `removeFromCart` **não** tem `selectorForm` no contrato (só selector).
6
+ > Fontes: payload manual, `data-product-id`, commerce state.
7
+
8
+ | # | Arquivo | Como dispara | O que valida |
9
+ |---|---------|--------------|--------------|
10
+ | 1 | [`example-remove-from-cart-attribute.html`](./example-remove-from-cart-attribute.html) | `[data-track="remove_from_cart"]` | SelectorDetector + ProductExtractor |
11
+ | 2 | [`example-remove-from-cart-text.html`](./example-remove-from-cart-text.html) | `text:Remover` | Match por texto |
12
+ | 3 | [`example-remove-from-cart-css.html`](./example-remove-from-cart-css.html) | `.remove-from-cart` | Seletor CSS class |
13
+ | 4 | [`example-remove-from-cart-manual.html`](./example-remove-from-cart-manual.html) | `pixel.removeFromCart()` | API + sem productId |
14
+ | 5 | [`example-remove-from-cart-state.html`](./example-remove-from-cart-state.html) | atributo + state | `removeItem` / cart mirror |
15
+ | 6 | [`example-remove-from-cart-dedupe.html`](./example-remove-from-cart-dedupe.html) | clique / API | Dedupe por `productId` (sem janela) |
16
+ | 7 | [`example-remove-from-cart-multi.html`](./example-remove-from-cart-multi.html) | multi botões | Remoção seletiva de 3 itens |
17
+
18
+ ## Dedupe (importante)
19
+
20
+ ```txt
21
+ REMOVE_FROM_CART:product:{productId}
22
+ ```
23
+
24
+ Sem bucket de tempo (diferente do ADD ~500ms). Segundo remove do mesmo id na sessão é bloqueado até **Reinitialize**.
25
+
26
+ ## Como abrir
27
+
28
+ 1. Na raiz: `npm run build`
29
+ 2. Abra o HTML (live server recomendado)
30
+ 3. Script: `../../../dist/v2/global.global.js`
31
+
32
+ ## Ordem sugerida
33
+
34
+ `atributo → text → css → manual → state → dedupe → multi`
35
+
36
+ Referências: [`../add-to-cart/`](../add-to-cart/) · [`../lead/`](../lead/)
@@ -0,0 +1,532 @@
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 v2 — REMOVE_FROM_CART atributo data-track</title>
7
+ <style>
8
+ :root {
9
+ --bg: #f8fafc; --card: #fff; --border: #e2e8f0; --text: #0f172a;
10
+ --muted: #64748b; --accent: #0f766e; --accent-soft: #ccfbf1;
11
+ --warn: #9a3412; --warn-soft: #ffedd5;
12
+ }
13
+ * { box-sizing: border-box; }
14
+ body {
15
+ margin: 0;
16
+ font-family: "Segoe UI", system-ui, sans-serif;
17
+ background:
18
+ radial-gradient(circle at top left, #ecfeff 0%, transparent 40%),
19
+ linear-gradient(180deg, #f8fafc 0%, #eef2ff 100%);
20
+ color: var(--text); line-height: 1.45;
21
+ }
22
+ .wrap { max-width: 980px; margin: 0 auto; padding: 1.5rem; }
23
+ h1 { font-size: 1.5rem; margin: 0 0 0.35rem; letter-spacing: -0.02em; }
24
+ h2 { font-size: 1.05rem; margin: 0 0 0.75rem; }
25
+ .sub { color: var(--muted); margin: 0 0 1rem; font-size: 0.92rem; }
26
+ .nav { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1rem; }
27
+ .nav a {
28
+ text-decoration: none; border: 1px solid var(--border); background: #fff;
29
+ color: var(--text); border-radius: 999px; padding: 0.3rem 0.7rem; font-size: 0.78rem;
30
+ }
31
+ .nav a.active { background: var(--accent); border-color: var(--accent); color: #fff; }
32
+ .grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 1rem; }
33
+ @media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
34
+ .card {
35
+ background: var(--card); border: 1px solid var(--border); border-radius: 12px;
36
+ padding: 1rem; margin-bottom: 1rem; box-shadow: 0 1px 0 rgba(15,23,42,.03);
37
+ }
38
+ .hint {
39
+ background: var(--accent-soft); border: 1px solid #99f6e4; border-radius: 10px;
40
+ padding: 0.85rem 1rem; font-size: 0.9rem; margin-bottom: 1rem;
41
+ }
42
+ .hint.warn { background: var(--warn-soft); border-color: #fdba74; color: var(--warn); }
43
+ .actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
44
+ button {
45
+ appearance: none; border: 1px solid var(--border); background: #fff; color: var(--text);
46
+ border-radius: 8px; padding: 0.5rem 0.85rem; cursor: pointer; font: inherit;
47
+ }
48
+ button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
49
+ button.danger { background: #7f1d1d; border-color: #7f1d1d; color: #fff; }
50
+ button:disabled { opacity: 0.55; cursor: not-allowed; }
51
+ label { display: block; font-size: 0.8rem; color: var(--muted); margin-bottom: 0.25rem; }
52
+ input {
53
+ width: 100%; border: 1px solid var(--border); border-radius: 8px;
54
+ padding: 0.55rem 0.7rem; font: inherit; background: #fff;
55
+ }
56
+ .row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
57
+ @media (max-width: 560px) { .row { grid-template-columns: 1fr; } }
58
+ .status, pre {
59
+ background: #0f172a; color: #e2e8f0; border-radius: 8px; padding: 0.75rem;
60
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
61
+ font-size: 0.78rem; white-space: pre-wrap; word-break: break-word;
62
+ max-height: 260px; overflow: auto;
63
+ }
64
+ .pill {
65
+ display: inline-block; border-radius: 999px; padding: 0.15rem 0.55rem;
66
+ font-size: 0.72rem; background: #e2e8f0; color: #334155; margin-left: 0.35rem;
67
+ }
68
+ .pill.ok { background: #bbf7d0; color: #166534; }
69
+ .checklist { margin: 0; padding-left: 1.1rem; font-size: 0.88rem; color: var(--muted); }
70
+ .checklist li { margin: 0.35rem 0; }
71
+ .ctx {
72
+ border-left: 3px solid var(--accent); padding-left: 0.75rem; margin-bottom: 0.85rem;
73
+ color: var(--muted); font-size: 0.88rem;
74
+ }
75
+ .product {
76
+ border: 1px dashed var(--border); border-radius: 10px; padding: 0.75rem; margin: 0.5rem 0;
77
+ }
78
+ .product strong { display: block; margin-bottom: 0.2rem; }
79
+ code { font-size: 0.85em; }
80
+ </style>
81
+ </head>
82
+ <body>
83
+ <div class="wrap">
84
+ <h1>REMOVE_FROM_CART — atributo · data-track</h1>
85
+ <p class="sub">
86
+ Cenário isolado para validação do Pixel v2.
87
+ <span class="pill" id="init-pill">offline</span>
88
+ </p>
89
+ <div class="nav"><a href="example-remove-from-cart-attribute.html" class="active">1. Atributo</a>
90
+ <a href="example-remove-from-cart-text.html" class="">2. Text</a>
91
+ <a href="example-remove-from-cart-css.html" class="">3. CSS class</a>
92
+ <a href="example-remove-from-cart-manual.html" class="">4. Manual API</a>
93
+ <a href="example-remove-from-cart-state.html" class="">5. CommerceState</a>
94
+ <a href="example-remove-from-cart-dedupe.html" class="">6. Dedupe</a>
95
+ <a href="example-remove-from-cart-multi.html" class="">7. Multi item</a></div>
96
+ <div class="hint"><strong>Contexto:</strong> carrinho / order bump. Clique em botão com
97
+ <code>data-track="remove_from_cart"</code> + <code>data-product-id</code>.
98
+ Sem <code>selectorForm</code> (não existe neste detector) —
99
+ <code>ConfiguredSelectorDetector</code> + <code>ProductExtractor</code>.</div>
100
+
101
+ <div class="card">
102
+ <h2>Lifecycle</h2>
103
+ <div class="actions">
104
+ <button id="btn-reinit" class="primary" type="button">Reinitialize</button>
105
+ <button id="btn-destroy" class="danger" type="button">Destroy</button>
106
+ <button id="btn-clear" type="button">Clear logs</button>
107
+ </div>
108
+ <div class="status" id="runtime-status">Aguardando init...</div>
109
+ </div>
110
+
111
+ <div class="grid">
112
+ <div>
113
+ <div class="card">
114
+ <h2>Remover por atributo <span class="pill">ConfiguredSelector</span></h2>
115
+ <div class="ctx">Carrinho seed: main_offer + order_bump_01.</div>
116
+ <div class="product">
117
+ <strong>Order Bump Especial — R$ 47</strong>
118
+ <div class="actions">
119
+ <button
120
+ type="button"
121
+ class="danger"
122
+ data-track="remove_from_cart"
123
+ data-product-id="order_bump_01"
124
+ data-quantity="1"
125
+ >
126
+ Remover order bump
127
+ </button>
128
+ <button
129
+ type="button"
130
+ data-track="remove_from_cart"
131
+ data-product-id="main_offer"
132
+ >
133
+ Remover main
134
+ </button>
135
+ <button type="button" id="btn-no-track">Clique sem data-track</button>
136
+ </div>
137
+ </div>
138
+ <p class="sub">
139
+ Sem atributo → não dispara. Cart mirror remove o item do seed.
140
+ </p>
141
+ </div>
142
+ <div class="card">
143
+ <h2>Checklist</h2>
144
+ <ul class="checklist">
145
+ <li>[ ] Clique sem <code>data-track</code> → não dispara</li>
146
+ <li>[ ] Remover bump → <code>REMOVE_FROM_CART</code> + some do mirror</li>
147
+ <li>[ ] Remover main → some main_offer do mirror</li>
148
+ <li>[ ] Payload traz <code>productId</code> (e qty se houver)</li>
149
+ <li>[ ] Detector: <code>ConfiguredSelector(REMOVE_FROM_CART)</code></li>
150
+ </ul>
151
+ </div>
152
+ </div>
153
+ <div>
154
+ <div class="card">
155
+ <h2>Event counts</h2>
156
+ <div class="status" id="event-counts">Nenhum evento ainda</div>
157
+ </div>
158
+ <div class="card">
159
+ <h2>Cart mirror (via eventos + seed)</h2>
160
+ <div class="status" id="cart-mirror">{}</div>
161
+ </div>
162
+ <div class="card">
163
+ <h2>Active detectors</h2>
164
+ <div class="status" id="detectors">—</div>
165
+ </div>
166
+
167
+ <div class="card">
168
+ <h2>Last event JSON</h2>
169
+ <pre id="last-event">null</pre>
170
+ </div>
171
+ <div class="card">
172
+ <h2>Event log</h2>
173
+ <pre id="logs">Aguardando eventos...</pre>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ <script src="../../../dist/v2/global.global.js"></script>
180
+ <script>
181
+ const { Pixel, DEFAULT_PIXEL_CONFIG } = window.PixelV2;
182
+ const API_ENDPOINT =
183
+ 'https://micro-service-pixel-production-4826.up.railway.app';
184
+ const PIXEL_ID = 'pix_7315610';
185
+
186
+ const els = {
187
+ logs: document.getElementById('logs'),
188
+ last: document.getElementById('last-event'),
189
+ counts: document.getElementById('event-counts'),
190
+ cart: document.getElementById('cart-mirror'),
191
+ detectors: document.getElementById('detectors'),
192
+ dedupe: document.getElementById('dedupe-keys'),
193
+ runtime: document.getElementById('runtime-status'),
194
+ pill: document.getElementById('init-pill'),
195
+ };
196
+
197
+ let pixel = null;
198
+ let unsubscribe = null;
199
+ let initCount = 0;
200
+ let destroyCount = 0;
201
+ const counts = {};
202
+ const cartMirror = {};
203
+
204
+ function removeFromCartDetectorConfig() {
205
+ return {
206
+ enabled: true,
207
+ selector: ['[data-track="remove_from_cart"]'],
208
+ selectorType: 'css',
209
+ };
210
+ }
211
+
212
+ function buildConfig() {
213
+ const base = DEFAULT_PIXEL_CONFIG;
214
+ return {
215
+ ...base,
216
+ app: {
217
+ ...base.app,
218
+ source: 'custom',
219
+ environment: 'development',
220
+ debug: true,
221
+ },
222
+ transport: {
223
+ ...DEFAULT_PIXEL_CONFIG.transport,
224
+ apiEndpoint: API_ENDPOINT,
225
+ timeoutMs: 10000,
226
+ },
227
+ identity: { ...base.identity, pixelId: PIXEL_ID },
228
+ modules: {
229
+ ...base.modules,
230
+ core: {
231
+ ...base.modules.core,
232
+ enabled: false,
233
+ pageView: {
234
+ ...base.modules.core.pageView,
235
+ enabled: false,
236
+ trackInitialPageView: false,
237
+ spa: false,
238
+ },
239
+ },
240
+ behavior: { ...base.modules.behavior, enabled: false },
241
+ privacy: { ...base.modules.privacy, enabled: false },
242
+ transport: {
243
+ enabled: true,
244
+ mockSender: { enabled: false },
245
+ sender: { mode: 'http' },
246
+ persistence: { enabled: true },
247
+ replay: { enabled: true },
248
+ ordering: { enabled: true },
249
+ coordination: { enabled: true },
250
+ circuitBreaker: {
251
+ enabled: true,
252
+ failureThreshold: 5,
253
+ resetTimeoutMs: 30000,
254
+ halfOpenMaxAttempts: 2,
255
+ },
256
+ backpressure: {
257
+ enabled: true,
258
+ maxQueueSize: 500,
259
+ policy: 'drop_oldest',
260
+ sampleRate: 0.5,
261
+ },
262
+ deadLetter: { enabled: true, maxEntries: 200 },
263
+ compression: { enabled: true, strategy: 'identity' },
264
+ retry: {
265
+ enabled: true,
266
+ maxAttempts: 4,
267
+ baseDelayMs: 500,
268
+ maxDelayMs: 4000,
269
+ multiplier: 2,
270
+ },
271
+ batch: {
272
+ enabled: true,
273
+ batchSize: 10,
274
+ flushIntervalMs: 2000,
275
+ maxWaitMs: 5000,
276
+ },
277
+ timeout: { enabled: true, timeoutMs: 10000 },
278
+ offline: { enabled: true },
279
+ flush: {
280
+ enabled: true,
281
+ flushIntervalMs: 2000,
282
+ flushOnDestroy: true,
283
+ prepareUnloadHooks: true,
284
+ },
285
+ },
286
+ integrations: { ...base.modules.integrations, enabled: false },
287
+ conversion: {
288
+ enabled: true,
289
+ commerce: {
290
+ currency: 'BRL',
291
+ catalog: { products: [
292
+ {
293
+ id: 'main_offer',
294
+ name: 'Oferta Principal',
295
+ type: 'main',
296
+ price: 197,
297
+ currency: 'BRL',
298
+ quantity: 1,
299
+ },
300
+ {
301
+ id: 'order_bump_01',
302
+ name: 'Order Bump Especial',
303
+ type: 'order_bump',
304
+ price: 47,
305
+ currency: 'BRL',
306
+ quantity: 1,
307
+ },
308
+ {
309
+ id: 'upsell_01',
310
+ name: 'Upsell 01',
311
+ type: 'upsell',
312
+ price: 97,
313
+ currency: 'BRL',
314
+ quantity: 1,
315
+ },
316
+ ] },
317
+ checkout: {
318
+ mode: 'single_product',
319
+ selectedItems: [
320
+ { productId: 'main_offer', quantity: 1 },
321
+ { productId: 'order_bump_01', quantity: 1 },
322
+ ],
323
+ calculateValueFrom: 'selected_items',
324
+ allowDynamicItems: true,
325
+ },
326
+ mappings: {
327
+ attributes: {
328
+ productId: ['data-product-id', 'data-sku', 'data-offer-id'],
329
+ productName: ['data-product-name', 'data-name'],
330
+ price: ['data-product-price', 'data-price'],
331
+ quantity: ['data-quantity', 'data-qty'],
332
+ currency: ['data-currency'],
333
+ },
334
+ fields: {
335
+ productId: ['productId', 'product_id', 'offerId', 'sku'],
336
+ productName: ['productName', 'product_name'],
337
+ price: ['price', 'amount'],
338
+ quantity: ['quantity', 'qty'],
339
+ currency: ['currency'],
340
+ email: ['email', 'customerEmail'],
341
+ phone: ['phone', 'telefone', 'customerPhone'],
342
+ },
343
+ },
344
+ },
345
+ manual: {
346
+ pageView: { enabled: false },
347
+ purchase: { enabled: false },
348
+ lead: { enabled: false },
349
+ addToCart: { enabled: true },
350
+ removeFromCart: { enabled: true },
351
+ initiateCheckout: { enabled: false },
352
+ addPaymentInfo: { enabled: false },
353
+ search: { enabled: false },
354
+ viewContent: { enabled: false },
355
+ },
356
+ auto: {
357
+ enabled: true,
358
+ detectors: {
359
+ lead: { enabled: false },
360
+ purchase: { enabled: false },
361
+ addToCart: { enabled: false },
362
+ removeFromCart: removeFromCartDetectorConfig(),
363
+ initiateCheckout: { enabled: false },
364
+ addPaymentInfo: { enabled: false },
365
+ search: { enabled: false },
366
+ viewContent: { enabled: false },
367
+ },
368
+ },
369
+ rules: {
370
+ enabled: false,
371
+ selectors: [],
372
+ texts: [],
373
+ urlPatterns: [],
374
+ checkout: { enabled: false },
375
+ card: { enabled: false },
376
+ },
377
+ },
378
+ },
379
+ };
380
+ }
381
+
382
+ function appendLog(message) {
383
+ const line = '[' + new Date().toISOString() + '] ' + message;
384
+ const prev = els.logs.textContent;
385
+ els.logs.textContent =
386
+ prev === 'Aguardando eventos...' ? line : line + '\n' + prev;
387
+ }
388
+
389
+ function renderCounts() {
390
+ const lines = Object.keys(counts)
391
+ .sort()
392
+ .map(function (type) { return type + ': ' + counts[type]; });
393
+ els.counts.textContent =
394
+ lines.length > 0 ? lines.join('\n') : 'Nenhum evento ainda';
395
+ }
396
+
397
+ function renderCart() {
398
+ if (!els.cart) return;
399
+ els.cart.textContent = JSON.stringify(cartMirror, null, 2);
400
+ }
401
+
402
+ function seedCartMirror() {
403
+ Object.keys(cartMirror).forEach(function (k) { delete cartMirror[k]; });
404
+ cartMirror.main_offer = {
405
+ productId: 'main_offer',
406
+ productName: 'Oferta Principal (seed)',
407
+ price: 197,
408
+ currency: 'BRL',
409
+ quantity: 1,
410
+ };
411
+ cartMirror.order_bump_01 = {
412
+ productId: 'order_bump_01',
413
+ productName: 'Order Bump Especial (seed)',
414
+ price: 47,
415
+ currency: 'BRL',
416
+ quantity: 1,
417
+ };
418
+ renderCart();
419
+ }
420
+
421
+ function renderDebug() {
422
+ const detectors =
423
+ pixel && pixel.getDebugActiveDetectors
424
+ ? pixel.getDebugActiveDetectors()
425
+ : [];
426
+ els.detectors.textContent =
427
+ detectors.length > 0 ? detectors.join('\n') : 'Nenhum detector ativo';
428
+ if (els.dedupe) {
429
+ const keys =
430
+ pixel && pixel.getDebugDedupeKeys ? pixel.getDebugDedupeKeys() : [];
431
+ els.dedupe.textContent =
432
+ keys.length > 0 ? keys.join('\n') : 'Nenhuma chave';
433
+ }
434
+ els.runtime.textContent =
435
+ 'initialized: ' +
436
+ (pixel ? pixel.isInitialized() : false) +
437
+ '\ninit count: ' +
438
+ initCount +
439
+ '\ndestroy count: ' +
440
+ destroyCount +
441
+ '\npixelId: ' +
442
+ PIXEL_ID +
443
+ '\nscenario: atributo · data-track';
444
+ els.pill.textContent =
445
+ pixel && pixel.isInitialized() ? 'ready' : 'offline';
446
+ els.pill.className =
447
+ 'pill' + (pixel && pixel.isInitialized() ? ' ok' : '');
448
+ }
449
+
450
+ function updateCartFromEvent(event) {
451
+ if (
452
+ event.type === 'ADD_TO_CART' &&
453
+ event.data &&
454
+ event.data.productId
455
+ ) {
456
+ cartMirror[event.data.productId] = {
457
+ productId: event.data.productId,
458
+ productName: event.data.productName,
459
+ price: event.data.price,
460
+ currency: event.data.currency,
461
+ quantity: event.data.quantity != null ? event.data.quantity : 1,
462
+ };
463
+ }
464
+ if (
465
+ event.type === 'REMOVE_FROM_CART' &&
466
+ event.data &&
467
+ event.data.productId
468
+ ) {
469
+ delete cartMirror[event.data.productId];
470
+ }
471
+ renderCart();
472
+ }
473
+
474
+ function onEvent(event) {
475
+ counts[event.type] = (counts[event.type] || 0) + 1;
476
+ renderCounts();
477
+ updateCartFromEvent(event);
478
+ els.last.textContent = JSON.stringify(event, null, 2);
479
+ appendLog(event.type + ' ' + JSON.stringify(event.data || {}));
480
+ renderDebug();
481
+ }
482
+
483
+ async function boot() {
484
+ if (unsubscribe) { unsubscribe(); unsubscribe = null; }
485
+ if (pixel) {
486
+ await pixel.destroy();
487
+ destroyCount += 1;
488
+ pixel = null;
489
+ }
490
+ seedCartMirror();
491
+ pixel = new Pixel(buildConfig());
492
+ await pixel.init();
493
+ initCount += 1;
494
+ const services = pixel.getDebugServices();
495
+ if (services && services.dispatcher) {
496
+ unsubscribe = services.dispatcher.subscribe(onEvent);
497
+ }
498
+ appendLog('Pixel initialized — atributo · data-track');
499
+ renderDebug();
500
+ }
501
+
502
+ async function destroyPixel() {
503
+ if (unsubscribe) { unsubscribe(); unsubscribe = null; }
504
+ if (pixel) {
505
+ await pixel.destroy();
506
+ destroyCount += 1;
507
+ pixel = null;
508
+ }
509
+ appendLog('Pixel destroyed');
510
+ renderDebug();
511
+ }
512
+
513
+ document.getElementById('btn-reinit').onclick = function () { boot(); };
514
+ document.getElementById('btn-destroy').onclick = function () { destroyPixel(); };
515
+ document.getElementById('btn-clear').onclick = function () {
516
+ els.logs.textContent = 'Aguardando eventos...';
517
+ els.last.textContent = 'null';
518
+ Object.keys(counts).forEach(function (k) { delete counts[k]; });
519
+ seedCartMirror();
520
+ renderCounts();
521
+ };
522
+
523
+
524
+ document.getElementById('btn-no-track').onclick = function () {
525
+ appendLog('(playground) clique sem data-track — esperado: nenhum REMOVE');
526
+ };
527
+
528
+
529
+ boot();
530
+ </script>
531
+ </body>
532
+ </html>