@beworke/pixel-bemony 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 (67) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/README.md +176 -0
  3. package/RELEASE_CANDIDATE.md +37 -0
  4. package/dist/browser/index.cjs.js +2598 -0
  5. package/dist/browser/index.cjs.js.map +1 -0
  6. package/dist/browser/index.d.mts +184 -0
  7. package/dist/browser/index.d.ts +184 -0
  8. package/dist/browser/index.esm.js +2557 -0
  9. package/dist/browser/index.esm.js.map +1 -0
  10. package/dist/browser/pixel-bemony.global.js +9848 -0
  11. package/dist/browser/pixel-bemony.global.js.map +1 -0
  12. package/dist/createBemonyPixel-BGRD66p-.d.mts +474 -0
  13. package/dist/createBemonyPixel-BGRD66p-.d.ts +474 -0
  14. package/dist/index.cjs.js +2154 -0
  15. package/dist/index.cjs.js.map +1 -0
  16. package/dist/index.d.mts +320 -0
  17. package/dist/index.d.ts +320 -0
  18. package/dist/index.esm.js +2081 -0
  19. package/dist/index.esm.js.map +1 -0
  20. package/docs/BACKEND_PURCHASE_AND_REDIRECTS.md +125 -0
  21. package/docs/BROWSER_EVENT_ENRICHMENT.md +116 -0
  22. package/docs/SCENARIOS.md +92 -0
  23. package/docs/SECURITY_LIMITATIONS.md +45 -0
  24. package/docs/TEST_MATRIX.md +39 -0
  25. package/docs/TROUBLESHOOTING.md +81 -0
  26. package/examples/README.md +73 -0
  27. package/examples/browser-bootstrap.html +47 -0
  28. package/examples/checkout-price-code.html +37 -0
  29. package/examples/funnel/donsell/downsell_1.html +130 -0
  30. package/examples/funnel/donsell/downsell_2.html +130 -0
  31. package/examples/funnel/donsell/downsell_3.html +130 -0
  32. package/examples/funnel/offer-page.html +105 -0
  33. package/examples/funnel/upsell/upsell_1.html +130 -0
  34. package/examples/funnel/upsell/upsell_2.html +130 -0
  35. package/examples/funnel/upsell/upsell_3.html +139 -0
  36. package/examples/offer-page-price-code.html +22 -0
  37. package/examples/one-click-price-code.html +38 -0
  38. package/examples/security/checkout-sim.css +408 -0
  39. package/examples/security/checkout-sim.js +414 -0
  40. package/examples/security/one-click/pri_downsell_1.html +85 -0
  41. package/examples/security/one-click/pri_downsell_1a.html +85 -0
  42. package/examples/security/one-click/pri_downsell_1b.html +78 -0
  43. package/examples/security/one-click/pri_downsell_2.html +78 -0
  44. package/examples/security/one-click/pri_downsell_2a.html +78 -0
  45. package/examples/security/one-click/pri_downsell_2b.html +78 -0
  46. package/examples/security/one-click/pri_downsell_3.html +78 -0
  47. package/examples/security/one-click/pri_downsell_3a.html +78 -0
  48. package/examples/security/one-click/pri_downsell_3b.html +78 -0
  49. package/examples/security/one-click/pri_upsell_1.html +78 -0
  50. package/examples/security/one-click/pri_upsell_1a.html +78 -0
  51. package/examples/security/one-click/pri_upsell_1b.html +78 -0
  52. package/examples/security/one-click/pri_upsell_2.html +78 -0
  53. package/examples/security/one-click/pri_upsell_2a.html +78 -0
  54. package/examples/security/one-click/pri_upsell_2b.html +78 -0
  55. package/examples/security/one-click/pri_upsell_3.html +78 -0
  56. package/examples/security/one-click/pri_upsell_3a.html +78 -0
  57. package/examples/security/one-click/pri_upsell_3b.html +78 -0
  58. package/examples/security/one-click/pri_upsell_3c.html +78 -0
  59. package/examples/security/pri1766322.html +333 -0
  60. package/examples/security/pri5529930.html +333 -0
  61. package/examples/security/pri6670988.html +334 -0
  62. package/examples/security/thank-you.html +65 -0
  63. package/examples/sim/funnel-flow.js +258 -0
  64. package/examples/sim/one-click-sim.js +167 -0
  65. package/examples/upsell-price-code.html +41 -0
  66. package/examples/url-context-navigation.html +96 -0
  67. package/package.json +63 -0
@@ -0,0 +1,2557 @@
1
+ // src/createBemonyPixel.ts
2
+ import { prepareJourneyUrlContext } from "@beworke/pixel";
3
+ import {
4
+ createStorageAdapter,
5
+ StorageServiceImpl
6
+ } from "@beworke/pixel/services";
7
+
8
+ // src/BemonyPixel.ts
9
+ import {
10
+ Pixel
11
+ } from "@beworke/pixel";
12
+
13
+ // src/domain/BemonyLeadInput.ts
14
+ var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
15
+ var BLOCKED_FIELD_KEY = /^(card|cvv|cvc|pan|number|expiry|expiration|password|token|cvv2)/i;
16
+ function isValidBemonyLead(input) {
17
+ const email = input.email?.trim();
18
+ const phone = input.phone?.trim();
19
+ const emailOk = Boolean(email && EMAIL_PATTERN.test(email));
20
+ const phoneDigits = phone ? phone.replace(/\D/g, "") : "";
21
+ const phoneOk = phoneDigits.length >= 8;
22
+ return emailOk || phoneOk;
23
+ }
24
+ function leadFingerprint(input) {
25
+ const email = input.email?.trim().toLowerCase() ?? "";
26
+ const phone = input.phone?.replace(/\D/g, "") ?? "";
27
+ const name = input.name?.trim().toLowerCase() ?? "";
28
+ return `${email}|${phone}|${name}`;
29
+ }
30
+ function sanitizeLeadFields(fields) {
31
+ if (!fields) {
32
+ return void 0;
33
+ }
34
+ const result = {};
35
+ for (const [key, value] of Object.entries(fields)) {
36
+ if (BLOCKED_FIELD_KEY.test(key)) {
37
+ continue;
38
+ }
39
+ result[key] = value;
40
+ }
41
+ return Object.keys(result).length > 0 ? result : void 0;
42
+ }
43
+
44
+ // src/domain/BemonyPaymentMethodInput.ts
45
+ var BEMONY_PAYMENT_METHODS = [
46
+ "CREDIT_CARD",
47
+ "PIX",
48
+ "BOLETO",
49
+ "PAYPAL",
50
+ // 'GOOGLE_PAY',
51
+ // 'APPLE_PAY',
52
+ "OTHER"
53
+ ];
54
+ function isValidBemonyPaymentMethod(input) {
55
+ if (!input) {
56
+ return false;
57
+ }
58
+ return BEMONY_PAYMENT_METHODS.includes(
59
+ input.paymentMethod
60
+ );
61
+ }
62
+
63
+ // src/domain/resolvePriceCode.ts
64
+ function resolvePriceCode(input) {
65
+ if (!input) {
66
+ return { priceCode: null, conflict: false };
67
+ }
68
+ const fromCode = input.priceCode?.trim() || null;
69
+ const fromLegacy = input.priceId?.trim() || null;
70
+ if (fromCode && fromLegacy && fromCode !== fromLegacy) {
71
+ return { priceCode: fromCode, conflict: true };
72
+ }
73
+ return {
74
+ priceCode: fromCode ?? fromLegacy,
75
+ conflict: false
76
+ };
77
+ }
78
+
79
+ // src/BemonyPixel.ts
80
+ var SAFE_PUBLIC_ORDER_ID = /^[a-zA-Z0-9_.:-]+$/;
81
+ var MAX_PUBLIC_ORDER_ID_LENGTH = 128;
82
+ var BemonyLifecycleError = class extends Error {
83
+ constructor(options) {
84
+ super(options.message);
85
+ this.name = "BemonyLifecycleError";
86
+ this.code = options.code;
87
+ this.state = options.state;
88
+ if (options.cause !== void 0) {
89
+ this.cause = options.cause;
90
+ }
91
+ }
92
+ };
93
+ function requirePriceCode(input, method, state) {
94
+ const { priceCode, conflict } = resolvePriceCode(input);
95
+ if (!priceCode) {
96
+ throw new BemonyLifecycleError({
97
+ code: "INVALID_STATE",
98
+ message: `BemonyPixel.${method} requires priceCode.`,
99
+ state
100
+ });
101
+ }
102
+ if (conflict && typeof console !== "undefined" && console.debug) {
103
+ console.debug("[BemonyPixel] priceCode/priceId conflict; using priceCode", {
104
+ code: "BEMONY_PRICE_CODE_CONFLICT",
105
+ method
106
+ });
107
+ }
108
+ return priceCode;
109
+ }
110
+ function toViewContentData(input) {
111
+ const priceCode = resolvePriceCode(input).priceCode;
112
+ const contentType = input.productType === "downsell" ? "downsell" : input.productType === "upsell" ? "upsell" : "offer";
113
+ const observedValue = input.observedValue ?? input.price;
114
+ const observedCurrency = input.observedCurrency ?? input.currency;
115
+ return {
116
+ contentId: priceCode,
117
+ contentType,
118
+ productId: priceCode,
119
+ ...observedValue !== void 0 ? { value: observedValue } : {},
120
+ ...observedCurrency !== void 0 ? { currency: observedCurrency } : {}
121
+ };
122
+ }
123
+ function toAddToCartData(input) {
124
+ const priceCode = resolvePriceCode(input).priceCode;
125
+ const observedValue = input.observedValue ?? input.price;
126
+ const observedCurrency = input.observedCurrency ?? input.currency;
127
+ return {
128
+ productId: priceCode,
129
+ quantity: input.quantity ?? 1,
130
+ ...observedValue !== void 0 ? { price: observedValue } : {},
131
+ ...observedCurrency !== void 0 ? { currency: observedCurrency } : {}
132
+ };
133
+ }
134
+ function toLeadData(input) {
135
+ const fields = sanitizeLeadFields(input.fields);
136
+ return {
137
+ ...input.email !== void 0 ? { email: input.email.trim() } : {},
138
+ ...input.phone !== void 0 ? { phone: input.phone.trim() } : {},
139
+ ...input.name !== void 0 ? { name: input.name.trim() } : {},
140
+ ...fields !== void 0 ? { fields } : {}
141
+ };
142
+ }
143
+ var BemonyPixel = class {
144
+ constructor(options) {
145
+ this.state = "created";
146
+ this.initPromise = null;
147
+ this.destroyPromise = null;
148
+ this.wrapperListeners = /* @__PURE__ */ new Set();
149
+ this.checkoutStarted = false;
150
+ this.lastLeadFingerprint = null;
151
+ this.selectedBumpIds = /* @__PURE__ */ new Set();
152
+ this.config = options.config;
153
+ this.scenario = options.scenario;
154
+ this.publicOrderId = options.publicOrderId?.trim() || void 0;
155
+ this.publicContext = options.publicContext ? { ...options.publicContext } : {};
156
+ this.autoInitiateCheckoutEnabled = options.autoInitiateCheckout !== false;
157
+ this.noThanksUrl = options.noThanksUrl?.trim() || void 0;
158
+ const createCore = options.createCorePixel ?? ((config) => new Pixel(config));
159
+ this.core = createCore(options.config);
160
+ }
161
+ getScenario() {
162
+ return this.scenario;
163
+ }
164
+ getConfig() {
165
+ return this.config;
166
+ }
167
+ getState() {
168
+ return this.state;
169
+ }
170
+ isInitialized() {
171
+ return this.state === "ready" && this.core.isInitialized();
172
+ }
173
+ getDebugSnapshot() {
174
+ return this.core.getDebugSnapshot();
175
+ }
176
+ /**
177
+ * `publicOrderId` do domínio do app (não mapeado para identity do Core).
178
+ * Fallback opcional: param `oid` da URL atual.
179
+ */
180
+ getPublicOrderId() {
181
+ if (this.publicOrderId) {
182
+ return this.publicOrderId;
183
+ }
184
+ if (typeof window === "undefined" || typeof window.location === "undefined") {
185
+ return null;
186
+ }
187
+ try {
188
+ return new URL(window.location.href).searchParams.get("oid");
189
+ } catch {
190
+ return null;
191
+ }
192
+ }
193
+ /**
194
+ * Define `publicOrderId` e propaga para managed param `oid` quando suportado.
195
+ */
196
+ setPublicOrderId(orderId) {
197
+ const trimmed = orderId.trim();
198
+ if (!trimmed || trimmed.length > MAX_PUBLIC_ORDER_ID_LENGTH) {
199
+ throw new BemonyLifecycleError({
200
+ code: "INVALID_STATE",
201
+ message: "setPublicOrderId requires a non-empty orderId within max length.",
202
+ state: this.state
203
+ });
204
+ }
205
+ if (!SAFE_PUBLIC_ORDER_ID.test(trimmed)) {
206
+ throw new BemonyLifecycleError({
207
+ code: "INVALID_STATE",
208
+ message: "setPublicOrderId orderId contains invalid characters.",
209
+ state: this.state
210
+ });
211
+ }
212
+ if (this.publicOrderId === trimmed) {
213
+ return;
214
+ }
215
+ this.publicOrderId = trimmed;
216
+ this.applyPublicOrderIdToManagedParam();
217
+ }
218
+ getPublicSessionId() {
219
+ if (typeof window === "undefined" || typeof window.location === "undefined") {
220
+ return null;
221
+ }
222
+ try {
223
+ return new URL(window.location.href).searchParams.get("sid");
224
+ } catch {
225
+ return null;
226
+ }
227
+ }
228
+ selectOffer(input) {
229
+ this.assertReady("selectOffer");
230
+ requirePriceCode(input, "selectOffer", this.state);
231
+ this.core.addToCart(toAddToCartData(input));
232
+ }
233
+ /**
234
+ * Inicia checkout → `Pixel.initiateCheckout()`.
235
+ * Idempotente: no máximo uma vez por lifecycle da instância.
236
+ */
237
+ startCheckout(input) {
238
+ this.assertReady("startCheckout");
239
+ if (this.checkoutStarted) {
240
+ return;
241
+ }
242
+ const data = input ? {
243
+ ...input.value !== void 0 ? { value: input.value } : {},
244
+ ...input.currency !== void 0 ? { currency: input.currency } : {}
245
+ } : void 0;
246
+ this.core.initiateCheckout(data);
247
+ this.checkoutStarted = true;
248
+ }
249
+ /**
250
+ * Captura lead → `Pixel.lead()`.
251
+ * Campos incompletos não disparam. Mesmo fingerprint não reenvia (debounce).
252
+ */
253
+ captureLead(input) {
254
+ this.assertReady("captureLead");
255
+ if (!isValidBemonyLead(input)) {
256
+ return false;
257
+ }
258
+ const fingerprint = leadFingerprint(input);
259
+ if (this.lastLeadFingerprint === fingerprint) {
260
+ return false;
261
+ }
262
+ this.core.lead(toLeadData(input));
263
+ this.lastLeadFingerprint = fingerprint;
264
+ return true;
265
+ }
266
+ selectOrderBump(input) {
267
+ this.assertReady("selectOrderBump");
268
+ const priceCode = requirePriceCode(input, "selectOrderBump", this.state);
269
+ this.core.addToCart(toAddToCartData(input));
270
+ this.selectedBumpIds.add(priceCode);
271
+ }
272
+ removeOrderBump(input) {
273
+ this.assertReady("removeOrderBump");
274
+ const priceCode = requirePriceCode(input, "removeOrderBump", this.state);
275
+ if (!this.selectedBumpIds.has(priceCode)) {
276
+ return;
277
+ }
278
+ this.core.removeFromCart({
279
+ // No adaptador Bemony, o campo genérico productId transporta o priceCode.
280
+ productId: priceCode,
281
+ ...input.quantity !== void 0 ? { quantity: input.quantity } : {}
282
+ });
283
+ this.selectedBumpIds.delete(priceCode);
284
+ }
285
+ trackPaymentMethod(input) {
286
+ this.assertReady("trackPaymentMethod");
287
+ if (!isValidBemonyPaymentMethod(input)) {
288
+ throw new BemonyLifecycleError({
289
+ code: "INVALID_STATE",
290
+ message: "trackPaymentMethod requires a valid paymentMethod enum.",
291
+ state: this.state
292
+ });
293
+ }
294
+ this.core.addPaymentInfo({ paymentMethod: input.paymentMethod });
295
+ }
296
+ viewUpsell(input) {
297
+ this.assertReady("viewUpsell");
298
+ requirePriceCode(input, "viewUpsell", this.state);
299
+ this.core.viewContent(toViewContentData(input));
300
+ }
301
+ acceptUpsell(input) {
302
+ this.assertReady("acceptUpsell");
303
+ requirePriceCode(input, "acceptUpsell", this.state);
304
+ this.core.addToCart(toAddToCartData(input));
305
+ }
306
+ /**
307
+ * Recusa de upsell/downsell — callback/navegação apenas.
308
+ * Destino: `navigateTo` explícito, senão `noThanksUrl` (data-no-thanks).
309
+ */
310
+ declineUpsell(options) {
311
+ this.assertReady("declineUpsell");
312
+ try {
313
+ options?.onDecline?.();
314
+ } finally {
315
+ const explicitTarget = options?.navigateTo?.trim() || this.noThanksUrl || void 0;
316
+ const target = explicitTarget ? this.decorateNavigateUrl(explicitTarget) : void 0;
317
+ if (target && typeof window !== "undefined" && typeof window.location?.assign === "function") {
318
+ window.location.assign(target);
319
+ }
320
+ }
321
+ }
322
+ /**
323
+ * Intenção de confirmação one-click → `Pixel.addToCart()`.
324
+ * Não processa pagamento e **não** emite PURCHASE.
325
+ */
326
+ trackOneClickConfirmation(input) {
327
+ this.assertReady("trackOneClickConfirmation");
328
+ this.assertOneClickReady("trackOneClickConfirmation");
329
+ requirePriceCode(input, "trackOneClickConfirmation", this.state);
330
+ this.core.addToCart(toAddToCartData(input));
331
+ }
332
+ init() {
333
+ if (this.state === "ready") {
334
+ return Promise.resolve();
335
+ }
336
+ if (this.state === "initializing" && this.initPromise) {
337
+ return this.initPromise;
338
+ }
339
+ if (this.state === "destroying" && this.destroyPromise) {
340
+ this.initPromise = this.destroyPromise.catch(() => void 0).then(() => this.startInit());
341
+ return this.initPromise;
342
+ }
343
+ this.initPromise = this.startInit();
344
+ return this.initPromise;
345
+ }
346
+ destroy() {
347
+ if (this.state === "destroyed") {
348
+ return Promise.resolve();
349
+ }
350
+ if (this.state === "destroying" && this.destroyPromise) {
351
+ return this.destroyPromise;
352
+ }
353
+ if (this.state === "initializing" && this.initPromise) {
354
+ this.destroyPromise = this.initPromise.catch(() => void 0).then(() => this.startDestroy());
355
+ return this.destroyPromise;
356
+ }
357
+ this.destroyPromise = this.startDestroy();
358
+ return this.destroyPromise;
359
+ }
360
+ addWrapperListener(cleanup) {
361
+ this.wrapperListeners.add(cleanup);
362
+ return () => {
363
+ this.wrapperListeners.delete(cleanup);
364
+ };
365
+ }
366
+ assertReady(method) {
367
+ if (this.state !== "ready") {
368
+ throw new BemonyLifecycleError({
369
+ code: "INVALID_STATE",
370
+ message: `BemonyPixel.${method} requires state "ready" (current: "${this.state}").`,
371
+ state: this.state
372
+ });
373
+ }
374
+ }
375
+ assertOneClickReady(method) {
376
+ if (!this.getPublicOrderId()) {
377
+ throw new BemonyLifecycleError({
378
+ code: "INVALID_STATE",
379
+ message: `BemonyPixel.${method} requires publicOrderId.`,
380
+ state: this.state
381
+ });
382
+ }
383
+ }
384
+ applyPublicOrderIdToManagedParam() {
385
+ if (!this.publicOrderId || !this.core.setManagedUrlParam) {
386
+ return;
387
+ }
388
+ this.core.setManagedUrlParam("oid", this.publicOrderId);
389
+ }
390
+ decorateNavigateUrl(rawUrl) {
391
+ try {
392
+ const base = typeof window !== "undefined" && window.location?.href ? window.location.href : "https://localhost/";
393
+ const url = new URL(rawUrl, base);
394
+ const sid = this.getPublicSessionId();
395
+ const oid = this.getPublicOrderId();
396
+ const fid = this.publicContext.funnelId;
397
+ const fsid = this.publicContext.funnelStepId;
398
+ const afid = this.publicContext.affiliateId;
399
+ if (sid && !url.searchParams.has("sid")) {
400
+ url.searchParams.set("sid", sid);
401
+ }
402
+ if (oid && !url.searchParams.has("oid")) {
403
+ url.searchParams.set("oid", oid);
404
+ }
405
+ if (fid && !url.searchParams.has("fid")) {
406
+ url.searchParams.set("fid", fid);
407
+ }
408
+ if (fsid && !url.searchParams.has("fsid")) {
409
+ url.searchParams.set("fsid", fsid);
410
+ }
411
+ if (afid && !url.searchParams.has("afid")) {
412
+ url.searchParams.set("afid", afid);
413
+ }
414
+ return url.toString();
415
+ } catch {
416
+ return rawUrl;
417
+ }
418
+ }
419
+ maybeAutoInitiateCheckout() {
420
+ if (this.scenario !== "checkout" && this.scenario !== "one-click-checkout") {
421
+ return;
422
+ }
423
+ if (!this.autoInitiateCheckoutEnabled || this.checkoutStarted) {
424
+ return;
425
+ }
426
+ this.core.initiateCheckout();
427
+ this.checkoutStarted = true;
428
+ }
429
+ resetDomainState() {
430
+ this.checkoutStarted = false;
431
+ this.lastLeadFingerprint = null;
432
+ this.selectedBumpIds.clear();
433
+ this.publicOrderId = void 0;
434
+ }
435
+ startInit() {
436
+ this.state = "initializing";
437
+ return this.core.init().then(() => {
438
+ if (this.publicOrderId) {
439
+ this.applyPublicOrderIdToManagedParam();
440
+ }
441
+ }).then(() => {
442
+ this.state = "ready";
443
+ this.maybeAutoInitiateCheckout();
444
+ }).catch((error) => {
445
+ this.state = "failed";
446
+ return this.safeCoreDestroy().then(() => {
447
+ throw new BemonyLifecycleError({
448
+ code: "INIT_FAILED",
449
+ message: "BemonyPixel init failed.",
450
+ state: this.state,
451
+ cause: error
452
+ });
453
+ });
454
+ }).finally(() => {
455
+ this.initPromise = null;
456
+ });
457
+ }
458
+ startDestroy() {
459
+ this.state = "destroying";
460
+ return this.safeCoreDestroy().then(() => {
461
+ this.clearWrapperListeners();
462
+ this.resetDomainState();
463
+ this.state = "destroyed";
464
+ }).catch((error) => {
465
+ this.clearWrapperListeners();
466
+ this.resetDomainState();
467
+ this.state = "destroyed";
468
+ throw new BemonyLifecycleError({
469
+ code: "DESTROY_FAILED",
470
+ message: "BemonyPixel destroy failed.",
471
+ state: this.state,
472
+ cause: error
473
+ });
474
+ }).finally(() => {
475
+ this.destroyPromise = null;
476
+ });
477
+ }
478
+ async safeCoreDestroy() {
479
+ await this.core.destroy();
480
+ }
481
+ clearWrapperListeners() {
482
+ for (const cleanup of this.wrapperListeners) {
483
+ try {
484
+ cleanup();
485
+ } catch {
486
+ }
487
+ }
488
+ this.wrapperListeners.clear();
489
+ }
490
+ };
491
+
492
+ // src/createBemonyPixelConfig.ts
493
+ import { DEFAULT_PIXEL_CONFIG } from "@beworke/pixel";
494
+
495
+ // src/domain/BemonyPageContext.ts
496
+ var BemonyValidationError = class extends Error {
497
+ constructor(options) {
498
+ super(options.message);
499
+ this.name = "BemonyValidationError";
500
+ this.code = options.code;
501
+ this.field = options.field;
502
+ this.scenario = options.scenario;
503
+ }
504
+ };
505
+ function isBemonyPageContextInput(value) {
506
+ return typeof value === "object" && value !== null && "public" in value && typeof value.public === "object" && value.public !== null;
507
+ }
508
+ function normalizePublicPriceFields(publicContext) {
509
+ const priceCode = publicContext.priceCode?.trim() || void 0;
510
+ const priceId = publicContext.priceId?.trim() || void 0;
511
+ const { priceId: _legacy, ...rest } = publicContext;
512
+ if (priceCode) {
513
+ return { ...rest, priceCode };
514
+ }
515
+ if (priceId) {
516
+ return { ...rest, priceCode: priceId };
517
+ }
518
+ return { ...rest };
519
+ }
520
+ function normalizeBemonyPageContextInput(page) {
521
+ if (!page) {
522
+ return { public: {} };
523
+ }
524
+ if (isBemonyPageContextInput(page)) {
525
+ return {
526
+ public: normalizePublicPriceFields({ ...page.public })
527
+ };
528
+ }
529
+ return {
530
+ public: normalizePublicPriceFields({ ...page })
531
+ };
532
+ }
533
+
534
+ // src/domain/resolveBemonyPageContext.ts
535
+ var PUBLIC_URL_PARAM_TO_FIELD = {
536
+ page_id: "pageId",
537
+ funnel_id: "funnelId",
538
+ funnel_step_id: "funnelStepId",
539
+ offer_id: "offerId",
540
+ product_id: "productId",
541
+ price_code: "priceCode",
542
+ price_id: "priceCode",
543
+ checkout_id: "checkoutId",
544
+ afid: "affiliateId",
545
+ fid: "funnelId",
546
+ fsid: "funnelStepId",
547
+ oid: "publicOrderId"
548
+ };
549
+ function pickDefined(source) {
550
+ if (!source) {
551
+ return {};
552
+ }
553
+ const result = {};
554
+ for (const key of Object.keys(source)) {
555
+ const value = source[key];
556
+ if (value !== void 0 && value !== "") {
557
+ result[key] = value;
558
+ }
559
+ }
560
+ return result;
561
+ }
562
+ function publicContextFromUrlParams(urlParams) {
563
+ if (!urlParams) {
564
+ return {};
565
+ }
566
+ const result = {};
567
+ for (const [rawKey, rawValue] of Object.entries(urlParams)) {
568
+ const field = PUBLIC_URL_PARAM_TO_FIELD[rawKey];
569
+ if (!field) {
570
+ continue;
571
+ }
572
+ if (rawValue === void 0 || rawValue === "") {
573
+ continue;
574
+ }
575
+ result[field] = rawValue;
576
+ }
577
+ return result;
578
+ }
579
+ function resolveBemonyPageContext(sources = {}) {
580
+ const fromScenario = pickDefined(sources.scenarioDefaults);
581
+ const fromMetadata = pickDefined(sources.pageMetadata);
582
+ const fromUrl = publicContextFromUrlParams(sources.urlParams);
583
+ const fromInput = pickDefined(sources.input);
584
+ return {
585
+ ...fromScenario,
586
+ ...fromMetadata,
587
+ ...fromUrl,
588
+ ...fromInput
589
+ };
590
+ }
591
+
592
+ // src/domain/validateBemonyPageContext.ts
593
+ var MAX_ID_LENGTH = 128;
594
+ var SAFE_ID_PATTERN = /^[a-zA-Z0-9_.:-]+$/;
595
+ var REQUIRED_PUBLIC_FIELDS = {
596
+ "offer-page": [],
597
+ checkout: [],
598
+ "upsell-offer": [],
599
+ "one-click-checkout": [
600
+ "publicOrderId",
601
+ "funnelId",
602
+ "funnelStepId",
603
+ "priceCode"
604
+ ],
605
+ "thank-you": []
606
+ };
607
+ function assertSafePublicId(field, value, scenario) {
608
+ const trimmed = value.trim();
609
+ if (!trimmed) {
610
+ throw new BemonyValidationError({
611
+ code: "INVALID_FIELD",
612
+ field,
613
+ scenario,
614
+ message: `Field "${field}" cannot be empty for scenario "${scenario}".`
615
+ });
616
+ }
617
+ if (trimmed.length > MAX_ID_LENGTH) {
618
+ throw new BemonyValidationError({
619
+ code: "INVALID_FIELD",
620
+ field,
621
+ scenario,
622
+ message: `Field "${field}" exceeds maximum length of ${MAX_ID_LENGTH}.`
623
+ });
624
+ }
625
+ if (!SAFE_ID_PATTERN.test(trimmed)) {
626
+ throw new BemonyValidationError({
627
+ code: "INVALID_FIELD",
628
+ field,
629
+ scenario,
630
+ message: `Field "${field}" contains invalid characters.`
631
+ });
632
+ }
633
+ return trimmed;
634
+ }
635
+ function validateBemonyPageContext(options) {
636
+ const { scenario } = options;
637
+ const sanitize = options.sanitize !== false;
638
+ const required = REQUIRED_PUBLIC_FIELDS[scenario];
639
+ const source = options.publicContext;
640
+ const result = {};
641
+ for (const field of Object.keys(
642
+ source
643
+ )) {
644
+ const value = source[field];
645
+ if (value === void 0) {
646
+ continue;
647
+ }
648
+ result[field] = sanitize ? assertSafePublicId(field, value, scenario) : value;
649
+ }
650
+ for (const field of required) {
651
+ if (!result[field]) {
652
+ throw new BemonyValidationError({
653
+ code: "MISSING_REQUIRED_FIELD",
654
+ field,
655
+ scenario,
656
+ message: `Field "${field}" is required for scenario "${scenario}".`
657
+ });
658
+ }
659
+ }
660
+ return result;
661
+ }
662
+
663
+ // src/platform/defaults.ts
664
+ var BEMONY_STORAGE_PREFIX = "__bemony_pixel";
665
+ var BEMONY_DEFAULT_NAMESPACE = "bemony-web";
666
+ var BEMONY_DEFAULT_API_ENDPOINT = "https://micro-service-pixel-production-4826.up.railway.app";
667
+ var BEMONY_DEFAULT_PIXEL_ID = "pix_7704308";
668
+ var BEMONY_DEFAULT_ALLOWED_DOMAINS = [
669
+ "security.bemony.com",
670
+ /** Serve HTTP local (`pnpm dlx serve`). */
671
+ "localhost",
672
+ "127.0.0.1",
673
+ /**
674
+ * Sentinel interno: permite links relativos / `file://` (hostname vazio)
675
+ * no LinkDecorator — só para simulação local dos examples.
676
+ */
677
+ "local"
678
+ ];
679
+ var BEMONY_DEFAULT_BROWSER_ENVIRONMENT = "production";
680
+ var BEMONY_DEFAULT_BROWSER_SCENARIO = "offer-page";
681
+ var BEMONY_BROWSER_AUTO_INIT_DEFAULTS = Object.freeze({
682
+ environment: BEMONY_DEFAULT_BROWSER_ENVIRONMENT,
683
+ scenario: BEMONY_DEFAULT_BROWSER_SCENARIO,
684
+ platform: Object.freeze({
685
+ pixelId: BEMONY_DEFAULT_PIXEL_ID,
686
+ apiEndpoint: BEMONY_DEFAULT_API_ENDPOINT,
687
+ namespace: BEMONY_DEFAULT_NAMESPACE,
688
+ allowedDomains: Object.freeze([...BEMONY_DEFAULT_ALLOWED_DOMAINS])
689
+ })
690
+ });
691
+ var BEMONY_PLATFORM_DEFAULTS = {
692
+ app: {
693
+ source: "bemony"
694
+ },
695
+ storage: {
696
+ prefix: BEMONY_STORAGE_PREFIX,
697
+ namespace: BEMONY_DEFAULT_NAMESPACE,
698
+ persistence: {
699
+ visitor: "localStorage",
700
+ session: "sessionStorage",
701
+ attribution: "localStorage"
702
+ }
703
+ },
704
+ attribution: {
705
+ enabled: true,
706
+ persist: true,
707
+ captureUrlParams: true,
708
+ captureCookies: true
709
+ }
710
+ };
711
+ function applyBemonyPlatformDefaults(base, platform) {
712
+ const namespace = platform.namespace ?? BEMONY_DEFAULT_NAMESPACE;
713
+ return {
714
+ ...base,
715
+ app: {
716
+ ...base.app,
717
+ source: BEMONY_PLATFORM_DEFAULTS.app.source
718
+ },
719
+ identity: {
720
+ ...base.identity,
721
+ pixelId: platform.pixelId
722
+ },
723
+ storage: {
724
+ ...base.storage,
725
+ prefix: BEMONY_PLATFORM_DEFAULTS.storage.prefix,
726
+ namespace,
727
+ persistence: {
728
+ ...base.storage.persistence,
729
+ ...BEMONY_PLATFORM_DEFAULTS.storage.persistence
730
+ }
731
+ },
732
+ attribution: {
733
+ ...base.attribution,
734
+ ...BEMONY_PLATFORM_DEFAULTS.attribution,
735
+ customClickIdParams: base.attribution.customClickIdParams ? [...base.attribution.customClickIdParams] : []
736
+ }
737
+ };
738
+ }
739
+
740
+ // src/navigation/BemonyLinkPolicy.ts
741
+ function normalizeAllowedDomain(domain) {
742
+ let value = domain.trim().toLowerCase();
743
+ value = value.replace(/^https?:\/\//, "");
744
+ value = value.split("/")[0] ?? value;
745
+ value = value.split("?")[0] ?? value;
746
+ value = value.split("#")[0] ?? value;
747
+ const withoutPort = value.replace(/:\d+$/, "");
748
+ return withoutPort;
749
+ }
750
+ function normalizeAllowedDomains(domains) {
751
+ const seen = /* @__PURE__ */ new Set();
752
+ const result = [];
753
+ for (const raw of domains) {
754
+ const normalized = normalizeAllowedDomain(raw);
755
+ if (!normalized || seen.has(normalized)) continue;
756
+ seen.add(normalized);
757
+ result.push(normalized);
758
+ }
759
+ return result;
760
+ }
761
+ function createBemonyLinkPolicy(options = {}) {
762
+ const sourceDomains = options.allowedDomains !== void 0 && options.allowedDomains.length > 0 ? options.allowedDomains : BEMONY_DEFAULT_ALLOWED_DOMAINS;
763
+ const allowedDomains = normalizeAllowedDomains([...sourceDomains]);
764
+ const selector = options.selector?.trim();
765
+ return {
766
+ allowedDomains,
767
+ ...selector ? { selector } : {},
768
+ strategy: options.strategy ?? "both",
769
+ preserveExisting: options.preserveExisting ?? true,
770
+ overwriteExisting: options.overwriteExisting ?? false,
771
+ decorateMailto: false,
772
+ decorateTel: false,
773
+ decorateHashLinks: false,
774
+ mergeDefaultExcludedDomains: true,
775
+ mergeDefaultExcludeSelectors: true,
776
+ excludeSelectors: options.excludeSelectors ? [...options.excludeSelectors] : void 0
777
+ };
778
+ }
779
+ function linkPolicyToDecorationConfig(policy) {
780
+ return {
781
+ enabled: true,
782
+ strategy: policy.strategy,
783
+ allowedDomains: [...policy.allowedDomains],
784
+ ...policy.selector ? { selector: policy.selector } : {},
785
+ preserveExisting: policy.preserveExisting,
786
+ overwriteExisting: policy.overwriteExisting,
787
+ decorateMailto: policy.decorateMailto,
788
+ decorateTel: policy.decorateTel,
789
+ decorateHashLinks: policy.decorateHashLinks,
790
+ mergeDefaultExcludedDomains: policy.mergeDefaultExcludedDomains,
791
+ mergeDefaultExcludeSelectors: policy.mergeDefaultExcludeSelectors,
792
+ ...policy.excludeSelectors ? { excludeSelectors: [...policy.excludeSelectors] } : {}
793
+ };
794
+ }
795
+
796
+ // src/navigation/configureBemonyLinks.ts
797
+ var BEMONY_SID_MANAGED_PARAM = {
798
+ key: "public_session",
799
+ param: "sid",
800
+ mode: "read_write",
801
+ writeStrategy: "replaceState",
802
+ generator: { type: "public_id", prefix: "sid" },
803
+ persistence: {
804
+ enabled: true,
805
+ strategy: "localStorage_cookie",
806
+ storageKey: "sid"
807
+ },
808
+ decorateLinks: true
809
+ };
810
+ var BEMONY_AFID_MANAGED_PARAM = {
811
+ key: "affiliate",
812
+ param: "afid",
813
+ mode: "read_write",
814
+ writeStrategy: "replaceState",
815
+ persistence: {
816
+ enabled: true,
817
+ strategy: "localStorage_cookie",
818
+ storageKey: "afid"
819
+ },
820
+ decorateLinks: true
821
+ };
822
+ var BEMONY_OID_MANAGED_PARAM = {
823
+ key: "order_id",
824
+ param: "oid",
825
+ mode: "read_write",
826
+ writeStrategy: "replaceState",
827
+ persistence: {
828
+ enabled: true,
829
+ strategy: "localStorage_cookie",
830
+ storageKey: "oid"
831
+ },
832
+ decorateLinks: true
833
+ };
834
+ var BEMONY_FID_MANAGED_PARAM = {
835
+ key: "funnel_id",
836
+ param: "fid",
837
+ mode: "read_write",
838
+ writeStrategy: "replaceState",
839
+ persistence: {
840
+ enabled: true,
841
+ strategy: "localStorage_cookie",
842
+ storageKey: "fid"
843
+ },
844
+ decorateLinks: true
845
+ };
846
+ var BEMONY_FSID_MANAGED_PARAM = {
847
+ key: "funnel_step_id",
848
+ param: "fsid",
849
+ mode: "read_write",
850
+ writeStrategy: "replaceState",
851
+ persistence: {
852
+ enabled: true,
853
+ strategy: "localStorage_cookie",
854
+ storageKey: "fsid"
855
+ },
856
+ decorateLinks: true
857
+ };
858
+ var BEMONY_FORWARD_DENYLIST = [
859
+ "token",
860
+ "one_click_token",
861
+ "oneclicktoken",
862
+ "oneClickToken",
863
+ "ephemeral_token",
864
+ "payment_token",
865
+ "access_token",
866
+ "refresh_token",
867
+ "id_token",
868
+ "auth_token",
869
+ "secret",
870
+ "password",
871
+ "pass",
872
+ "pwd",
873
+ "email",
874
+ "phone",
875
+ "cpf",
876
+ "cnpj",
877
+ "document",
878
+ "card",
879
+ "cc",
880
+ "credit_card",
881
+ "pan",
882
+ "cvv",
883
+ "cvc",
884
+ "auth",
885
+ "code",
886
+ "sessionid",
887
+ "internalsessionid",
888
+ "pixelsessionid"
889
+ ];
890
+ function cloneManagedParam(param) {
891
+ return {
892
+ ...param,
893
+ ...param.generator ? { generator: { ...param.generator } } : {},
894
+ ...param.persistence ? {
895
+ persistence: {
896
+ ...param.persistence,
897
+ ...param.persistence.cookie ? { cookie: { ...param.persistence.cookie } } : {}
898
+ }
899
+ } : {}
900
+ };
901
+ }
902
+ function configureBemonyLinks(options = {}) {
903
+ const policy = createBemonyLinkPolicy(options);
904
+ const includeSid = options.includeSidManagedParam !== false;
905
+ const includeAfid = options.includeAfidManagedParam !== false;
906
+ const includeOid = options.includeOidManagedParam !== false;
907
+ const includeFunnel = options.includeFunnelManagedParams !== false;
908
+ const managedParams = [];
909
+ if (includeSid) {
910
+ managedParams.push(cloneManagedParam(BEMONY_SID_MANAGED_PARAM));
911
+ }
912
+ if (includeAfid) {
913
+ managedParams.push(cloneManagedParam(BEMONY_AFID_MANAGED_PARAM));
914
+ }
915
+ if (includeOid) {
916
+ managedParams.push(cloneManagedParam(BEMONY_OID_MANAGED_PARAM));
917
+ }
918
+ if (includeFunnel) {
919
+ managedParams.push(cloneManagedParam(BEMONY_FID_MANAGED_PARAM));
920
+ managedParams.push(cloneManagedParam(BEMONY_FSID_MANAGED_PARAM));
921
+ }
922
+ const denylist = [...BEMONY_FORWARD_DENYLIST];
923
+ return {
924
+ enabled: true,
925
+ queryParams: {
926
+ enabled: true,
927
+ mode: "all_except",
928
+ mergeDefaultDenylist: true,
929
+ denylist: [...denylist]
930
+ },
931
+ managedParams,
932
+ forwardParams: {
933
+ enabled: true,
934
+ mode: "all_except",
935
+ mergeDefaultDenylist: true,
936
+ denylist: [...denylist]
937
+ },
938
+ linkDecoration: linkPolicyToDecorationConfig(policy)
939
+ };
940
+ }
941
+
942
+ // src/platform/environments.ts
943
+ var BEMONY_ENVIRONMENTS = [
944
+ "development",
945
+ "staging",
946
+ "production"
947
+ ];
948
+ function isNonEmptyEndpoint(value) {
949
+ return typeof value === "string" && value.trim().length > 0;
950
+ }
951
+ function resolveBemonyEnvironment(options) {
952
+ const { environment } = options;
953
+ if (environment === "development") {
954
+ return {
955
+ environment,
956
+ debug: options.debugOverride ?? true,
957
+ apiEndpoint: isNonEmptyEndpoint(options.apiEndpoint) ? options.apiEndpoint.trim() : "",
958
+ transportEnabled: false,
959
+ senderMode: "mock"
960
+ };
961
+ }
962
+ if (environment === "staging" || environment === "production") {
963
+ if (!isNonEmptyEndpoint(options.apiEndpoint)) {
964
+ throw new BemonyValidationError({
965
+ code: "MISSING_ENDPOINT",
966
+ field: "apiEndpoint",
967
+ message: `apiEndpoint is required for environment "${environment}". Inject an approved endpoint; do not hardcode credentials.`
968
+ });
969
+ }
970
+ return {
971
+ environment,
972
+ debug: options.debugOverride ?? false,
973
+ apiEndpoint: options.apiEndpoint.trim(),
974
+ transportEnabled: true,
975
+ senderMode: "http"
976
+ };
977
+ }
978
+ throw new BemonyValidationError({
979
+ code: "INVALID_ENVIRONMENT",
980
+ field: "environment",
981
+ message: "Unsupported Bemony environment."
982
+ });
983
+ }
984
+ function applyBemonyEnvironment(base, resolution) {
985
+ return {
986
+ ...base,
987
+ app: {
988
+ ...base.app,
989
+ environment: resolution.environment,
990
+ debug: resolution.debug
991
+ },
992
+ transport: {
993
+ ...base.transport,
994
+ apiEndpoint: resolution.apiEndpoint
995
+ },
996
+ modules: {
997
+ ...base.modules,
998
+ transport: {
999
+ ...base.modules.transport,
1000
+ enabled: resolution.transportEnabled,
1001
+ sender: {
1002
+ ...base.modules.transport.sender,
1003
+ mode: resolution.senderMode
1004
+ },
1005
+ mockSender: {
1006
+ ...base.modules.transport.mockSender,
1007
+ enabled: resolution.senderMode === "mock"
1008
+ }
1009
+ }
1010
+ }
1011
+ };
1012
+ }
1013
+
1014
+ // src/scenarios/checkout.ts
1015
+ function resolveMainProductId(products) {
1016
+ if (!products || products.length === 0) {
1017
+ return void 0;
1018
+ }
1019
+ const main = products.find((product) => product.type === "main");
1020
+ return (main ?? products[0])?.id;
1021
+ }
1022
+ function applyCheckoutScenario(base, options = {
1023
+ autoInitiateCheckout: true,
1024
+ includeOidManagedParam: true
1025
+ }) {
1026
+ const products = (options.products ?? []).map((product) => ({ ...product }));
1027
+ const currency = options.currency ?? base.commerce.currency ?? "BRL";
1028
+ const mainProductId = resolveMainProductId(products);
1029
+ const autoInitiateCheckout = options.autoInitiateCheckout !== false;
1030
+ const allowedDomains = normalizeAllowedDomains(
1031
+ options.allowedDomains !== void 0 && options.allowedDomains.length > 0 ? [...options.allowedDomains] : [...BEMONY_DEFAULT_ALLOWED_DOMAINS]
1032
+ );
1033
+ const urlContext = configureBemonyLinks({
1034
+ allowedDomains,
1035
+ includeOidManagedParam: options.includeOidManagedParam ?? true
1036
+ });
1037
+ const conversionManual = {
1038
+ ...base.modules.conversion.manual,
1039
+ lead: { enabled: true },
1040
+ addToCart: { enabled: true },
1041
+ removeFromCart: { enabled: true },
1042
+ initiateCheckout: { enabled: true },
1043
+ addPaymentInfo: { enabled: true },
1044
+ viewContent: { enabled: false },
1045
+ pageView: { enabled: false },
1046
+ purchase: { enabled: false },
1047
+ search: { enabled: false }
1048
+ };
1049
+ return {
1050
+ ...base,
1051
+ app: {
1052
+ ...base.app,
1053
+ target: "checkout",
1054
+ source: "bemony"
1055
+ },
1056
+ commerce: {
1057
+ ...base.commerce,
1058
+ enabled: true,
1059
+ currency,
1060
+ catalog: { products },
1061
+ cart: {
1062
+ ...base.commerce.cart,
1063
+ mode: "checkout",
1064
+ initialItems: mainProductId ? [{ productId: mainProductId, quantity: 1 }] : [],
1065
+ allowDynamicItems: true,
1066
+ calculateValueFrom: "cart"
1067
+ },
1068
+ mappings: {
1069
+ attributes: { ...base.commerce.mappings?.attributes ?? {} },
1070
+ fields: { ...base.commerce.mappings?.fields ?? {} }
1071
+ },
1072
+ enrichment: {
1073
+ ...base.commerce.enrichment ?? {},
1074
+ initiateCheckout: { enabled: true, source: "cart" },
1075
+ lead: { enabled: false, source: "event_or_cart" },
1076
+ addToCart: { enabled: true, source: "event_or_cart" },
1077
+ removeFromCart: { enabled: true, source: "event_or_cart" },
1078
+ addPaymentInfo: { enabled: true, source: "cart" },
1079
+ purchase: { enabled: false, source: "cart" },
1080
+ viewContent: { enabled: false, source: "event_or_cart" },
1081
+ pageView: { enabled: false, source: "cart" }
1082
+ }
1083
+ },
1084
+ modules: {
1085
+ ...base.modules,
1086
+ core: {
1087
+ ...base.modules.core,
1088
+ enabled: true,
1089
+ pageView: {
1090
+ ...base.modules.core.pageView,
1091
+ enabled: true,
1092
+ trackInitialPageView: true
1093
+ },
1094
+ urlContext
1095
+ },
1096
+ conversion: {
1097
+ ...base.modules.conversion,
1098
+ enabled: true,
1099
+ manual: conversionManual,
1100
+ auto: {
1101
+ enabled: true,
1102
+ detectors: {
1103
+ ...base.modules.conversion.auto.detectors,
1104
+ addToCart: {
1105
+ enabled: true,
1106
+ sources: [
1107
+ {
1108
+ name: "main-product-after-contact",
1109
+ type: "form",
1110
+ selectorForm: {
1111
+ fields: ["email", "phone"],
1112
+ mode: "all",
1113
+ formSelector: "#checkout-form",
1114
+ trigger: "input",
1115
+ debounceMs: 300,
1116
+ fireOnce: true
1117
+ }
1118
+ },
1119
+ {
1120
+ name: "product-or-bump-click",
1121
+ type: "selector",
1122
+ selector: "add_to_cart",
1123
+ selectorType: "attribute",
1124
+ trigger: "click",
1125
+ fireOnce: false
1126
+ }
1127
+ ]
1128
+ },
1129
+ removeFromCart: {
1130
+ enabled: true,
1131
+ sources: [
1132
+ {
1133
+ name: "remove-product-click",
1134
+ type: "selector",
1135
+ selector: "remove_from_cart",
1136
+ selectorType: "attribute",
1137
+ trigger: "click"
1138
+ }
1139
+ ]
1140
+ },
1141
+ initiateCheckout: {
1142
+ enabled: autoInitiateCheckout,
1143
+ sources: autoInitiateCheckout ? [
1144
+ {
1145
+ name: "checkout-loaded",
1146
+ type: "lifecycle",
1147
+ trigger: "ready",
1148
+ fireOnce: true
1149
+ }
1150
+ ] : []
1151
+ },
1152
+ addPaymentInfo: {
1153
+ enabled: true,
1154
+ sources: [
1155
+ {
1156
+ name: "credit-card-detection",
1157
+ type: "payment",
1158
+ paymentMethod: "CREDIT_CARD",
1159
+ cardDetection: true,
1160
+ autoDispatch: true,
1161
+ formSelector: "#checkout-form",
1162
+ fireOnce: true
1163
+ },
1164
+ {
1165
+ name: "payment-button-click",
1166
+ type: "selector",
1167
+ selector: '[data-track="add_payment_info"]',
1168
+ selectorType: "css",
1169
+ trigger: "click",
1170
+ fireOnce: false
1171
+ }
1172
+ ]
1173
+ }
1174
+ }
1175
+ }
1176
+ },
1177
+ behavior: {
1178
+ ...base.modules.behavior,
1179
+ enabled: false
1180
+ }
1181
+ }
1182
+ };
1183
+ }
1184
+
1185
+ // src/scenarios/one-click-checkout.ts
1186
+ function resolveCartMode(products) {
1187
+ const list = products ?? [];
1188
+ const isUpsellLike = list.some(
1189
+ (product) => product.type === "upsell" || product.type === "downsell"
1190
+ );
1191
+ return isUpsellLike ? "upsell" : "checkout";
1192
+ }
1193
+ function resolvePrimaryProductId(products) {
1194
+ if (!products || products.length === 0) {
1195
+ return void 0;
1196
+ }
1197
+ const preferred = products.find(
1198
+ (product) => product.type === "upsell" || product.type === "downsell" || product.type === "main"
1199
+ );
1200
+ return (preferred ?? products[0])?.id;
1201
+ }
1202
+ function applyOneClickCheckoutScenario(base, options = {}) {
1203
+ const products = (options.products ?? []).map((product) => ({ ...product }));
1204
+ const currency = options.currency ?? base.commerce.currency ?? "BRL";
1205
+ const cartMode = resolveCartMode(products);
1206
+ const primaryId = resolvePrimaryProductId(products);
1207
+ const urlContext = configureBemonyLinks({
1208
+ allowedDomains: options.allowedDomains ? [...options.allowedDomains] : [],
1209
+ includeOidManagedParam: true
1210
+ });
1211
+ const conversionManual = {
1212
+ ...base.modules.conversion.manual,
1213
+ initiateCheckout: { enabled: true },
1214
+ addToCart: { enabled: true },
1215
+ viewContent: { enabled: false },
1216
+ lead: { enabled: false },
1217
+ removeFromCart: { enabled: false },
1218
+ addPaymentInfo: { enabled: false },
1219
+ pageView: { enabled: false },
1220
+ purchase: { enabled: false },
1221
+ search: { enabled: false }
1222
+ };
1223
+ return {
1224
+ ...base,
1225
+ app: {
1226
+ ...base.app,
1227
+ target: "checkout"
1228
+ },
1229
+ commerce: {
1230
+ ...base.commerce,
1231
+ enabled: true,
1232
+ currency,
1233
+ catalog: { products },
1234
+ cart: {
1235
+ ...base.commerce.cart,
1236
+ mode: cartMode,
1237
+ initialItems: primaryId ? [{ productId: primaryId, quantity: 1 }] : [],
1238
+ allowDynamicItems: true,
1239
+ calculateValueFrom: "cart"
1240
+ },
1241
+ mappings: {
1242
+ attributes: { ...base.commerce.mappings?.attributes ?? {} },
1243
+ fields: { ...base.commerce.mappings?.fields ?? {} }
1244
+ },
1245
+ enrichment: {
1246
+ ...base.commerce.enrichment ?? {},
1247
+ initiateCheckout: { enabled: true, source: "cart" },
1248
+ addToCart: { enabled: true, source: "event_or_cart" },
1249
+ purchase: { enabled: false, source: "cart" },
1250
+ lead: { enabled: false, source: "event_or_cart" },
1251
+ viewContent: { enabled: false, source: "event_or_cart" },
1252
+ pageView: { enabled: false, source: "cart" }
1253
+ }
1254
+ },
1255
+ modules: {
1256
+ ...base.modules,
1257
+ core: {
1258
+ ...base.modules.core,
1259
+ enabled: true,
1260
+ pageView: {
1261
+ ...base.modules.core.pageView,
1262
+ enabled: true,
1263
+ trackInitialPageView: true
1264
+ },
1265
+ urlContext
1266
+ },
1267
+ conversion: {
1268
+ ...base.modules.conversion,
1269
+ enabled: true,
1270
+ manual: conversionManual,
1271
+ auto: {
1272
+ ...base.modules.conversion.auto,
1273
+ enabled: false
1274
+ }
1275
+ },
1276
+ behavior: {
1277
+ ...base.modules.behavior,
1278
+ enabled: false
1279
+ }
1280
+ }
1281
+ };
1282
+ }
1283
+
1284
+ // src/navigation/createBemonyOfferLinkSource.ts
1285
+ function createBemonyOfferLinkSource(allowedDomains) {
1286
+ const hostnames = normalizeAllowedDomains([...allowedDomains]).filter(
1287
+ (host) => host !== "local"
1288
+ );
1289
+ return {
1290
+ name: "bemony-offer-link",
1291
+ type: "link",
1292
+ enabled: true,
1293
+ trigger: "click",
1294
+ fireOnce: false,
1295
+ match: {
1296
+ protocols: ["https:", "http:"],
1297
+ hostnames,
1298
+ path: {
1299
+ segmentPrefixes: ["pri"]
1300
+ }
1301
+ },
1302
+ bindings: {
1303
+ // Core LinkAuto reconhece priceCode; productId no evento = priceCode observado.
1304
+ priceCode: {
1305
+ from: {
1306
+ source: "pathSegment",
1307
+ index: -1
1308
+ },
1309
+ required: true
1310
+ }
1311
+ }
1312
+ };
1313
+ }
1314
+
1315
+ // src/scenarios/offer-page.ts
1316
+ function applyOfferPageScenario(base, options = {}) {
1317
+ const cartMode = options.cartMode ?? "landing_page";
1318
+ const products = (options.products ?? []).map((product) => ({ ...product }));
1319
+ const currency = options.currency ?? base.commerce.currency ?? "BRL";
1320
+ const allowedDomains = normalizeAllowedDomains(
1321
+ options.allowedDomains !== void 0 && options.allowedDomains.length > 0 ? [...options.allowedDomains] : [...BEMONY_DEFAULT_ALLOWED_DOMAINS]
1322
+ );
1323
+ const urlContext = configureBemonyLinks({ allowedDomains });
1324
+ const offerLinkSource = createBemonyOfferLinkSource(allowedDomains);
1325
+ const conversionManual = {
1326
+ ...base.modules.conversion.manual,
1327
+ viewContent: { enabled: true },
1328
+ addToCart: { enabled: true },
1329
+ // Offer page não emite estes manualmente nesta etapa.
1330
+ pageView: { enabled: false },
1331
+ purchase: { enabled: false },
1332
+ lead: { enabled: false },
1333
+ removeFromCart: { enabled: false },
1334
+ initiateCheckout: { enabled: false },
1335
+ addPaymentInfo: { enabled: false },
1336
+ search: { enabled: false }
1337
+ };
1338
+ return {
1339
+ ...base,
1340
+ app: {
1341
+ ...base.app,
1342
+ target: "landing"
1343
+ },
1344
+ commerce: {
1345
+ ...base.commerce,
1346
+ enabled: true,
1347
+ currency,
1348
+ catalog: { products },
1349
+ cart: {
1350
+ ...base.commerce.cart,
1351
+ mode: cartMode,
1352
+ initialItems: base.commerce.cart?.initialItems ? base.commerce.cart.initialItems.map((item) => ({ ...item })) : [],
1353
+ allowDynamicItems: true,
1354
+ calculateValueFrom: "cart"
1355
+ },
1356
+ mappings: {
1357
+ attributes: { ...base.commerce.mappings?.attributes ?? {} },
1358
+ fields: { ...base.commerce.mappings?.fields ?? {} }
1359
+ },
1360
+ enrichment: {
1361
+ ...base.commerce.enrichment ?? {},
1362
+ viewContent: { enabled: true, source: "event_or_cart" },
1363
+ addToCart: { enabled: true, source: "event_or_cart" },
1364
+ pageView: { enabled: false, source: "cart" },
1365
+ purchase: { enabled: false, source: "cart" },
1366
+ lead: { enabled: false, source: "event_or_cart" }
1367
+ }
1368
+ },
1369
+ modules: {
1370
+ ...base.modules,
1371
+ core: {
1372
+ ...base.modules.core,
1373
+ enabled: true,
1374
+ pageView: {
1375
+ ...base.modules.core.pageView,
1376
+ enabled: true,
1377
+ trackInitialPageView: true
1378
+ },
1379
+ urlContext
1380
+ },
1381
+ conversion: {
1382
+ ...base.modules.conversion,
1383
+ enabled: true,
1384
+ manual: conversionManual,
1385
+ auto: {
1386
+ ...base.modules.conversion.auto,
1387
+ enabled: true,
1388
+ detectors: {
1389
+ ...base.modules.conversion.auto.detectors,
1390
+ addToCart: {
1391
+ enabled: true,
1392
+ sources: [offerLinkSource]
1393
+ }
1394
+ }
1395
+ }
1396
+ },
1397
+ behavior: {
1398
+ ...base.modules.behavior,
1399
+ enabled: false
1400
+ }
1401
+ }
1402
+ };
1403
+ }
1404
+
1405
+ // src/scenarios/thank-you.ts
1406
+ function applyThankYouScenario(base, options = {}) {
1407
+ const currency = options.currency ?? base.commerce.currency ?? "BRL";
1408
+ const urlContext = configureBemonyLinks({
1409
+ allowedDomains: options.allowedDomains ? [...options.allowedDomains] : [],
1410
+ includeOidManagedParam: true
1411
+ });
1412
+ const conversionManual = {
1413
+ ...base.modules.conversion.manual,
1414
+ pageView: { enabled: false },
1415
+ purchase: { enabled: false },
1416
+ lead: { enabled: false },
1417
+ addToCart: { enabled: false },
1418
+ removeFromCart: { enabled: false },
1419
+ initiateCheckout: { enabled: false },
1420
+ addPaymentInfo: { enabled: false },
1421
+ search: { enabled: false },
1422
+ viewContent: { enabled: false }
1423
+ };
1424
+ return {
1425
+ ...base,
1426
+ app: {
1427
+ ...base.app,
1428
+ target: "custom"
1429
+ },
1430
+ commerce: {
1431
+ ...base.commerce,
1432
+ enabled: false,
1433
+ currency,
1434
+ catalog: { products: [] },
1435
+ cart: {
1436
+ ...base.commerce.cart,
1437
+ mode: "custom",
1438
+ initialItems: [],
1439
+ allowDynamicItems: false,
1440
+ calculateValueFrom: "cart"
1441
+ },
1442
+ enrichment: {
1443
+ ...base.commerce.enrichment ?? {},
1444
+ purchase: { enabled: false, source: "cart" },
1445
+ pageView: { enabled: false, source: "cart" }
1446
+ }
1447
+ },
1448
+ modules: {
1449
+ ...base.modules,
1450
+ core: {
1451
+ ...base.modules.core,
1452
+ enabled: true,
1453
+ pageView: {
1454
+ ...base.modules.core.pageView,
1455
+ enabled: true,
1456
+ trackInitialPageView: true
1457
+ },
1458
+ urlContext
1459
+ },
1460
+ conversion: {
1461
+ ...base.modules.conversion,
1462
+ enabled: false,
1463
+ manual: conversionManual,
1464
+ auto: {
1465
+ ...base.modules.conversion.auto,
1466
+ enabled: false
1467
+ }
1468
+ },
1469
+ behavior: {
1470
+ ...base.modules.behavior,
1471
+ enabled: false
1472
+ }
1473
+ }
1474
+ };
1475
+ }
1476
+
1477
+ // src/scenarios/upsell-offer.ts
1478
+ var BEMONY_UPSELL_BUY_LINK_SELECTOR = 'a[href*="pri"], [data-bemony-offer][href]';
1479
+ function escapeCssAttributeValue(value) {
1480
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
1481
+ return CSS.escape(value);
1482
+ }
1483
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
1484
+ }
1485
+ function buildUpsellLinkSelector(noThanksUrl) {
1486
+ const raw = noThanksUrl?.trim();
1487
+ if (!raw) {
1488
+ return BEMONY_UPSELL_BUY_LINK_SELECTOR;
1489
+ }
1490
+ return `${BEMONY_UPSELL_BUY_LINK_SELECTOR}, a[href="${escapeCssAttributeValue(raw)}"]`;
1491
+ }
1492
+ function applyUpsellOfferScenario(base, options = {}) {
1493
+ const products = (options.products ?? []).map((product) => ({ ...product }));
1494
+ const currency = options.currency ?? base.commerce.currency ?? "BRL";
1495
+ const allowedDomains = normalizeAllowedDomains(
1496
+ options.allowedDomains !== void 0 && options.allowedDomains.length > 0 ? [...options.allowedDomains] : [...BEMONY_DEFAULT_ALLOWED_DOMAINS]
1497
+ );
1498
+ const urlContext = configureBemonyLinks({
1499
+ allowedDomains,
1500
+ selector: buildUpsellLinkSelector(options.noThanksUrl),
1501
+ includeOidManagedParam: options.includeOidManagedParam ?? true
1502
+ });
1503
+ const offerLinkSource = createBemonyOfferLinkSource(allowedDomains);
1504
+ const conversionManual = {
1505
+ ...base.modules.conversion.manual,
1506
+ viewContent: { enabled: true },
1507
+ addToCart: { enabled: true },
1508
+ pageView: { enabled: false },
1509
+ purchase: { enabled: false },
1510
+ lead: { enabled: false },
1511
+ removeFromCart: { enabled: false },
1512
+ initiateCheckout: { enabled: false },
1513
+ addPaymentInfo: { enabled: false },
1514
+ search: { enabled: false }
1515
+ };
1516
+ return {
1517
+ ...base,
1518
+ app: {
1519
+ ...base.app,
1520
+ target: "custom"
1521
+ },
1522
+ commerce: {
1523
+ ...base.commerce,
1524
+ enabled: true,
1525
+ currency,
1526
+ catalog: { products },
1527
+ cart: {
1528
+ ...base.commerce.cart,
1529
+ mode: "upsell",
1530
+ initialItems: [],
1531
+ allowDynamicItems: true,
1532
+ calculateValueFrom: "cart"
1533
+ },
1534
+ mappings: {
1535
+ attributes: { ...base.commerce.mappings?.attributes ?? {} },
1536
+ fields: { ...base.commerce.mappings?.fields ?? {} }
1537
+ },
1538
+ enrichment: {
1539
+ ...base.commerce.enrichment ?? {},
1540
+ viewContent: { enabled: true, source: "event_or_cart" },
1541
+ addToCart: { enabled: true, source: "event_or_cart" },
1542
+ pageView: { enabled: false, source: "cart" },
1543
+ purchase: { enabled: false, source: "cart" },
1544
+ lead: { enabled: false, source: "event_or_cart" },
1545
+ initiateCheckout: { enabled: false, source: "cart" }
1546
+ }
1547
+ },
1548
+ modules: {
1549
+ ...base.modules,
1550
+ core: {
1551
+ ...base.modules.core,
1552
+ enabled: true,
1553
+ pageView: {
1554
+ ...base.modules.core.pageView,
1555
+ enabled: true,
1556
+ trackInitialPageView: true
1557
+ },
1558
+ urlContext
1559
+ },
1560
+ conversion: {
1561
+ ...base.modules.conversion,
1562
+ enabled: true,
1563
+ manual: conversionManual,
1564
+ auto: {
1565
+ ...base.modules.conversion.auto,
1566
+ enabled: true,
1567
+ detectors: {
1568
+ ...base.modules.conversion.auto.detectors,
1569
+ addToCart: {
1570
+ enabled: true,
1571
+ sources: [offerLinkSource]
1572
+ }
1573
+ }
1574
+ }
1575
+ },
1576
+ behavior: {
1577
+ ...base.modules.behavior,
1578
+ enabled: false
1579
+ }
1580
+ }
1581
+ };
1582
+ }
1583
+
1584
+ // src/createBemonyPixelConfig.ts
1585
+ var SCENARIO_TARGET = {
1586
+ "offer-page": "landing",
1587
+ checkout: "checkout",
1588
+ "upsell-offer": "custom",
1589
+ "one-click-checkout": "checkout",
1590
+ "thank-you": "custom"
1591
+ };
1592
+ var SCENARIO_CART_MODE = {
1593
+ "offer-page": "landing_page",
1594
+ checkout: "checkout",
1595
+ "upsell-offer": "upsell",
1596
+ "one-click-checkout": "checkout",
1597
+ "thank-you": "custom"
1598
+ };
1599
+ var PRODUCT_TYPES = /* @__PURE__ */ new Set([
1600
+ "main",
1601
+ "order_bump",
1602
+ "upsell",
1603
+ "downsell",
1604
+ "cross_sell",
1605
+ "addon",
1606
+ "subscription",
1607
+ "custom",
1608
+ "other"
1609
+ ]);
1610
+ function cloneProducts(products) {
1611
+ if (!products) {
1612
+ return [];
1613
+ }
1614
+ return products.map((product) => {
1615
+ const type = product.type && PRODUCT_TYPES.has(product.type) ? product.type : void 0;
1616
+ return {
1617
+ id: product.id,
1618
+ ...product.name !== void 0 ? { name: product.name } : {},
1619
+ ...type !== void 0 ? { type } : {},
1620
+ ...product.price !== void 0 ? { price: product.price } : {},
1621
+ ...product.currency !== void 0 ? { currency: product.currency } : {},
1622
+ ...product.quantity !== void 0 ? { quantity: product.quantity } : {}
1623
+ };
1624
+ });
1625
+ }
1626
+ function resolveOfferPageCartMode(commerce) {
1627
+ if (commerce?.cartMode === "single_product") {
1628
+ return "single_product";
1629
+ }
1630
+ return "landing_page";
1631
+ }
1632
+ function mapPublicContextToIdentity(base, publicContext) {
1633
+ return {
1634
+ ...base,
1635
+ ...publicContext.pageId !== void 0 ? { pageId: publicContext.pageId } : {},
1636
+ ...publicContext.funnelId !== void 0 ? { funnelId: publicContext.funnelId } : {},
1637
+ ...publicContext.funnelStepId !== void 0 ? { funnelStepId: publicContext.funnelStepId } : {},
1638
+ ...publicContext.offerId !== void 0 ? { offerId: publicContext.offerId } : {},
1639
+ ...publicContext.affiliateId !== void 0 ? { affiliateId: publicContext.affiliateId } : {},
1640
+ ...publicContext.checkoutId !== void 0 ? { checkoutId: publicContext.checkoutId } : {}
1641
+ };
1642
+ }
1643
+ function applyMinimalScenarioPreset(base, scenario, commerce, allowedDomains) {
1644
+ const products = cloneProducts(commerce?.products);
1645
+ const currency = commerce?.currency ?? base.commerce.currency ?? "BRL";
1646
+ const urlContext = configureBemonyLinks({
1647
+ allowedDomains: allowedDomains ? [...allowedDomains] : []
1648
+ });
1649
+ return {
1650
+ ...base,
1651
+ app: {
1652
+ ...base.app,
1653
+ target: SCENARIO_TARGET[scenario],
1654
+ debug: true
1655
+ },
1656
+ commerce: {
1657
+ ...base.commerce,
1658
+ enabled: true,
1659
+ currency,
1660
+ catalog: {
1661
+ products
1662
+ },
1663
+ cart: {
1664
+ ...base.commerce.cart,
1665
+ mode: SCENARIO_CART_MODE[scenario],
1666
+ initialItems: base.commerce.cart?.initialItems ? base.commerce.cart.initialItems.map((item) => ({ ...item })) : [],
1667
+ allowDynamicItems: true,
1668
+ calculateValueFrom: "cart"
1669
+ },
1670
+ mappings: {
1671
+ attributes: { ...base.commerce.mappings?.attributes ?? {} },
1672
+ fields: { ...base.commerce.mappings?.fields ?? {} }
1673
+ },
1674
+ enrichment: {
1675
+ ...base.commerce.enrichment ?? {}
1676
+ }
1677
+ },
1678
+ modules: {
1679
+ ...base.modules,
1680
+ core: {
1681
+ ...base.modules.core,
1682
+ urlContext
1683
+ },
1684
+ conversion: {
1685
+ ...base.modules.conversion,
1686
+ enabled: false
1687
+ },
1688
+ behavior: {
1689
+ ...base.modules.behavior,
1690
+ enabled: false
1691
+ }
1692
+ }
1693
+ };
1694
+ }
1695
+ function applyScenarioPreset(base, scenario, commerce, allowedDomains, autoInitiateCheckout, noThanksUrl) {
1696
+ if (scenario === "offer-page") {
1697
+ return applyOfferPageScenario(base, {
1698
+ allowedDomains,
1699
+ currency: commerce?.currency,
1700
+ cartMode: resolveOfferPageCartMode(commerce),
1701
+ products: cloneProducts(commerce?.products)
1702
+ });
1703
+ }
1704
+ if (scenario === "checkout") {
1705
+ return applyCheckoutScenario(base, {
1706
+ allowedDomains,
1707
+ currency: commerce?.currency,
1708
+ products: cloneProducts(commerce?.products),
1709
+ autoInitiateCheckout
1710
+ });
1711
+ }
1712
+ if (scenario === "upsell-offer") {
1713
+ return applyUpsellOfferScenario(base, {
1714
+ allowedDomains,
1715
+ currency: commerce?.currency,
1716
+ products: cloneProducts(commerce?.products),
1717
+ ...noThanksUrl ? { noThanksUrl } : {}
1718
+ });
1719
+ }
1720
+ if (scenario === "one-click-checkout") {
1721
+ return applyOneClickCheckoutScenario(base, {
1722
+ allowedDomains,
1723
+ currency: commerce?.currency,
1724
+ products: cloneProducts(commerce?.products)
1725
+ });
1726
+ }
1727
+ if (scenario === "thank-you") {
1728
+ return applyThankYouScenario(base, {
1729
+ allowedDomains,
1730
+ currency: commerce?.currency
1731
+ });
1732
+ }
1733
+ return applyMinimalScenarioPreset(base, scenario, commerce, allowedDomains);
1734
+ }
1735
+ function createBemonyPixelConfig(options) {
1736
+ const pageInput = normalizeBemonyPageContextInput(options.page);
1737
+ const resolvedPublic = resolveBemonyPageContext({
1738
+ input: pageInput.public,
1739
+ urlParams: options.urlParams,
1740
+ pageMetadata: options.pageMetadata,
1741
+ scenarioDefaults: options.scenarioDefaults
1742
+ });
1743
+ const validatedPublic = validateBemonyPageContext({
1744
+ scenario: options.scenario,
1745
+ publicContext: resolvedPublic
1746
+ });
1747
+ const apiEndpoint = options.overrides?.apiEndpoint ?? options.platform.apiEndpoint;
1748
+ const debugOverride = options.overrides?.debug ?? options.platform.debug;
1749
+ const allowedDomains = options.overrides?.allowedDomains ?? options.platform.allowedDomains;
1750
+ const envResolution = resolveBemonyEnvironment({
1751
+ environment: options.environment,
1752
+ apiEndpoint,
1753
+ debugOverride
1754
+ });
1755
+ let config = {
1756
+ ...DEFAULT_PIXEL_CONFIG,
1757
+ app: { ...DEFAULT_PIXEL_CONFIG.app },
1758
+ identity: { ...DEFAULT_PIXEL_CONFIG.identity },
1759
+ transport: { ...DEFAULT_PIXEL_CONFIG.transport },
1760
+ storage: {
1761
+ ...DEFAULT_PIXEL_CONFIG.storage,
1762
+ queue: DEFAULT_PIXEL_CONFIG.storage.queue ? { ...DEFAULT_PIXEL_CONFIG.storage.queue } : void 0,
1763
+ keys: DEFAULT_PIXEL_CONFIG.storage.keys ? { ...DEFAULT_PIXEL_CONFIG.storage.keys } : void 0,
1764
+ persistence: DEFAULT_PIXEL_CONFIG.storage.persistence ? { ...DEFAULT_PIXEL_CONFIG.storage.persistence } : void 0
1765
+ },
1766
+ attribution: {
1767
+ ...DEFAULT_PIXEL_CONFIG.attribution,
1768
+ customClickIdParams: DEFAULT_PIXEL_CONFIG.attribution.customClickIdParams ? [...DEFAULT_PIXEL_CONFIG.attribution.customClickIdParams] : []
1769
+ },
1770
+ commerce: {
1771
+ ...DEFAULT_PIXEL_CONFIG.commerce,
1772
+ catalog: {
1773
+ products: DEFAULT_PIXEL_CONFIG.commerce.catalog?.products ? DEFAULT_PIXEL_CONFIG.commerce.catalog.products.map((p) => ({
1774
+ ...p
1775
+ })) : []
1776
+ },
1777
+ cart: {
1778
+ ...DEFAULT_PIXEL_CONFIG.commerce.cart,
1779
+ initialItems: DEFAULT_PIXEL_CONFIG.commerce.cart?.initialItems ? DEFAULT_PIXEL_CONFIG.commerce.cart.initialItems.map((i) => ({
1780
+ ...i
1781
+ })) : []
1782
+ },
1783
+ mappings: {
1784
+ attributes: {
1785
+ ...DEFAULT_PIXEL_CONFIG.commerce.mappings?.attributes ?? {}
1786
+ },
1787
+ fields: { ...DEFAULT_PIXEL_CONFIG.commerce.mappings?.fields ?? {} }
1788
+ },
1789
+ enrichment: { ...DEFAULT_PIXEL_CONFIG.commerce.enrichment ?? {} }
1790
+ },
1791
+ modules: {
1792
+ core: { ...DEFAULT_PIXEL_CONFIG.modules.core },
1793
+ behavior: { ...DEFAULT_PIXEL_CONFIG.modules.behavior },
1794
+ conversion: { ...DEFAULT_PIXEL_CONFIG.modules.conversion },
1795
+ transport: {
1796
+ ...DEFAULT_PIXEL_CONFIG.modules.transport,
1797
+ sender: { ...DEFAULT_PIXEL_CONFIG.modules.transport.sender },
1798
+ mockSender: { ...DEFAULT_PIXEL_CONFIG.modules.transport.mockSender }
1799
+ },
1800
+ integrations: { ...DEFAULT_PIXEL_CONFIG.modules.integrations },
1801
+ privacy: { ...DEFAULT_PIXEL_CONFIG.modules.privacy }
1802
+ }
1803
+ };
1804
+ config = applyBemonyPlatformDefaults(config, options.platform);
1805
+ config = applyBemonyEnvironment(config, envResolution);
1806
+ config = applyScenarioPreset(
1807
+ config,
1808
+ options.scenario,
1809
+ options.commerce,
1810
+ allowedDomains,
1811
+ options.autoInitiateCheckout,
1812
+ options.noThanksUrl
1813
+ );
1814
+ config = {
1815
+ ...config,
1816
+ identity: mapPublicContextToIdentity(config.identity, validatedPublic)
1817
+ };
1818
+ return config;
1819
+ }
1820
+
1821
+ // src/createBemonyPixel.ts
1822
+ function createJourneyStorage() {
1823
+ return new StorageServiceImpl(
1824
+ createStorageAdapter("localStorage"),
1825
+ "bemony",
1826
+ "urlctx"
1827
+ );
1828
+ }
1829
+ function seedJourneyManagedParams(journey, publicContext) {
1830
+ if (publicContext.funnelId) {
1831
+ journey.setManagedParam("fid", publicContext.funnelId);
1832
+ }
1833
+ if (publicContext.funnelStepId) {
1834
+ journey.setManagedParam("fsid", publicContext.funnelStepId);
1835
+ }
1836
+ if (publicContext.publicOrderId) {
1837
+ journey.setManagedParam("oid", publicContext.publicOrderId);
1838
+ }
1839
+ if (publicContext.affiliateId) {
1840
+ journey.setManagedParam("afid", publicContext.affiliateId);
1841
+ }
1842
+ }
1843
+ async function createBemonyPixel(options) {
1844
+ const pageInput = normalizeBemonyPageContextInput(options.page);
1845
+ const publicContext = validateBemonyPageContext({
1846
+ scenario: options.scenario,
1847
+ publicContext: resolveBemonyPageContext({
1848
+ input: pageInput.public,
1849
+ urlParams: options.urlParams,
1850
+ pageMetadata: options.pageMetadata,
1851
+ scenarioDefaults: options.scenarioDefaults
1852
+ })
1853
+ });
1854
+ const allowedDomains = options.overrides?.allowedDomains ?? options.platform.allowedDomains;
1855
+ const journeyUrlConfig = configureBemonyLinks({
1856
+ allowedDomains: allowedDomains ? [...allowedDomains] : []
1857
+ });
1858
+ const journeyStorage = createJourneyStorage();
1859
+ const journey = prepareJourneyUrlContext(journeyUrlConfig, journeyStorage);
1860
+ seedJourneyManagedParams(journey, publicContext);
1861
+ const config = createBemonyPixelConfig({
1862
+ ...options,
1863
+ page: { public: publicContext }
1864
+ });
1865
+ const construct = {
1866
+ config,
1867
+ scenario: options.scenario,
1868
+ publicOrderId: publicContext.publicOrderId,
1869
+ publicContext,
1870
+ autoInitiateCheckout: options.autoInitiateCheckout,
1871
+ ...options.noThanksUrl ? { noThanksUrl: options.noThanksUrl } : {},
1872
+ ...options.createCorePixel ? { createCorePixel: options.createCorePixel } : {}
1873
+ };
1874
+ try {
1875
+ const instance = new BemonyPixel(construct);
1876
+ await instance.init();
1877
+ return instance;
1878
+ } finally {
1879
+ journey.destroy();
1880
+ }
1881
+ }
1882
+
1883
+ // src/browser/errors.ts
1884
+ var BemonyBootstrapError = class extends Error {
1885
+ constructor(message, code, cause) {
1886
+ super(message);
1887
+ this.name = "BemonyBootstrapError";
1888
+ this.code = code;
1889
+ if (cause !== void 0) {
1890
+ this.cause = cause;
1891
+ }
1892
+ }
1893
+ };
1894
+
1895
+ // src/browser/events.ts
1896
+ var BEMONY_PIXEL_READY_EVENT = "bemony:pixel:ready";
1897
+ var BEMONY_PIXEL_ERROR_EVENT = "bemony:pixel:error";
1898
+ var BEMONY_PIXEL_INITIALIZING_EVENT = "bemony:pixel:initializing";
1899
+ var BEMONY_PIXEL_DESTROYED_EVENT = "bemony:pixel:destroyed";
1900
+ function safeDispatch(type, detail) {
1901
+ if (typeof window === "undefined" || typeof CustomEvent === "undefined") {
1902
+ return;
1903
+ }
1904
+ try {
1905
+ window.dispatchEvent(new CustomEvent(type, { detail }));
1906
+ } catch {
1907
+ }
1908
+ }
1909
+ function emitBemonyPixelReady(pixel) {
1910
+ safeDispatch(BEMONY_PIXEL_READY_EVENT, {
1911
+ pixel
1912
+ });
1913
+ }
1914
+ function emitBemonyPixelError(code, message) {
1915
+ safeDispatch(BEMONY_PIXEL_ERROR_EVENT, {
1916
+ code,
1917
+ message
1918
+ });
1919
+ }
1920
+ function emitBemonyPixelInitializing() {
1921
+ safeDispatch(BEMONY_PIXEL_INITIALIZING_EVENT, {});
1922
+ }
1923
+ function emitBemonyPixelDestroyed() {
1924
+ safeDispatch(BEMONY_PIXEL_DESTROYED_EVENT, {});
1925
+ }
1926
+
1927
+ // src/browser/bootstrap.ts
1928
+ var WINDOW_STORE_KEY = "__bemony_pixel_bootstrap__";
1929
+ function assertBrowser() {
1930
+ if (typeof window === "undefined") {
1931
+ throw new BemonyBootstrapError(
1932
+ "bootstrapBemonyPixel s\xF3 pode ser usado no browser (window ausente).",
1933
+ "NOT_BROWSER"
1934
+ );
1935
+ }
1936
+ }
1937
+ function getStore() {
1938
+ assertBrowser();
1939
+ const win = window;
1940
+ if (!win[WINDOW_STORE_KEY]) {
1941
+ win[WINDOW_STORE_KEY] = {
1942
+ instance: null,
1943
+ pending: null,
1944
+ readyEmittedFor: null
1945
+ };
1946
+ }
1947
+ return win[WINDOW_STORE_KEY];
1948
+ }
1949
+ function isReusableInstance(instance) {
1950
+ const state = instance.getState();
1951
+ return state === "ready" || state === "initializing";
1952
+ }
1953
+ async function bootstrapBemonyPixel(options) {
1954
+ assertBrowser();
1955
+ const store = getStore();
1956
+ const { force = false, waitForConsent, ...pixelOptions } = options;
1957
+ if (!force) {
1958
+ if (store.pending) {
1959
+ return store.pending;
1960
+ }
1961
+ if (store.instance && isReusableInstance(store.instance)) {
1962
+ return store.instance;
1963
+ }
1964
+ }
1965
+ if (force) {
1966
+ if (store.pending) {
1967
+ try {
1968
+ await store.pending;
1969
+ } catch {
1970
+ }
1971
+ store.pending = null;
1972
+ }
1973
+ if (store.instance) {
1974
+ try {
1975
+ await store.instance.destroy();
1976
+ } catch {
1977
+ }
1978
+ store.instance = null;
1979
+ store.readyEmittedFor = null;
1980
+ }
1981
+ }
1982
+ if (waitForConsent) {
1983
+ const allowed = await waitForConsent();
1984
+ if (!allowed) {
1985
+ const error = new BemonyBootstrapError(
1986
+ "Consentimento negado \u2014 bootstrap abortado.",
1987
+ "CONSENT_DENIED"
1988
+ );
1989
+ emitBemonyPixelError(error.code, error.message);
1990
+ throw error;
1991
+ }
1992
+ }
1993
+ emitBemonyPixelInitializing();
1994
+ const pending = createBemonyPixel(pixelOptions).then((instance) => {
1995
+ store.instance = instance;
1996
+ if (store.pending === pending) {
1997
+ store.pending = null;
1998
+ }
1999
+ if (store.readyEmittedFor !== instance) {
2000
+ emitBemonyPixelReady(instance);
2001
+ store.readyEmittedFor = instance;
2002
+ }
2003
+ return instance;
2004
+ }).catch((error) => {
2005
+ if (store.pending === pending) {
2006
+ store.pending = null;
2007
+ }
2008
+ const code = error instanceof BemonyBootstrapError ? error.code : "AUTO_INIT_FAILED";
2009
+ const message = error instanceof Error ? error.message : "Bootstrap falhou";
2010
+ emitBemonyPixelError(code, message);
2011
+ throw error;
2012
+ });
2013
+ store.pending = pending;
2014
+ return pending;
2015
+ }
2016
+ function getBootstrappedBemonyPixel() {
2017
+ if (typeof window === "undefined") {
2018
+ return null;
2019
+ }
2020
+ const store = window[WINDOW_STORE_KEY];
2021
+ return store?.instance ?? null;
2022
+ }
2023
+ function getBootstrappedBemonyPixelPending() {
2024
+ if (typeof window === "undefined") {
2025
+ return null;
2026
+ }
2027
+ const store = window[WINDOW_STORE_KEY];
2028
+ return store?.pending ?? null;
2029
+ }
2030
+ async function destroyBootstrappedBemonyPixel() {
2031
+ if (typeof window === "undefined") {
2032
+ return;
2033
+ }
2034
+ const store = getStore();
2035
+ if (store.pending) {
2036
+ try {
2037
+ await store.pending;
2038
+ } catch {
2039
+ }
2040
+ store.pending = null;
2041
+ }
2042
+ if (store.instance) {
2043
+ await store.instance.destroy();
2044
+ store.instance = null;
2045
+ store.readyEmittedFor = null;
2046
+ emitBemonyPixelDestroyed();
2047
+ }
2048
+ }
2049
+
2050
+ // src/scenarios/types.ts
2051
+ var BEMONY_SCENARIOS = [
2052
+ "offer-page",
2053
+ "checkout",
2054
+ "upsell-offer",
2055
+ "one-click-checkout",
2056
+ "thank-you"
2057
+ ];
2058
+
2059
+ // src/browser/resolveExecutingScript.ts
2060
+ var BEMONY_GLOBAL_BUNDLE_FILENAME = "pixel-bemony.global.js";
2061
+ var LEGACY_SCRIPT_SELECTOR = "script[data-bemony-pixel]";
2062
+ function isHtmlScript(el) {
2063
+ return !!el && typeof HTMLScriptElement !== "undefined" && el instanceof HTMLScriptElement;
2064
+ }
2065
+ function isBemonyGlobalBundleSrc(src) {
2066
+ if (!src || !src.trim()) {
2067
+ return false;
2068
+ }
2069
+ try {
2070
+ const base = typeof location !== "undefined" && location.href ? location.href : "https://example.invalid/";
2071
+ const url = new URL(src.trim(), base);
2072
+ const path = url.pathname.toLowerCase();
2073
+ return path === `/${BEMONY_GLOBAL_BUNDLE_FILENAME}` || path.endsWith(`/${BEMONY_GLOBAL_BUNDLE_FILENAME}`);
2074
+ } catch {
2075
+ const normalized = src.trim().toLowerCase().split(/[?#]/)[0] ?? "";
2076
+ return normalized === BEMONY_GLOBAL_BUNDLE_FILENAME || normalized.endsWith(`/${BEMONY_GLOBAL_BUNDLE_FILENAME}`);
2077
+ }
2078
+ }
2079
+ function resolveBemonyExecutingScript(input = {}) {
2080
+ if (typeof document === "undefined") {
2081
+ return null;
2082
+ }
2083
+ const current = input.currentScript !== void 0 ? input.currentScript : typeof document.currentScript !== "undefined" ? document.currentScript : null;
2084
+ if (isHtmlScript(current)) {
2085
+ return current;
2086
+ }
2087
+ const root = input.root ?? document;
2088
+ const allScripts = Array.from(root.querySelectorAll("script"));
2089
+ const bySrc = allScripts.filter(
2090
+ (el) => isHtmlScript(el) && isBemonyGlobalBundleSrc(el.getAttribute("src"))
2091
+ );
2092
+ if (bySrc.length === 1) {
2093
+ return bySrc[0];
2094
+ }
2095
+ if (bySrc.length > 1) {
2096
+ throw new BemonyBootstrapError(
2097
+ `Encontrados ${bySrc.length} scripts com src de ${BEMONY_GLOBAL_BUNDLE_FILENAME}; n\xE3o \xE9 poss\xEDvel determinar qual est\xE1 em execu\xE7\xE3o.`,
2098
+ "AMBIGUOUS_SCRIPT"
2099
+ );
2100
+ }
2101
+ const legacy = Array.from(
2102
+ root.querySelectorAll(LEGACY_SCRIPT_SELECTOR)
2103
+ ).filter(isHtmlScript);
2104
+ if (legacy.length === 1) {
2105
+ return legacy[0];
2106
+ }
2107
+ return null;
2108
+ }
2109
+
2110
+ // src/browser/resolveAutoInitConfig.ts
2111
+ var BEMONY_FORBIDDEN_DATA_ATTRIBUTES = [
2112
+ "data-token",
2113
+ "data-one-click-token",
2114
+ "data-oneclick-token",
2115
+ "data-ephemeral-token",
2116
+ "data-payment-token",
2117
+ "data-oc-token",
2118
+ "data-secret",
2119
+ "data-auth-token"
2120
+ ];
2121
+ var SCRIPT_SELECTOR = "script[data-bemony-pixel]";
2122
+ function isEnvironment(value) {
2123
+ return BEMONY_ENVIRONMENTS.includes(value);
2124
+ }
2125
+ function isScenario(value) {
2126
+ return BEMONY_SCENARIOS.includes(value);
2127
+ }
2128
+ function parseBooleanAttr(value) {
2129
+ if (value === null) return void 0;
2130
+ const normalized = value.trim().toLowerCase();
2131
+ if (normalized === "true" || normalized === "1" || normalized === "") {
2132
+ return true;
2133
+ }
2134
+ if (normalized === "false" || normalized === "0") {
2135
+ return false;
2136
+ }
2137
+ return void 0;
2138
+ }
2139
+ function isAutoInitEnabledFromAttr(value) {
2140
+ if (value === null || value === void 0) {
2141
+ return true;
2142
+ }
2143
+ const parsed = parseBooleanAttr(value);
2144
+ if (parsed === void 0) {
2145
+ throw new BemonyBootstrapError(
2146
+ `data-auto-init inv\xE1lido (recebido: ${value}). Use true/false/1/0.`,
2147
+ "INVALID_ATTRIBUTES"
2148
+ );
2149
+ }
2150
+ return parsed;
2151
+ }
2152
+ function assertNoForbiddenAttributes(el) {
2153
+ for (const name of BEMONY_FORBIDDEN_DATA_ATTRIBUTES) {
2154
+ if (el.hasAttribute(name)) {
2155
+ throw new BemonyBootstrapError(
2156
+ `Atributo proibido em script tag: ${name}. Token one-click n\xE3o pode ir em data-*.`,
2157
+ "FORBIDDEN_ATTRIBUTE"
2158
+ );
2159
+ }
2160
+ }
2161
+ for (const attr of Array.from(el.attributes)) {
2162
+ if (attr.name.startsWith("data-") && attr.name.includes("token")) {
2163
+ throw new BemonyBootstrapError(
2164
+ `Atributo proibido em script tag: ${attr.name}. Token n\xE3o permitido em data-*.`,
2165
+ "FORBIDDEN_ATTRIBUTE"
2166
+ );
2167
+ }
2168
+ }
2169
+ }
2170
+ function nonEmpty(value) {
2171
+ if (value === null || value === void 0) return void 0;
2172
+ const trimmed = value.trim();
2173
+ return trimmed.length > 0 ? trimmed : void 0;
2174
+ }
2175
+ function readPublicPageFromDataset(el) {
2176
+ const pageId = nonEmpty(el.getAttribute("data-page-id"));
2177
+ const funnelId = nonEmpty(el.getAttribute("data-funnel-id"));
2178
+ const funnelStepId = nonEmpty(el.getAttribute("data-funnel-step-id"));
2179
+ const offerId = nonEmpty(el.getAttribute("data-offer-id"));
2180
+ const productId = nonEmpty(el.getAttribute("data-product-id"));
2181
+ const priceCode = nonEmpty(el.getAttribute("data-price-code"));
2182
+ const checkoutId = nonEmpty(el.getAttribute("data-checkout-id"));
2183
+ const publicOrderId = nonEmpty(el.getAttribute("data-public-order-id"));
2184
+ if (!pageId && !funnelId && !funnelStepId && !offerId && !productId && !priceCode && !checkoutId && !publicOrderId) {
2185
+ return void 0;
2186
+ }
2187
+ return {
2188
+ ...pageId ? { pageId } : {},
2189
+ ...funnelId ? { funnelId } : {},
2190
+ ...funnelStepId ? { funnelStepId } : {},
2191
+ ...offerId ? { offerId } : {},
2192
+ ...productId ? { productId } : {},
2193
+ ...priceCode ? { priceCode } : {},
2194
+ ...checkoutId ? { checkoutId } : {},
2195
+ ...publicOrderId ? { publicOrderId } : {}
2196
+ };
2197
+ }
2198
+ function cloneDefaults() {
2199
+ return {
2200
+ environment: BEMONY_BROWSER_AUTO_INIT_DEFAULTS.environment,
2201
+ scenario: BEMONY_BROWSER_AUTO_INIT_DEFAULTS.scenario,
2202
+ platform: {
2203
+ pixelId: BEMONY_BROWSER_AUTO_INIT_DEFAULTS.platform.pixelId,
2204
+ apiEndpoint: BEMONY_BROWSER_AUTO_INIT_DEFAULTS.platform.apiEndpoint,
2205
+ namespace: BEMONY_BROWSER_AUTO_INIT_DEFAULTS.platform.namespace,
2206
+ allowedDomains: [
2207
+ ...BEMONY_BROWSER_AUTO_INIT_DEFAULTS.platform.allowedDomains
2208
+ ]
2209
+ }
2210
+ };
2211
+ }
2212
+ function mergePlatform(base, overlay) {
2213
+ if (!overlay) return { ...base };
2214
+ const pixelId = overlay.pixelId !== void 0 && overlay.pixelId.trim() !== "" ? overlay.pixelId.trim() : base.pixelId;
2215
+ const apiEndpoint = overlay.apiEndpoint !== void 0 ? overlay.apiEndpoint.trim() || base.apiEndpoint : base.apiEndpoint;
2216
+ const namespace = overlay.namespace !== void 0 ? overlay.namespace.trim() || base.namespace : base.namespace;
2217
+ return {
2218
+ ...base,
2219
+ pixelId,
2220
+ ...apiEndpoint !== void 0 ? { apiEndpoint } : {},
2221
+ ...namespace !== void 0 ? { namespace } : {},
2222
+ ...overlay.debug !== void 0 ? { debug: overlay.debug } : {},
2223
+ allowedDomains: overlay.allowedDomains !== void 0 ? (() => {
2224
+ const cleaned = overlay.allowedDomains.filter(
2225
+ (d) => d.trim().length > 0
2226
+ );
2227
+ return cleaned.length > 0 ? cleaned : base.allowedDomains;
2228
+ })() : base.allowedDomains
2229
+ };
2230
+ }
2231
+ function mergePage(base, overlay) {
2232
+ if (!overlay && !base) return void 0;
2233
+ if (!overlay) return base;
2234
+ if (!base) return overlay;
2235
+ const baseNorm = base && "public" in base ? base : { public: base };
2236
+ const overlayNorm = overlay && "public" in overlay ? overlay : { public: overlay };
2237
+ const basePublic = baseNorm && "public" in baseNorm ? baseNorm.public ?? {} : {};
2238
+ const overlayPublic = overlayNorm && "public" in overlayNorm ? overlayNorm.public ?? {} : {};
2239
+ return {
2240
+ ...baseNorm,
2241
+ ...overlayNorm,
2242
+ public: {
2243
+ ...basePublic,
2244
+ ...overlayPublic
2245
+ }
2246
+ };
2247
+ }
2248
+ function mergeOverrides(base, overlay) {
2249
+ if (!overlay && !base) return void 0;
2250
+ if (!overlay) return base ? { ...base } : void 0;
2251
+ if (!base) return { ...overlay };
2252
+ const apiEndpoint = overlay.apiEndpoint !== void 0 ? overlay.apiEndpoint.trim() || base.apiEndpoint : base.apiEndpoint;
2253
+ return {
2254
+ ...base,
2255
+ ...overlay,
2256
+ ...apiEndpoint !== void 0 ? { apiEndpoint } : {},
2257
+ allowedDomains: overlay.allowedDomains !== void 0 ? overlay.allowedDomains.filter((d) => d.trim().length > 0) : base.allowedDomains
2258
+ };
2259
+ }
2260
+ function mergeBemonyPixelOptions(base, overlay) {
2261
+ const environment = overlay.environment && isEnvironment(overlay.environment) ? overlay.environment : base.environment;
2262
+ const scenario = overlay.scenario && isScenario(overlay.scenario) ? overlay.scenario : base.scenario;
2263
+ const merged = {
2264
+ environment,
2265
+ scenario,
2266
+ platform: mergePlatform(base.platform, overlay.platform)
2267
+ };
2268
+ const page = mergePage(base.page, overlay.page);
2269
+ if (page !== void 0) merged.page = page;
2270
+ const commerce = overlay.commerce ?? base.commerce;
2271
+ if (commerce !== void 0) merged.commerce = commerce;
2272
+ const overrides = mergeOverrides(base.overrides, overlay.overrides);
2273
+ if (overrides !== void 0) merged.overrides = overrides;
2274
+ const autoInitiateCheckout = overlay.autoInitiateCheckout ?? base.autoInitiateCheckout;
2275
+ if (autoInitiateCheckout !== void 0) {
2276
+ merged.autoInitiateCheckout = autoInitiateCheckout;
2277
+ }
2278
+ const noThanksUrl = overlay.noThanksUrl ?? base.noThanksUrl;
2279
+ if (noThanksUrl !== void 0 && noThanksUrl.trim() !== "") {
2280
+ merged.noThanksUrl = noThanksUrl.trim();
2281
+ }
2282
+ if ("createCorePixel" in overlay && overlay.createCorePixel) {
2283
+ merged.createCorePixel = overlay.createCorePixel;
2284
+ } else if (base.createCorePixel) {
2285
+ merged.createCorePixel = base.createCorePixel;
2286
+ }
2287
+ return merged;
2288
+ }
2289
+ function parseBemonyScriptAttributes(el) {
2290
+ assertNoForbiddenAttributes(el);
2291
+ const htmlEl = el;
2292
+ const environmentRaw = nonEmpty(htmlEl.getAttribute("data-environment"));
2293
+ const scenarioRaw = nonEmpty(htmlEl.getAttribute("data-scenario"));
2294
+ if (environmentRaw !== void 0 && !isEnvironment(environmentRaw)) {
2295
+ throw new BemonyBootstrapError(
2296
+ `data-environment inv\xE1lido (recebido: ${environmentRaw}).`,
2297
+ "INVALID_ATTRIBUTES"
2298
+ );
2299
+ }
2300
+ if (scenarioRaw !== void 0 && !isScenario(scenarioRaw)) {
2301
+ throw new BemonyBootstrapError(
2302
+ `data-scenario inv\xE1lido (recebido: ${scenarioRaw}).`,
2303
+ "INVALID_ATTRIBUTES"
2304
+ );
2305
+ }
2306
+ const pixelId = nonEmpty(htmlEl.getAttribute("data-pixel-id")) ?? nonEmpty(htmlEl.getAttribute("data-funnel-id"));
2307
+ const namespace = nonEmpty(htmlEl.getAttribute("data-namespace"));
2308
+ const apiEndpoint = nonEmpty(htmlEl.getAttribute("data-api-endpoint"));
2309
+ const debug = parseBooleanAttr(htmlEl.getAttribute("data-debug"));
2310
+ const allowedDomainsRaw = nonEmpty(
2311
+ htmlEl.getAttribute("data-allowed-domains")
2312
+ );
2313
+ const allowedDomains = allowedDomainsRaw ? allowedDomainsRaw.split(",").map((d) => d.trim()).filter(Boolean) : void 0;
2314
+ const pagePublic = readPublicPageFromDataset(htmlEl);
2315
+ const partial = {};
2316
+ if (environmentRaw) partial.environment = environmentRaw;
2317
+ if (scenarioRaw) partial.scenario = scenarioRaw;
2318
+ if (pixelId || namespace || apiEndpoint || allowedDomains || debug !== void 0) {
2319
+ partial.platform = {
2320
+ pixelId: pixelId ?? BEMONY_DEFAULT_PIXEL_ID,
2321
+ ...namespace ? { namespace } : {},
2322
+ ...apiEndpoint ? { apiEndpoint } : {},
2323
+ ...allowedDomains ? { allowedDomains } : {},
2324
+ ...debug !== void 0 ? { debug } : {}
2325
+ };
2326
+ }
2327
+ if (pagePublic) {
2328
+ partial.page = { public: pagePublic };
2329
+ }
2330
+ if (apiEndpoint || debug !== void 0) {
2331
+ partial.overrides = {
2332
+ ...apiEndpoint ? { apiEndpoint } : {},
2333
+ ...debug !== void 0 ? { debug } : {}
2334
+ };
2335
+ }
2336
+ const autoInitiateCheckout = parseBooleanAttr(
2337
+ htmlEl.getAttribute("data-auto-initiate-checkout")
2338
+ );
2339
+ if (autoInitiateCheckout !== void 0) {
2340
+ partial.autoInitiateCheckout = autoInitiateCheckout;
2341
+ }
2342
+ const noThanksUrl = nonEmpty(htmlEl.getAttribute("data-no-thanks"));
2343
+ if (noThanksUrl) {
2344
+ partial.noThanksUrl = noThanksUrl;
2345
+ }
2346
+ return partial;
2347
+ }
2348
+ function readWindowConfig() {
2349
+ if (typeof window === "undefined") {
2350
+ return null;
2351
+ }
2352
+ const config = window.BemonyPixelConfig;
2353
+ return config && typeof config === "object" ? config : null;
2354
+ }
2355
+ function assertValidWindowConfigPartial(config) {
2356
+ if (config.environment !== void 0 && !isEnvironment(config.environment)) {
2357
+ throw new BemonyBootstrapError(
2358
+ "window.BemonyPixelConfig.environment inv\xE1lido.",
2359
+ "INVALID_CONFIG"
2360
+ );
2361
+ }
2362
+ if (config.scenario !== void 0 && !isScenario(config.scenario)) {
2363
+ throw new BemonyBootstrapError(
2364
+ "window.BemonyPixelConfig.scenario inv\xE1lido.",
2365
+ "INVALID_CONFIG"
2366
+ );
2367
+ }
2368
+ if (config.platform?.pixelId !== void 0 && config.platform.pixelId.trim() === "") {
2369
+ throw new BemonyBootstrapError(
2370
+ "window.BemonyPixelConfig.platform.pixelId n\xE3o pode ser vazio.",
2371
+ "INVALID_CONFIG"
2372
+ );
2373
+ }
2374
+ }
2375
+ function resolveAutoInitConfig(input = {}) {
2376
+ const applyDefaults = input.applyDefaults !== false;
2377
+ if (typeof document === "undefined" && typeof window === "undefined") {
2378
+ if (input.config && applyDefaults) {
2379
+ return {
2380
+ options: mergeBemonyPixelOptions(cloneDefaults(), input.config),
2381
+ source: "explicit",
2382
+ sources: ["default", "explicit"],
2383
+ script: null
2384
+ };
2385
+ }
2386
+ if (input.config) {
2387
+ return {
2388
+ options: input.config,
2389
+ source: "explicit",
2390
+ sources: ["explicit"],
2391
+ script: null
2392
+ };
2393
+ }
2394
+ return null;
2395
+ }
2396
+ const sources = [];
2397
+ let options = applyDefaults ? cloneDefaults() : null;
2398
+ if (applyDefaults) {
2399
+ sources.push("default");
2400
+ }
2401
+ const windowConfig = readWindowConfig();
2402
+ if (windowConfig) {
2403
+ assertValidWindowConfigPartial(windowConfig);
2404
+ if (!options) {
2405
+ options = cloneDefaults();
2406
+ if (!sources.includes("default")) sources.push("default");
2407
+ }
2408
+ options = mergeBemonyPixelOptions(options, windowConfig);
2409
+ sources.push("window-config");
2410
+ }
2411
+ let script = input.script ?? null;
2412
+ if (script === null && input.script === void 0) {
2413
+ const root = input.root ?? (typeof document !== "undefined" ? document : void 0);
2414
+ try {
2415
+ script = resolveBemonyExecutingScript({
2416
+ ...root ? { root } : {}
2417
+ });
2418
+ } catch (error) {
2419
+ if (error instanceof BemonyBootstrapError && error.code === "AMBIGUOUS_SCRIPT") {
2420
+ throw error;
2421
+ }
2422
+ script = null;
2423
+ }
2424
+ if (!script && root) {
2425
+ const legacyAuto = Array.from(
2426
+ root.querySelectorAll(`${SCRIPT_SELECTOR}[data-auto-init]`)
2427
+ );
2428
+ if (legacyAuto.length > 1) {
2429
+ throw new BemonyBootstrapError(
2430
+ `Encontrados ${legacyAuto.length} scripts com data-bemony-pixel + data-auto-init; use apenas um.`,
2431
+ "MULTIPLE_SCRIPTS"
2432
+ );
2433
+ }
2434
+ if (legacyAuto.length === 1) {
2435
+ script = legacyAuto[0];
2436
+ }
2437
+ }
2438
+ }
2439
+ if (script) {
2440
+ const fromAttrs = parseBemonyScriptAttributes(script);
2441
+ if (!options) {
2442
+ options = cloneDefaults();
2443
+ if (!sources.includes("default")) sources.push("default");
2444
+ }
2445
+ options = mergeBemonyPixelOptions(options, fromAttrs);
2446
+ sources.push("data-attributes");
2447
+ }
2448
+ if (input.config) {
2449
+ if (!options) {
2450
+ options = { ...input.config };
2451
+ sources.push("explicit");
2452
+ } else {
2453
+ options = mergeBemonyPixelOptions(options, input.config);
2454
+ sources.push("explicit");
2455
+ }
2456
+ }
2457
+ if (!options) {
2458
+ return null;
2459
+ }
2460
+ if (!options.platform.pixelId?.trim()) {
2461
+ options = mergeBemonyPixelOptions(options, {
2462
+ platform: {
2463
+ pixelId: BEMONY_DEFAULT_PIXEL_ID,
2464
+ namespace: BEMONY_DEFAULT_NAMESPACE,
2465
+ apiEndpoint: BEMONY_DEFAULT_API_ENDPOINT
2466
+ }
2467
+ });
2468
+ }
2469
+ if ((options.environment === "staging" || options.environment === "production") && !options.platform.apiEndpoint?.trim() && !options.overrides?.apiEndpoint?.trim()) {
2470
+ options = mergeBemonyPixelOptions(options, {
2471
+ platform: {
2472
+ pixelId: options.platform.pixelId,
2473
+ apiEndpoint: BEMONY_DEFAULT_API_ENDPOINT
2474
+ }
2475
+ });
2476
+ }
2477
+ const highest = sources[sources.length - 1] ?? "default";
2478
+ const source = sources.length > 1 ? "merged" : highest;
2479
+ return {
2480
+ options,
2481
+ source: sources.length === 1 ? highest : source,
2482
+ sources,
2483
+ script
2484
+ };
2485
+ }
2486
+
2487
+ // src/browser/autoInit.ts
2488
+ async function installBemonyPixelAutoInit(options = {}) {
2489
+ if (typeof window === "undefined") {
2490
+ throw new BemonyBootstrapError(
2491
+ "installBemonyPixelAutoInit s\xF3 pode ser usado no browser.",
2492
+ "NOT_BROWSER"
2493
+ );
2494
+ }
2495
+ const script = options.script !== void 0 ? options.script : resolveBemonyExecutingScript({
2496
+ ...options.root ? { root: options.root } : {}
2497
+ });
2498
+ if (script) {
2499
+ const autoInitAttr = script.getAttribute("data-auto-init");
2500
+ if (!options.config && autoInitAttr !== null && !isAutoInitEnabledFromAttr(autoInitAttr)) {
2501
+ return null;
2502
+ }
2503
+ }
2504
+ const resolved = resolveAutoInitConfig({
2505
+ config: options.config,
2506
+ root: options.root,
2507
+ script,
2508
+ applyDefaults: options.applyDefaults
2509
+ });
2510
+ if (!resolved) {
2511
+ return null;
2512
+ }
2513
+ if (options.requireDataAutoInit && !options.config && !resolved.sources.includes("data-attributes")) {
2514
+ return null;
2515
+ }
2516
+ const bootstrapOptions = {
2517
+ ...resolved.options,
2518
+ ...options.force !== void 0 ? { force: options.force } : {},
2519
+ ...options.waitForConsent ? { waitForConsent: options.waitForConsent } : {}
2520
+ };
2521
+ try {
2522
+ const pixel = await bootstrapBemonyPixel(bootstrapOptions);
2523
+ return { pixel, source: resolved.source };
2524
+ } catch (error) {
2525
+ if (error instanceof BemonyBootstrapError) {
2526
+ throw error;
2527
+ }
2528
+ throw new BemonyBootstrapError(
2529
+ error instanceof Error ? error.message : "Auto-init falhou",
2530
+ "AUTO_INIT_FAILED",
2531
+ error
2532
+ );
2533
+ }
2534
+ }
2535
+ export {
2536
+ BEMONY_FORBIDDEN_DATA_ATTRIBUTES,
2537
+ BEMONY_GLOBAL_BUNDLE_FILENAME,
2538
+ BEMONY_PIXEL_DESTROYED_EVENT,
2539
+ BEMONY_PIXEL_ERROR_EVENT,
2540
+ BEMONY_PIXEL_INITIALIZING_EVENT,
2541
+ BEMONY_PIXEL_READY_EVENT,
2542
+ SCRIPT_SELECTOR as BEMONY_PIXEL_SCRIPT_SELECTOR,
2543
+ BemonyBootstrapError,
2544
+ bootstrapBemonyPixel,
2545
+ destroyBootstrappedBemonyPixel,
2546
+ getBootstrappedBemonyPixel,
2547
+ getBootstrappedBemonyPixelPending,
2548
+ installBemonyPixelAutoInit,
2549
+ isAutoInitEnabledFromAttr,
2550
+ isBemonyGlobalBundleSrc,
2551
+ mergeBemonyPixelOptions,
2552
+ parseBemonyScriptAttributes,
2553
+ parseBooleanAttr,
2554
+ resolveAutoInitConfig,
2555
+ resolveBemonyExecutingScript
2556
+ };
2557
+ //# sourceMappingURL=index.esm.js.map