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