@aranova/tracking-react 1.14.0 → 1.14.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.
- package/dist/{bookings-Bw2ImtPd.d.ts → bookings-CkfA5XOM.d.ts} +283 -8
- package/dist/{bookings-CDGNZUaH.d.mts → bookings-DFz3BUiP.d.mts} +283 -8
- package/dist/client.d.mts +10 -9
- package/dist/client.d.ts +10 -9
- package/dist/client.js +157 -141
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +157 -141
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +364 -203
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +364 -203
- package/dist/index.mjs.map +1 -1
- package/dist/{submit-DuvP5AGN.d.ts → ingest-typed-BO6Arbw-.d.mts} +2 -252
- package/dist/{submit-rqgXl-Wg.d.mts → ingest-typed-D7I4aQ7p.d.ts} +2 -252
- package/dist/{phone-utils-Cfdx474X.d.mts → phone-utils-CYr6AmEP.d.mts} +55 -2
- package/dist/{phone-utils-D2TGPCQW.d.ts → phone-utils-CYr6AmEP.d.ts} +55 -2
- package/dist/phone.d.mts +1 -2
- package/dist/phone.d.ts +1 -2
- package/dist/{sales-DkdrGIUS.d.ts → sales-C0FMkN4m.d.ts} +1 -1
- package/dist/{sales-D4aU73mR.d.mts → sales-KbTcowYa.d.mts} +1 -1
- package/dist/sales.d.mts +3 -3
- package/dist/sales.d.ts +3 -3
- package/dist/sales.js +1204 -170
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +1204 -170
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/form-submit-C_vJXCxh.d.mts +0 -57
- package/dist/form-submit-C_vJXCxh.d.ts +0 -57
package/dist/client.d.mts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, CSSProperties, InputHTMLAttributes, ChangeEvent, FocusEvent, AnchorHTMLAttributes } from 'react';
|
|
3
|
-
import { G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, h as ConsentState, f as ConsentChoiceState, g as ConsentSource, T as TrackingParams, b as TrackingEnvironment,
|
|
4
|
-
import { T as TrackingConfigReference, C as ConversionConfig,
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, h as ConsentState, f as ConsentChoiceState, g as ConsentSource, T as TrackingParams, b as TrackingEnvironment, u as PhoneConfig, P as ParsedPhone, v as PhoneDisplayFormat } from './phone-utils-CYr6AmEP.mjs';
|
|
4
|
+
import { T as TrackingConfigReference, C as ConversionConfig, h as BookingHandoffPrefill, i as BookingInput, p as BookingOutcome, b as BookingDetailsInput, d as BookingDetailsOutcome, k as BookingIntegration, B as BookableDay, x as LeadFormContracts, S as SalesBookingsClient, g as BookingFormSubmit, t as BookingSimulation, j as BookingInputFor } from './bookings-DFz3BUiP.mjs';
|
|
5
|
+
export { Z as createLeadFormSubmit } from './bookings-DFz3BUiP.mjs';
|
|
6
|
+
import { L as TriggerRegistryConfig, O as TypedTrackingClient } from './ingest-typed-BO6Arbw-.mjs';
|
|
7
7
|
import { CountryCode } from 'libphonenumber-js';
|
|
8
|
-
import './form-submit-C_vJXCxh.mjs';
|
|
9
8
|
import 'zod/mini';
|
|
10
9
|
import 'zod/v4/core';
|
|
11
10
|
|
|
@@ -408,11 +407,11 @@ interface BookedAttempt {
|
|
|
408
407
|
bookingId: string;
|
|
409
408
|
attemptKey: string;
|
|
410
409
|
}
|
|
411
|
-
interface BookingSubmitState {
|
|
410
|
+
interface BookingSubmitState<I = BookingInput> {
|
|
412
411
|
status: BookingSubmitStatus;
|
|
413
412
|
outcome: BookingOutcome | null;
|
|
414
413
|
/** Send the booking. A retry of an unanswered or refused submit reuses its attempt key. */
|
|
415
|
-
submit(input:
|
|
414
|
+
submit(input: I): Promise<BookingOutcome>;
|
|
416
415
|
/**
|
|
417
416
|
* The recorded booking and the key it was sent with; persist it (e.g. `sessionStorage`) to add
|
|
418
417
|
* details after a reload. Null until the server has the booking.
|
|
@@ -431,11 +430,13 @@ interface BookingSubmitState {
|
|
|
431
430
|
* get wrong: one attempt key per submit (a double-click never books twice), the visit's
|
|
432
431
|
* `form_submit`, the stale-config refetch, and the fallback link on failure. A `pending` answer
|
|
433
432
|
* shows at once (`status: "pending"`) while the final one is polled; the submit stays in flight.
|
|
433
|
+
* Pass the site's `ARANOVA_LEAD_FORMS` as `contracts` to type the input by the shop's rules.
|
|
434
434
|
*/
|
|
435
|
-
declare function useBookingSubmit(bookings: SalesBookingsClient, options?: {
|
|
435
|
+
declare function useBookingSubmit<C extends LeadFormContracts | undefined = undefined>(bookings: SalesBookingsClient, options?: {
|
|
436
436
|
formSubmit?: BookingFormSubmit;
|
|
437
437
|
/** Development only: a simulated create's outcome. The production API ignores it. */
|
|
438
438
|
simulate?: BookingSimulation;
|
|
439
|
-
|
|
439
|
+
contracts?: C;
|
|
440
|
+
}): BookingSubmitState<C extends LeadFormContracts ? BookingInputFor<C> : BookingInput>;
|
|
440
441
|
|
|
441
442
|
export { AdPlatformTracking, type AdPlatformTrackingProps, type BookedAttempt, BookingHandoffLink, type BookingHandoffLinkProps, type BookingHandoffOptions, type BookingSubmitState, type BookingSubmitStatus, ConsentBanner, type ConsentBannerProps, type CreateTrackingOptions, type CreateTrackingResult, GoogleAdsTracking, type GoogleAdsTrackingProps, PhoneField, type PhoneFieldApi, type PhoneFieldProps, type PhoneInputProps, type TrackingProviderProps, type UseConsentResult, type UseCookiePreferencesOptions, type UseCookiePreferencesResult, type UsePhoneFieldOptions, createTracking, useBookingHandoffUrl, useBookingIntegration, useBookingSlots, useBookingSubmit, useConsent, useConsentState, useCookiePreferences, useGclid, usePhoneConfig, usePhoneField, useTrackingParams };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, CSSProperties, InputHTMLAttributes, ChangeEvent, FocusEvent, AnchorHTMLAttributes } from 'react';
|
|
3
|
-
import { G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, h as ConsentState, f as ConsentChoiceState, g as ConsentSource, T as TrackingParams, b as TrackingEnvironment,
|
|
4
|
-
import { T as TrackingConfigReference, C as ConversionConfig,
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { G as GtagEnvironmentMap, M as MetaPixelEnvironmentMap, h as ConsentState, f as ConsentChoiceState, g as ConsentSource, T as TrackingParams, b as TrackingEnvironment, u as PhoneConfig, P as ParsedPhone, v as PhoneDisplayFormat } from './phone-utils-CYr6AmEP.js';
|
|
4
|
+
import { T as TrackingConfigReference, C as ConversionConfig, h as BookingHandoffPrefill, i as BookingInput, p as BookingOutcome, b as BookingDetailsInput, d as BookingDetailsOutcome, k as BookingIntegration, B as BookableDay, x as LeadFormContracts, S as SalesBookingsClient, g as BookingFormSubmit, t as BookingSimulation, j as BookingInputFor } from './bookings-CkfA5XOM.js';
|
|
5
|
+
export { Z as createLeadFormSubmit } from './bookings-CkfA5XOM.js';
|
|
6
|
+
import { L as TriggerRegistryConfig, O as TypedTrackingClient } from './ingest-typed-D7I4aQ7p.js';
|
|
7
7
|
import { CountryCode } from 'libphonenumber-js';
|
|
8
|
-
import './form-submit-C_vJXCxh.js';
|
|
9
8
|
import 'zod/mini';
|
|
10
9
|
import 'zod/v4/core';
|
|
11
10
|
|
|
@@ -408,11 +407,11 @@ interface BookedAttempt {
|
|
|
408
407
|
bookingId: string;
|
|
409
408
|
attemptKey: string;
|
|
410
409
|
}
|
|
411
|
-
interface BookingSubmitState {
|
|
410
|
+
interface BookingSubmitState<I = BookingInput> {
|
|
412
411
|
status: BookingSubmitStatus;
|
|
413
412
|
outcome: BookingOutcome | null;
|
|
414
413
|
/** Send the booking. A retry of an unanswered or refused submit reuses its attempt key. */
|
|
415
|
-
submit(input:
|
|
414
|
+
submit(input: I): Promise<BookingOutcome>;
|
|
416
415
|
/**
|
|
417
416
|
* The recorded booking and the key it was sent with; persist it (e.g. `sessionStorage`) to add
|
|
418
417
|
* details after a reload. Null until the server has the booking.
|
|
@@ -431,11 +430,13 @@ interface BookingSubmitState {
|
|
|
431
430
|
* get wrong: one attempt key per submit (a double-click never books twice), the visit's
|
|
432
431
|
* `form_submit`, the stale-config refetch, and the fallback link on failure. A `pending` answer
|
|
433
432
|
* shows at once (`status: "pending"`) while the final one is polled; the submit stays in flight.
|
|
433
|
+
* Pass the site's `ARANOVA_LEAD_FORMS` as `contracts` to type the input by the shop's rules.
|
|
434
434
|
*/
|
|
435
|
-
declare function useBookingSubmit(bookings: SalesBookingsClient, options?: {
|
|
435
|
+
declare function useBookingSubmit<C extends LeadFormContracts | undefined = undefined>(bookings: SalesBookingsClient, options?: {
|
|
436
436
|
formSubmit?: BookingFormSubmit;
|
|
437
437
|
/** Development only: a simulated create's outcome. The production API ignores it. */
|
|
438
438
|
simulate?: BookingSimulation;
|
|
439
|
-
|
|
439
|
+
contracts?: C;
|
|
440
|
+
}): BookingSubmitState<C extends LeadFormContracts ? BookingInputFor<C> : BookingInput>;
|
|
440
441
|
|
|
441
442
|
export { AdPlatformTracking, type AdPlatformTrackingProps, type BookedAttempt, BookingHandoffLink, type BookingHandoffLinkProps, type BookingHandoffOptions, type BookingSubmitState, type BookingSubmitStatus, ConsentBanner, type ConsentBannerProps, type CreateTrackingOptions, type CreateTrackingResult, GoogleAdsTracking, type GoogleAdsTrackingProps, PhoneField, type PhoneFieldApi, type PhoneFieldProps, type PhoneInputProps, type TrackingProviderProps, type UseConsentResult, type UseCookiePreferencesOptions, type UseCookiePreferencesResult, type UsePhoneFieldOptions, createTracking, useBookingHandoffUrl, useBookingIntegration, useBookingSlots, useBookingSubmit, useConsent, useConsentState, useCookiePreferences, useGclid, usePhoneConfig, usePhoneField, useTrackingParams };
|
package/dist/client.js
CHANGED
|
@@ -3931,6 +3931,157 @@ var LEAD_FORM_ROLE_SPECS = {
|
|
|
3931
3931
|
attribution: { primitive: "enum", smsLabel: "", uninteresting: true }
|
|
3932
3932
|
};
|
|
3933
3933
|
|
|
3934
|
+
// ../tracking-core/src/lead-forms/submit.ts
|
|
3935
|
+
var import_mini4 = require("zod/mini");
|
|
3936
|
+
var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
|
|
3937
|
+
var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
|
|
3938
|
+
var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
|
|
3939
|
+
var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
|
|
3940
|
+
var INPUT_TYPES = {
|
|
3941
|
+
string: "text",
|
|
3942
|
+
text: "textarea",
|
|
3943
|
+
enum: "select",
|
|
3944
|
+
multi_enum: "select",
|
|
3945
|
+
bool: "checkbox",
|
|
3946
|
+
date: "date",
|
|
3947
|
+
time_window: "time",
|
|
3948
|
+
phone: "tel",
|
|
3949
|
+
email: "email",
|
|
3950
|
+
address: "address",
|
|
3951
|
+
number: "number"
|
|
3952
|
+
};
|
|
3953
|
+
function createLeadFormSubmit(tracking, contracts, options = {}) {
|
|
3954
|
+
registerCapability("typed_form_submit");
|
|
3955
|
+
const settings = { ...typedClientSettings(tracking), ...options };
|
|
3956
|
+
return {
|
|
3957
|
+
submit(input) {
|
|
3958
|
+
const fields = presentFields(input.fields);
|
|
3959
|
+
const { violations, hash } = judgeLeadForm(
|
|
3960
|
+
input.kind,
|
|
3961
|
+
input.formId,
|
|
3962
|
+
fields,
|
|
3963
|
+
contracts,
|
|
3964
|
+
settings
|
|
3965
|
+
);
|
|
3966
|
+
const metadata = {
|
|
3967
|
+
form: {
|
|
3968
|
+
id: input.formId,
|
|
3969
|
+
action: input.action ?? null,
|
|
3970
|
+
fields: fields.map(([role, value]) => ({
|
|
3971
|
+
name: role,
|
|
3972
|
+
type: INPUT_TYPES[primitiveOf(role) ?? "string"],
|
|
3973
|
+
label: labelOf(role),
|
|
3974
|
+
value,
|
|
3975
|
+
role
|
|
3976
|
+
})),
|
|
3977
|
+
kind: input.kind,
|
|
3978
|
+
contract_version: LEAD_FORM_REGISTRY_VERSION,
|
|
3979
|
+
...hash ? { contract_hash: hash } : {},
|
|
3980
|
+
...input.extra?.length ? { extra: input.extra } : {},
|
|
3981
|
+
...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
|
|
3982
|
+
},
|
|
3983
|
+
page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
|
|
3984
|
+
};
|
|
3985
|
+
tracking.trackEvent("form_submit", metadata);
|
|
3986
|
+
return metadata;
|
|
3987
|
+
}
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
function judgeLeadForm(kind, formId, fields, contracts, settings) {
|
|
3991
|
+
const generated = contracts?.contracts[kind];
|
|
3992
|
+
const live = liveContract(settings.trackingConfig, kind);
|
|
3993
|
+
const violations = check(live === void 0 ? generated : fromLive(live), fields);
|
|
3994
|
+
const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
|
|
3995
|
+
if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
|
|
3996
|
+
violations.push({ role: null, rule: "contract_behind" });
|
|
3997
|
+
}
|
|
3998
|
+
if (violations.length > 0 && (settings.debug || settings.environment === "development")) {
|
|
3999
|
+
const message = `[AranovaTracking] lead form "${formId}" (${kind}) breaks its contract: ${violations.map((v) => `${v.rule}${v.role ? ` (${v.role})` : ""}`).join(", ")}`;
|
|
4000
|
+
console.error(message);
|
|
4001
|
+
if (settings.debug) throw new Error(message);
|
|
4002
|
+
}
|
|
4003
|
+
return {
|
|
4004
|
+
violations,
|
|
4005
|
+
hash: liveHash === void 0 ? generated?.hash ?? null : liveHash
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
function liveContract(ref, kind) {
|
|
4009
|
+
const leadForms = ref ? getTrackingConfigRuntime(ref).leadForms() : null;
|
|
4010
|
+
if (!leadForms) return void 0;
|
|
4011
|
+
return leadForms.contracts.find((c) => c.form_kind === kind) ?? null;
|
|
4012
|
+
}
|
|
4013
|
+
function fromLive(live) {
|
|
4014
|
+
if (!live) return void 0;
|
|
4015
|
+
return {
|
|
4016
|
+
requires: live.requires.map((r) => ({
|
|
4017
|
+
role: r.role,
|
|
4018
|
+
requiredWhen: r.required_when ? { role: r.required_when.role, anyOf: r.required_when.any_of } : null
|
|
4019
|
+
})),
|
|
4020
|
+
requiresAny: live.requires_any.map((g) => g.roles),
|
|
4021
|
+
// Deprecated keys still resolve: a cached form may send them (ADR-0024 §7).
|
|
4022
|
+
options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
function presentFields(fields) {
|
|
4026
|
+
return Object.entries(fields).map(([role, value]) => [role, normalize(role, value)]).filter((entry) => !isBlank(entry[1])).sort(([a], [b]) => (ROLE_ORDER.get(a) ?? 999) - (ROLE_ORDER.get(b) ?? 999));
|
|
4027
|
+
}
|
|
4028
|
+
function normalize(role, value) {
|
|
4029
|
+
if (typeof value !== "string") return value;
|
|
4030
|
+
const trimmed = value.trim();
|
|
4031
|
+
const primitive = primitiveOf(role);
|
|
4032
|
+
if (primitive === "phone") return toE164(trimmed) ?? trimmed;
|
|
4033
|
+
if (primitive === "email") return trimmed.toLowerCase();
|
|
4034
|
+
return primitive === "text" ? value : trimmed;
|
|
4035
|
+
}
|
|
4036
|
+
function isBlank(value) {
|
|
4037
|
+
return value === void 0 || value === null || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0;
|
|
4038
|
+
}
|
|
4039
|
+
function check(contract, fields) {
|
|
4040
|
+
const answered = new Map(fields);
|
|
4041
|
+
const violations = [];
|
|
4042
|
+
for (const [role, value] of fields) {
|
|
4043
|
+
const primitive = primitiveOf(role);
|
|
4044
|
+
if (!primitive) {
|
|
4045
|
+
violations.push({ role: CONTRACT_NAME.test(role) ? role : null, rule: "unknown_role" });
|
|
4046
|
+
continue;
|
|
4047
|
+
}
|
|
4048
|
+
if (!(0, import_mini4.safeParse)(leadFormPrimitiveSchemas[primitive], value).success) {
|
|
4049
|
+
violations.push({ role, rule: "invalid_value" });
|
|
4050
|
+
continue;
|
|
4051
|
+
}
|
|
4052
|
+
const allowed = contract?.options[role] ?? registryOptions(role);
|
|
4053
|
+
if (allowed?.length && optionKeys(value).some((key) => !allowed.includes(key))) {
|
|
4054
|
+
violations.push({ role, rule: "unknown_option" });
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
for (const { role, requiredWhen } of contract?.requires ?? []) {
|
|
4058
|
+
const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
|
|
4059
|
+
if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
|
|
4060
|
+
}
|
|
4061
|
+
for (const group of contract?.requiresAny ?? []) {
|
|
4062
|
+
if (!group.some((role) => answered.has(role))) {
|
|
4063
|
+
violations.push({ role: group.join("|"), rule: "missing_any_of" });
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
4066
|
+
return violations;
|
|
4067
|
+
}
|
|
4068
|
+
function primitiveOf(role) {
|
|
4069
|
+
if (ADD_ON.test(role)) return "bool";
|
|
4070
|
+
return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].primitive : null;
|
|
4071
|
+
}
|
|
4072
|
+
function labelOf(role) {
|
|
4073
|
+
if (ADD_ON.test(role)) return role.slice("add_on:".length).replaceAll(/[_-]+/g, " ");
|
|
4074
|
+
return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].smsLabel || null : null;
|
|
4075
|
+
}
|
|
4076
|
+
function registryOptions(role) {
|
|
4077
|
+
const spec = KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role] : void 0;
|
|
4078
|
+
return spec && "options" in spec ? spec.options.map((o) => o.key) : void 0;
|
|
4079
|
+
}
|
|
4080
|
+
function optionKeys(value) {
|
|
4081
|
+
if (typeof value === "string") return [value];
|
|
4082
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
4083
|
+
}
|
|
4084
|
+
|
|
3934
4085
|
// ../tracking-core/src/resources/sales/bookings.ts
|
|
3935
4086
|
var newBookingAttemptKey = uuidV4;
|
|
3936
4087
|
|
|
@@ -4265,7 +4416,7 @@ function GoogleAdsTracking(props) {
|
|
|
4265
4416
|
var import_react6 = require("react");
|
|
4266
4417
|
|
|
4267
4418
|
// package.json
|
|
4268
|
-
var version = "1.14.
|
|
4419
|
+
var version = "1.14.1";
|
|
4269
4420
|
|
|
4270
4421
|
// ../tracking-core/src/phone-react.tsx
|
|
4271
4422
|
var import_react5 = require("react");
|
|
@@ -4587,7 +4738,11 @@ function useBookingSubmit(bookings, options = {}) {
|
|
|
4587
4738
|
const attemptKey = (0, import_react7.useRef)(null);
|
|
4588
4739
|
const [booked, setBooked] = (0, import_react7.useState)(null);
|
|
4589
4740
|
const inFlight = (0, import_react7.useRef)(null);
|
|
4590
|
-
const {
|
|
4741
|
+
const { simulate, contracts } = options;
|
|
4742
|
+
const formSubmit = (0, import_react7.useMemo)(
|
|
4743
|
+
() => options.formSubmit && contracts ? { ...options.formSubmit, contracts } : options.formSubmit,
|
|
4744
|
+
[options.formSubmit, contracts]
|
|
4745
|
+
);
|
|
4591
4746
|
const submit = (0, import_react7.useCallback)(
|
|
4592
4747
|
(input) => {
|
|
4593
4748
|
if (inFlight.current) return inFlight.current;
|
|
@@ -4639,145 +4794,6 @@ function useBookingSubmit(bookings, options = {}) {
|
|
|
4639
4794
|
const status = submitting ? "submitting" : outcome?.status ?? "idle";
|
|
4640
4795
|
return { status, outcome, booked, submit, updateBooking, reset };
|
|
4641
4796
|
}
|
|
4642
|
-
|
|
4643
|
-
// ../tracking-core/src/lead-forms/submit.ts
|
|
4644
|
-
var import_mini4 = require("zod/mini");
|
|
4645
|
-
var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
|
|
4646
|
-
var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
|
|
4647
|
-
var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
|
|
4648
|
-
var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
|
|
4649
|
-
var INPUT_TYPES = {
|
|
4650
|
-
string: "text",
|
|
4651
|
-
text: "textarea",
|
|
4652
|
-
enum: "select",
|
|
4653
|
-
multi_enum: "select",
|
|
4654
|
-
bool: "checkbox",
|
|
4655
|
-
date: "date",
|
|
4656
|
-
time_window: "time",
|
|
4657
|
-
phone: "tel",
|
|
4658
|
-
email: "email",
|
|
4659
|
-
address: "address",
|
|
4660
|
-
number: "number"
|
|
4661
|
-
};
|
|
4662
|
-
function createLeadFormSubmit(tracking, contracts, options = {}) {
|
|
4663
|
-
registerCapability("typed_form_submit");
|
|
4664
|
-
const settings = { ...typedClientSettings(tracking), ...options };
|
|
4665
|
-
return {
|
|
4666
|
-
submit(input) {
|
|
4667
|
-
const generated = contracts.contracts[input.kind];
|
|
4668
|
-
const live = liveContract(settings.trackingConfig, input.kind);
|
|
4669
|
-
const fields = presentFields(input.fields);
|
|
4670
|
-
const violations = check(live === void 0 ? generated : fromLive(live), fields);
|
|
4671
|
-
const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
|
|
4672
|
-
if (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION) {
|
|
4673
|
-
violations.push({ role: null, rule: "contract_behind" });
|
|
4674
|
-
}
|
|
4675
|
-
const hash = liveHash === void 0 ? generated?.hash ?? null : liveHash;
|
|
4676
|
-
const metadata = {
|
|
4677
|
-
form: {
|
|
4678
|
-
id: input.formId,
|
|
4679
|
-
action: input.action ?? null,
|
|
4680
|
-
fields: fields.map(([role, value]) => ({
|
|
4681
|
-
name: role,
|
|
4682
|
-
type: INPUT_TYPES[primitiveOf(role) ?? "string"],
|
|
4683
|
-
label: labelOf(role),
|
|
4684
|
-
value,
|
|
4685
|
-
role
|
|
4686
|
-
})),
|
|
4687
|
-
kind: input.kind,
|
|
4688
|
-
contract_version: LEAD_FORM_REGISTRY_VERSION,
|
|
4689
|
-
...hash ? { contract_hash: hash } : {},
|
|
4690
|
-
...input.extra?.length ? { extra: input.extra } : {},
|
|
4691
|
-
...violations.length > 0 ? { contract_violations: violations.slice(0, MAX_CONTRACT_VIOLATIONS) } : {}
|
|
4692
|
-
},
|
|
4693
|
-
page: { path: typeof window === "undefined" ? "/" : window.location.pathname }
|
|
4694
|
-
};
|
|
4695
|
-
if (violations.length > 0 && (settings.debug || settings.environment === "development")) {
|
|
4696
|
-
const message = `[AranovaTracking] lead form "${input.formId}" (${input.kind}) breaks its contract: ${violations.map((v) => `${v.rule}${v.role ? ` (${v.role})` : ""}`).join(", ")}`;
|
|
4697
|
-
console.error(message);
|
|
4698
|
-
if (settings.debug) throw new Error(message);
|
|
4699
|
-
}
|
|
4700
|
-
tracking.trackEvent("form_submit", metadata);
|
|
4701
|
-
return metadata;
|
|
4702
|
-
}
|
|
4703
|
-
};
|
|
4704
|
-
}
|
|
4705
|
-
function liveContract(ref, kind) {
|
|
4706
|
-
const leadForms = ref ? getTrackingConfigRuntime(ref).leadForms() : null;
|
|
4707
|
-
if (!leadForms) return void 0;
|
|
4708
|
-
return leadForms.contracts.find((c) => c.form_kind === kind) ?? null;
|
|
4709
|
-
}
|
|
4710
|
-
function fromLive(live) {
|
|
4711
|
-
if (!live) return void 0;
|
|
4712
|
-
return {
|
|
4713
|
-
requires: live.requires.map((r) => ({
|
|
4714
|
-
role: r.role,
|
|
4715
|
-
requiredWhen: r.required_when ? { role: r.required_when.role, anyOf: r.required_when.any_of } : null
|
|
4716
|
-
})),
|
|
4717
|
-
requiresAny: live.requires_any.map((g) => g.roles),
|
|
4718
|
-
// Deprecated keys still resolve: a cached form may send them (ADR-0024 §7).
|
|
4719
|
-
options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
|
|
4720
|
-
};
|
|
4721
|
-
}
|
|
4722
|
-
function presentFields(fields) {
|
|
4723
|
-
return Object.entries(fields).map(([role, value]) => [role, normalize(role, value)]).filter((entry) => !isBlank(entry[1])).sort(([a], [b]) => (ROLE_ORDER.get(a) ?? 999) - (ROLE_ORDER.get(b) ?? 999));
|
|
4724
|
-
}
|
|
4725
|
-
function normalize(role, value) {
|
|
4726
|
-
if (typeof value !== "string") return value;
|
|
4727
|
-
const trimmed = value.trim();
|
|
4728
|
-
const primitive = primitiveOf(role);
|
|
4729
|
-
if (primitive === "phone") return toE164(trimmed) ?? trimmed;
|
|
4730
|
-
if (primitive === "email") return trimmed.toLowerCase();
|
|
4731
|
-
return primitive === "text" ? value : trimmed;
|
|
4732
|
-
}
|
|
4733
|
-
function isBlank(value) {
|
|
4734
|
-
return value === void 0 || value === null || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0;
|
|
4735
|
-
}
|
|
4736
|
-
function check(contract, fields) {
|
|
4737
|
-
const answered = new Map(fields);
|
|
4738
|
-
const violations = [];
|
|
4739
|
-
for (const [role, value] of fields) {
|
|
4740
|
-
const primitive = primitiveOf(role);
|
|
4741
|
-
if (!primitive) {
|
|
4742
|
-
violations.push({ role: CONTRACT_NAME.test(role) ? role : null, rule: "unknown_role" });
|
|
4743
|
-
continue;
|
|
4744
|
-
}
|
|
4745
|
-
if (!(0, import_mini4.safeParse)(leadFormPrimitiveSchemas[primitive], value).success) {
|
|
4746
|
-
violations.push({ role, rule: "invalid_value" });
|
|
4747
|
-
continue;
|
|
4748
|
-
}
|
|
4749
|
-
const allowed = contract?.options[role] ?? registryOptions(role);
|
|
4750
|
-
if (allowed?.length && optionKeys(value).some((key) => !allowed.includes(key))) {
|
|
4751
|
-
violations.push({ role, rule: "unknown_option" });
|
|
4752
|
-
}
|
|
4753
|
-
}
|
|
4754
|
-
for (const { role, requiredWhen } of contract?.requires ?? []) {
|
|
4755
|
-
const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
|
|
4756
|
-
if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
|
|
4757
|
-
}
|
|
4758
|
-
for (const group of contract?.requiresAny ?? []) {
|
|
4759
|
-
if (!group.some((role) => answered.has(role))) {
|
|
4760
|
-
violations.push({ role: group.join("|"), rule: "missing_any_of" });
|
|
4761
|
-
}
|
|
4762
|
-
}
|
|
4763
|
-
return violations;
|
|
4764
|
-
}
|
|
4765
|
-
function primitiveOf(role) {
|
|
4766
|
-
if (ADD_ON.test(role)) return "bool";
|
|
4767
|
-
return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].primitive : null;
|
|
4768
|
-
}
|
|
4769
|
-
function labelOf(role) {
|
|
4770
|
-
if (ADD_ON.test(role)) return role.slice("add_on:".length).replaceAll(/[_-]+/g, " ");
|
|
4771
|
-
return KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role].smsLabel || null : null;
|
|
4772
|
-
}
|
|
4773
|
-
function registryOptions(role) {
|
|
4774
|
-
const spec = KNOWN_ROLES.has(role) ? LEAD_FORM_ROLE_SPECS[role] : void 0;
|
|
4775
|
-
return spec && "options" in spec ? spec.options.map((o) => o.key) : void 0;
|
|
4776
|
-
}
|
|
4777
|
-
function optionKeys(value) {
|
|
4778
|
-
if (typeof value === "string") return [value];
|
|
4779
|
-
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
4780
|
-
}
|
|
4781
4797
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4782
4798
|
0 && (module.exports = {
|
|
4783
4799
|
AdPlatformTracking,
|