@kubuild/core 0.4.0 → 0.6.0
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/index.cjs +430 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +420 -13
- package/dist/index.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/server-tracking.d.ts +110 -0
- package/dist/runtime/server-tracking.d.ts.map +1 -0
- package/dist/validation/validator.d.ts +14 -0
- package/dist/validation/validator.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -58,6 +58,7 @@ __export(index_exports, {
|
|
|
58
58
|
defaultIdGenerator: () => defaultIdGenerator,
|
|
59
59
|
defaultMigrationRegistry: () => defaultMigrationRegistry,
|
|
60
60
|
defaultRenameAssetStrategy: () => defaultRenameAssetStrategy,
|
|
61
|
+
dispatchServerTracking: () => dispatchServerTracking,
|
|
61
62
|
duplicateNode: () => duplicateNode,
|
|
62
63
|
evaluateActionCondition: () => evaluateActionCondition,
|
|
63
64
|
evaluateCondition: () => evaluateCondition,
|
|
@@ -77,6 +78,7 @@ __export(index_exports, {
|
|
|
77
78
|
findMissingComponentNodes: () => findMissingComponentNodes,
|
|
78
79
|
findNodeById: () => findNodeById,
|
|
79
80
|
findNodeLocation: () => findNodeLocation,
|
|
81
|
+
generateTrackingEventId: () => generateTrackingEventId,
|
|
80
82
|
getActiveArtboard: () => getActiveArtboard,
|
|
81
83
|
getAncestorChain: () => getAncestorChain,
|
|
82
84
|
getComponentArtboards: () => getComponentArtboards,
|
|
@@ -86,6 +88,7 @@ __export(index_exports, {
|
|
|
86
88
|
getPageArtboards: () => getPageArtboards,
|
|
87
89
|
getParentNodeId: () => getParentNodeId,
|
|
88
90
|
hasTemplateExpressions: () => hasTemplateExpressions,
|
|
91
|
+
hashSha256: () => hashSha256,
|
|
89
92
|
importPackage: () => importPackage,
|
|
90
93
|
importStoraPackage: () => importStoraPackage,
|
|
91
94
|
insertNode: () => insertNode,
|
|
@@ -103,6 +106,9 @@ __export(index_exports, {
|
|
|
103
106
|
loadProjectDocument: () => loadProjectDocument,
|
|
104
107
|
migrateDocument: () => migrateDocument,
|
|
105
108
|
moveNode: () => moveNode,
|
|
109
|
+
normalizeEmail: () => normalizeEmail,
|
|
110
|
+
normalizePhone: () => normalizePhone,
|
|
111
|
+
normalizeText: () => normalizeText,
|
|
106
112
|
preflightPackage: () => preflightPackage,
|
|
107
113
|
previewImportPackage: () => previewImportPackage,
|
|
108
114
|
remapAssetReferences: () => remapAssetReferences,
|
|
@@ -118,6 +124,10 @@ __export(index_exports, {
|
|
|
118
124
|
sanitizeHtml: () => sanitizeHtml,
|
|
119
125
|
sanitizeUrl: () => sanitizeUrl,
|
|
120
126
|
saveDraftAsTemplate: () => saveDraftAsTemplate,
|
|
127
|
+
sendCustomWebhookEvent: () => sendCustomWebhookEvent,
|
|
128
|
+
sendGa4MeasurementEvent: () => sendGa4MeasurementEvent,
|
|
129
|
+
sendMetaCapiEvent: () => sendMetaCapiEvent,
|
|
130
|
+
sendTikTokEventsApi: () => sendTikTokEventsApi,
|
|
121
131
|
setActiveArtboard: () => setActiveArtboard,
|
|
122
132
|
sha256Sync: () => sha256Sync,
|
|
123
133
|
ungroupNodeFrame: () => ungroupNodeFrame,
|
|
@@ -2584,6 +2594,385 @@ function createRuntimeStore(initialState) {
|
|
|
2584
2594
|
return new RuntimeStateStore(initialState);
|
|
2585
2595
|
}
|
|
2586
2596
|
|
|
2597
|
+
// src/runtime/server-tracking.ts
|
|
2598
|
+
function normalizeEmail(email) {
|
|
2599
|
+
return (email || "").trim().toLowerCase();
|
|
2600
|
+
}
|
|
2601
|
+
function normalizePhone(phone) {
|
|
2602
|
+
return (phone || "").replace(/[^0-9]/g, "");
|
|
2603
|
+
}
|
|
2604
|
+
function normalizeText(text) {
|
|
2605
|
+
return (text || "").trim().toLowerCase();
|
|
2606
|
+
}
|
|
2607
|
+
async function hashSha256(value) {
|
|
2608
|
+
const normalized = (value || "").trim();
|
|
2609
|
+
if (!normalized) return "";
|
|
2610
|
+
if (typeof globalThis.crypto?.subtle?.digest === "function") {
|
|
2611
|
+
const encoder = new TextEncoder();
|
|
2612
|
+
const data = encoder.encode(normalized);
|
|
2613
|
+
const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
2614
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
2615
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2616
|
+
}
|
|
2617
|
+
throw new Error("Web Crypto API (crypto.subtle) is not available in current runtime environment.");
|
|
2618
|
+
}
|
|
2619
|
+
function generateTrackingEventId(prefix = "evt") {
|
|
2620
|
+
const timestamp = Date.now().toString(36);
|
|
2621
|
+
const randomPart = Math.random().toString(36).substring(2, 10);
|
|
2622
|
+
return `${prefix}_${timestamp}_${randomPart}`;
|
|
2623
|
+
}
|
|
2624
|
+
async function sendMetaCapiEvent(event, config, options) {
|
|
2625
|
+
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2626
|
+
if (!config.pixelId) {
|
|
2627
|
+
return {
|
|
2628
|
+
provider: "meta",
|
|
2629
|
+
success: false,
|
|
2630
|
+
error: "Meta Pixel ID is missing"
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
const rawUserData = event.userData || {};
|
|
2634
|
+
const hashedUserData = {};
|
|
2635
|
+
if (rawUserData.email) {
|
|
2636
|
+
hashedUserData.em = [await hashSha256(normalizeEmail(String(rawUserData.email)))];
|
|
2637
|
+
}
|
|
2638
|
+
if (rawUserData.phone) {
|
|
2639
|
+
hashedUserData.ph = [await hashSha256(normalizePhone(String(rawUserData.phone)))];
|
|
2640
|
+
}
|
|
2641
|
+
if (rawUserData.firstName) {
|
|
2642
|
+
hashedUserData.fn = [await hashSha256(normalizeText(String(rawUserData.firstName)))];
|
|
2643
|
+
}
|
|
2644
|
+
if (rawUserData.lastName) {
|
|
2645
|
+
hashedUserData.ln = [await hashSha256(normalizeText(String(rawUserData.lastName)))];
|
|
2646
|
+
}
|
|
2647
|
+
if (rawUserData.city) {
|
|
2648
|
+
hashedUserData.ct = [await hashSha256(normalizeText(String(rawUserData.city)))];
|
|
2649
|
+
}
|
|
2650
|
+
if (rawUserData.state) {
|
|
2651
|
+
hashedUserData.st = [await hashSha256(normalizeText(String(rawUserData.state)))];
|
|
2652
|
+
}
|
|
2653
|
+
if (rawUserData.zip) {
|
|
2654
|
+
hashedUserData.zp = [await hashSha256(normalizeText(String(rawUserData.zip)))];
|
|
2655
|
+
}
|
|
2656
|
+
if (rawUserData.country) {
|
|
2657
|
+
hashedUserData.country = [await hashSha256(normalizeText(String(rawUserData.country)))];
|
|
2658
|
+
}
|
|
2659
|
+
const clientIp = rawUserData.clientIp || options?.clientIp;
|
|
2660
|
+
if (clientIp) hashedUserData.client_ip_address = clientIp;
|
|
2661
|
+
const clientUserAgent = rawUserData.clientUserAgent || options?.clientUserAgent;
|
|
2662
|
+
if (clientUserAgent) hashedUserData.client_user_agent = clientUserAgent;
|
|
2663
|
+
if (rawUserData.fbp) hashedUserData.fbp = rawUserData.fbp;
|
|
2664
|
+
if (rawUserData.fbc) hashedUserData.fbc = rawUserData.fbc;
|
|
2665
|
+
if (rawUserData.externalId) {
|
|
2666
|
+
hashedUserData.external_id = [await hashSha256(String(rawUserData.externalId))];
|
|
2667
|
+
}
|
|
2668
|
+
const eventTime = event.eventTime || Math.floor(Date.now() / 1e3);
|
|
2669
|
+
const eventSourceUrl = event.eventSourceUrl || options?.sourceUrl;
|
|
2670
|
+
const capiPayload = {
|
|
2671
|
+
data: [
|
|
2672
|
+
{
|
|
2673
|
+
event_name: event.eventName,
|
|
2674
|
+
event_time: eventTime,
|
|
2675
|
+
event_id: event.eventId,
|
|
2676
|
+
event_source_url: eventSourceUrl,
|
|
2677
|
+
action_source: event.actionSource || "website",
|
|
2678
|
+
user_data: hashedUserData,
|
|
2679
|
+
custom_data: {
|
|
2680
|
+
...event.params || {},
|
|
2681
|
+
...event.customData || {}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
]
|
|
2685
|
+
};
|
|
2686
|
+
if (config.testEventCode) {
|
|
2687
|
+
capiPayload.test_event_code = config.testEventCode;
|
|
2688
|
+
}
|
|
2689
|
+
if (options?.simulateInDebug) {
|
|
2690
|
+
options.onLog?.("[Meta CAPI SIMULATED]", capiPayload);
|
|
2691
|
+
return { provider: "meta", success: true, data: { simulated: true, payload: capiPayload } };
|
|
2692
|
+
}
|
|
2693
|
+
try {
|
|
2694
|
+
const url = `https://graph.facebook.com/v19.0/${encodeURIComponent(config.pixelId)}/events`;
|
|
2695
|
+
const headers = {
|
|
2696
|
+
"Content-Type": "application/json"
|
|
2697
|
+
};
|
|
2698
|
+
if (config.capiAccessToken) {
|
|
2699
|
+
headers["Authorization"] = `Bearer ${config.capiAccessToken}`;
|
|
2700
|
+
}
|
|
2701
|
+
const res = await fetcher(url, {
|
|
2702
|
+
method: "POST",
|
|
2703
|
+
headers,
|
|
2704
|
+
body: JSON.stringify(capiPayload)
|
|
2705
|
+
});
|
|
2706
|
+
const resJson = await res.json().catch(() => ({}));
|
|
2707
|
+
if (!res.ok) {
|
|
2708
|
+
return {
|
|
2709
|
+
provider: "meta",
|
|
2710
|
+
success: false,
|
|
2711
|
+
status: res.status,
|
|
2712
|
+
error: resJson?.error?.message || `HTTP ${res.status}`,
|
|
2713
|
+
data: resJson
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
return {
|
|
2717
|
+
provider: "meta",
|
|
2718
|
+
success: true,
|
|
2719
|
+
status: res.status,
|
|
2720
|
+
data: resJson
|
|
2721
|
+
};
|
|
2722
|
+
} catch (err) {
|
|
2723
|
+
return {
|
|
2724
|
+
provider: "meta",
|
|
2725
|
+
success: false,
|
|
2726
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
async function sendTikTokEventsApi(event, config, options) {
|
|
2731
|
+
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2732
|
+
if (!config.pixelId) {
|
|
2733
|
+
return { provider: "tiktok", success: false, error: "TikTok Pixel ID is missing" };
|
|
2734
|
+
}
|
|
2735
|
+
const rawUserData = event.userData || {};
|
|
2736
|
+
const user = {};
|
|
2737
|
+
if (rawUserData.email) {
|
|
2738
|
+
user.email = await hashSha256(normalizeEmail(String(rawUserData.email)));
|
|
2739
|
+
}
|
|
2740
|
+
if (rawUserData.phone) {
|
|
2741
|
+
user.phone_number = await hashSha256(normalizePhone(String(rawUserData.phone)));
|
|
2742
|
+
}
|
|
2743
|
+
if (rawUserData.clientIp || options?.clientIp) {
|
|
2744
|
+
user.ip = rawUserData.clientIp || options?.clientIp;
|
|
2745
|
+
}
|
|
2746
|
+
if (rawUserData.clientUserAgent || options?.clientUserAgent) {
|
|
2747
|
+
user.user_agent = rawUserData.clientUserAgent || options?.clientUserAgent;
|
|
2748
|
+
}
|
|
2749
|
+
const tiktokPayload = {
|
|
2750
|
+
event_source: "web",
|
|
2751
|
+
event_source_id: config.pixelId,
|
|
2752
|
+
data: [
|
|
2753
|
+
{
|
|
2754
|
+
event: event.eventName,
|
|
2755
|
+
event_id: event.eventId,
|
|
2756
|
+
timestamp: new Date(event.eventTime ? event.eventTime * 1e3 : Date.now()).toISOString(),
|
|
2757
|
+
user,
|
|
2758
|
+
properties: {
|
|
2759
|
+
...event.params || {},
|
|
2760
|
+
...event.customData || {}
|
|
2761
|
+
},
|
|
2762
|
+
page: {
|
|
2763
|
+
url: event.eventSourceUrl || options?.sourceUrl
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
]
|
|
2767
|
+
};
|
|
2768
|
+
if (config.testEventCode) {
|
|
2769
|
+
tiktokPayload.test_event_code = config.testEventCode;
|
|
2770
|
+
}
|
|
2771
|
+
if (options?.simulateInDebug) {
|
|
2772
|
+
options.onLog?.("[TikTok Events API SIMULATED]", tiktokPayload);
|
|
2773
|
+
return { provider: "tiktok", success: true, data: { simulated: true, payload: tiktokPayload } };
|
|
2774
|
+
}
|
|
2775
|
+
try {
|
|
2776
|
+
const url = "https://business-api.tiktok.com/open_api/v1.3/event/track/";
|
|
2777
|
+
const headers = {
|
|
2778
|
+
"Content-Type": "application/json"
|
|
2779
|
+
};
|
|
2780
|
+
if (config.accessToken) {
|
|
2781
|
+
headers["Access-Token"] = config.accessToken;
|
|
2782
|
+
}
|
|
2783
|
+
const res = await fetcher(url, {
|
|
2784
|
+
method: "POST",
|
|
2785
|
+
headers,
|
|
2786
|
+
body: JSON.stringify(tiktokPayload)
|
|
2787
|
+
});
|
|
2788
|
+
const resJson = await res.json().catch(() => ({}));
|
|
2789
|
+
if (!res.ok) {
|
|
2790
|
+
return {
|
|
2791
|
+
provider: "tiktok",
|
|
2792
|
+
success: false,
|
|
2793
|
+
status: res.status,
|
|
2794
|
+
error: resJson?.message || `HTTP ${res.status}`,
|
|
2795
|
+
data: resJson
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
return { provider: "tiktok", success: true, status: res.status, data: resJson };
|
|
2799
|
+
} catch (err) {
|
|
2800
|
+
return {
|
|
2801
|
+
provider: "tiktok",
|
|
2802
|
+
success: false,
|
|
2803
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
async function sendGa4MeasurementEvent(event, config, options) {
|
|
2808
|
+
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2809
|
+
if (!config.measurementId) {
|
|
2810
|
+
return { provider: "google", success: false, error: "GA4 Measurement ID is missing" };
|
|
2811
|
+
}
|
|
2812
|
+
const clientId = event.userData?.clientId || event.userData?.externalId || "anonymous_client";
|
|
2813
|
+
const ga4Payload = {
|
|
2814
|
+
client_id: clientId,
|
|
2815
|
+
events: [
|
|
2816
|
+
{
|
|
2817
|
+
name: event.eventName.toLowerCase().replace(/[^a-z0-9_]/g, "_"),
|
|
2818
|
+
params: {
|
|
2819
|
+
...event.params || {},
|
|
2820
|
+
...event.customData || {},
|
|
2821
|
+
event_id: event.eventId
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
]
|
|
2825
|
+
};
|
|
2826
|
+
if (options?.simulateInDebug) {
|
|
2827
|
+
options.onLog?.("[GA4 Measurement Protocol SIMULATED]", ga4Payload);
|
|
2828
|
+
return { provider: "google", success: true, data: { simulated: true, payload: ga4Payload } };
|
|
2829
|
+
}
|
|
2830
|
+
try {
|
|
2831
|
+
let url = `https://www.google-analytics.com/mp/collect?measurement_id=${encodeURIComponent(
|
|
2832
|
+
config.measurementId
|
|
2833
|
+
)}`;
|
|
2834
|
+
if (config.measurementProtocolSecret) {
|
|
2835
|
+
url += `&api_secret=${encodeURIComponent(config.measurementProtocolSecret)}`;
|
|
2836
|
+
}
|
|
2837
|
+
const res = await fetcher(url, {
|
|
2838
|
+
method: "POST",
|
|
2839
|
+
headers: { "Content-Type": "application/json" },
|
|
2840
|
+
body: JSON.stringify(ga4Payload)
|
|
2841
|
+
});
|
|
2842
|
+
return {
|
|
2843
|
+
provider: "google",
|
|
2844
|
+
success: res.ok,
|
|
2845
|
+
status: res.status,
|
|
2846
|
+
data: { status: res.status }
|
|
2847
|
+
};
|
|
2848
|
+
} catch (err) {
|
|
2849
|
+
return {
|
|
2850
|
+
provider: "google",
|
|
2851
|
+
success: false,
|
|
2852
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2853
|
+
};
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
async function sendCustomWebhookEvent(event, config, options) {
|
|
2857
|
+
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2858
|
+
if (!config.endpointUrl) {
|
|
2859
|
+
return { provider: "custom", success: false, error: "Custom Webhook URL is missing" };
|
|
2860
|
+
}
|
|
2861
|
+
const webhookPayload = {
|
|
2862
|
+
event: event.eventName,
|
|
2863
|
+
eventId: event.eventId,
|
|
2864
|
+
timestamp: event.eventTime ? event.eventTime * 1e3 : Date.now(),
|
|
2865
|
+
userData: event.userData,
|
|
2866
|
+
params: event.params,
|
|
2867
|
+
customData: event.customData,
|
|
2868
|
+
sourceUrl: event.eventSourceUrl || options?.sourceUrl
|
|
2869
|
+
};
|
|
2870
|
+
if (options?.simulateInDebug) {
|
|
2871
|
+
options.onLog?.("[Custom Webhook SIMULATED]", webhookPayload);
|
|
2872
|
+
return { provider: "custom", success: true, data: { simulated: true, payload: webhookPayload } };
|
|
2873
|
+
}
|
|
2874
|
+
try {
|
|
2875
|
+
const res = await fetcher(config.endpointUrl, {
|
|
2876
|
+
method: "POST",
|
|
2877
|
+
headers: {
|
|
2878
|
+
"Content-Type": "application/json",
|
|
2879
|
+
...config.headers || {}
|
|
2880
|
+
},
|
|
2881
|
+
body: JSON.stringify(webhookPayload)
|
|
2882
|
+
});
|
|
2883
|
+
const resJson = await res.json().catch(() => ({}));
|
|
2884
|
+
return {
|
|
2885
|
+
provider: "custom",
|
|
2886
|
+
success: res.ok,
|
|
2887
|
+
status: res.status,
|
|
2888
|
+
data: resJson
|
|
2889
|
+
};
|
|
2890
|
+
} catch (err) {
|
|
2891
|
+
return {
|
|
2892
|
+
provider: "custom",
|
|
2893
|
+
success: false,
|
|
2894
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
async function dispatchServerTracking(event, config, options) {
|
|
2899
|
+
const eventId = event.eventId || generateTrackingEventId();
|
|
2900
|
+
const eventWithId = { ...event, eventId };
|
|
2901
|
+
if (!config || config.enabled === false) {
|
|
2902
|
+
return {
|
|
2903
|
+
success: true,
|
|
2904
|
+
eventId,
|
|
2905
|
+
skipped: true,
|
|
2906
|
+
reason: "Tracking is disabled globally",
|
|
2907
|
+
results: {}
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
const isDebug = Boolean(config.debugMode);
|
|
2911
|
+
const simulate = isDebug && options?.simulateInDebug !== false;
|
|
2912
|
+
const mergedOptions = {
|
|
2913
|
+
...options,
|
|
2914
|
+
simulateInDebug: simulate,
|
|
2915
|
+
onLog: (msg, data) => {
|
|
2916
|
+
if (isDebug) {
|
|
2917
|
+
console.log(`[KUBUILD Tracking] ${msg}`, data || "");
|
|
2918
|
+
}
|
|
2919
|
+
options?.onLog?.(msg, data);
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
const providers = config.providers || {};
|
|
2923
|
+
const dispatchPromises = [];
|
|
2924
|
+
if (providers.meta && providers.meta.enabled !== false && providers.meta.capiEnabled) {
|
|
2925
|
+
dispatchPromises.push(
|
|
2926
|
+
sendMetaCapiEvent(eventWithId, providers.meta, mergedOptions).then((result) => ({
|
|
2927
|
+
key: "meta",
|
|
2928
|
+
result
|
|
2929
|
+
}))
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
if (providers.tiktok && providers.tiktok.enabled !== false && providers.tiktok.eventsApiEnabled) {
|
|
2933
|
+
dispatchPromises.push(
|
|
2934
|
+
sendTikTokEventsApi(eventWithId, providers.tiktok, mergedOptions).then((result) => ({
|
|
2935
|
+
key: "tiktok",
|
|
2936
|
+
result
|
|
2937
|
+
}))
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
if (providers.google && providers.google.enabled !== false && providers.google.measurementId && providers.google.measurementProtocolSecret) {
|
|
2941
|
+
dispatchPromises.push(
|
|
2942
|
+
sendGa4MeasurementEvent(eventWithId, providers.google, mergedOptions).then((result) => ({
|
|
2943
|
+
key: "google",
|
|
2944
|
+
result
|
|
2945
|
+
}))
|
|
2946
|
+
);
|
|
2947
|
+
}
|
|
2948
|
+
if (providers.custom && providers.custom.enabled !== false && providers.custom.endpointUrl) {
|
|
2949
|
+
dispatchPromises.push(
|
|
2950
|
+
sendCustomWebhookEvent(eventWithId, providers.custom, mergedOptions).then((result) => ({
|
|
2951
|
+
key: "custom",
|
|
2952
|
+
result
|
|
2953
|
+
}))
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
const settled = await Promise.allSettled(dispatchPromises);
|
|
2957
|
+
const results = {};
|
|
2958
|
+
let overallSuccess = true;
|
|
2959
|
+
for (const item of settled) {
|
|
2960
|
+
if (item.status === "fulfilled") {
|
|
2961
|
+
results[item.value.key] = item.value.result;
|
|
2962
|
+
if (!item.value.result.success) {
|
|
2963
|
+
overallSuccess = false;
|
|
2964
|
+
}
|
|
2965
|
+
} else {
|
|
2966
|
+
overallSuccess = false;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
return {
|
|
2970
|
+
success: overallSuccess,
|
|
2971
|
+
eventId,
|
|
2972
|
+
results
|
|
2973
|
+
};
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2587
2976
|
// src/io/exporter.ts
|
|
2588
2977
|
var import_fflate = require("fflate");
|
|
2589
2978
|
var import_schema6 = require("@kubuild/schema");
|
|
@@ -2843,6 +3232,7 @@ function sanitizeHtml(rawHtml) {
|
|
|
2843
3232
|
// src/validation/validator.ts
|
|
2844
3233
|
function validateDocument(input, options = {}) {
|
|
2845
3234
|
const errors = [];
|
|
3235
|
+
const warnings = [];
|
|
2846
3236
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
2847
3237
|
return {
|
|
2848
3238
|
valid: false,
|
|
@@ -2853,7 +3243,8 @@ function validateDocument(input, options = {}) {
|
|
|
2853
3243
|
message: "Document must be a valid non-null object",
|
|
2854
3244
|
path: ""
|
|
2855
3245
|
}
|
|
2856
|
-
]
|
|
3246
|
+
],
|
|
3247
|
+
warnings: []
|
|
2857
3248
|
};
|
|
2858
3249
|
}
|
|
2859
3250
|
const doc = input;
|
|
@@ -2871,7 +3262,8 @@ function validateDocument(input, options = {}) {
|
|
|
2871
3262
|
return {
|
|
2872
3263
|
valid: false,
|
|
2873
3264
|
success: false,
|
|
2874
|
-
errors
|
|
3265
|
+
errors,
|
|
3266
|
+
warnings: []
|
|
2875
3267
|
};
|
|
2876
3268
|
}
|
|
2877
3269
|
}
|
|
@@ -2898,7 +3290,8 @@ function validateDocument(input, options = {}) {
|
|
|
2898
3290
|
return {
|
|
2899
3291
|
valid: false,
|
|
2900
3292
|
success: false,
|
|
2901
|
-
errors
|
|
3293
|
+
errors,
|
|
3294
|
+
warnings
|
|
2902
3295
|
};
|
|
2903
3296
|
}
|
|
2904
3297
|
const rootNode = doc.document;
|
|
@@ -2937,7 +3330,8 @@ function validateDocument(input, options = {}) {
|
|
|
2937
3330
|
seenIds,
|
|
2938
3331
|
visitedObjects,
|
|
2939
3332
|
options,
|
|
2940
|
-
errors
|
|
3333
|
+
errors,
|
|
3334
|
+
warnings
|
|
2941
3335
|
);
|
|
2942
3336
|
if (errors.length === 0) {
|
|
2943
3337
|
const zodResult = import_schema5.PageDocumentSchema.safeParse(input);
|
|
@@ -2955,6 +3349,7 @@ function validateDocument(input, options = {}) {
|
|
|
2955
3349
|
valid: true,
|
|
2956
3350
|
success: true,
|
|
2957
3351
|
errors: [],
|
|
3352
|
+
warnings,
|
|
2958
3353
|
data: zodResult.data
|
|
2959
3354
|
};
|
|
2960
3355
|
}
|
|
@@ -2962,10 +3357,11 @@ function validateDocument(input, options = {}) {
|
|
|
2962
3357
|
return {
|
|
2963
3358
|
valid: errors.length === 0,
|
|
2964
3359
|
success: errors.length === 0,
|
|
2965
|
-
errors
|
|
3360
|
+
errors,
|
|
3361
|
+
warnings
|
|
2966
3362
|
};
|
|
2967
3363
|
}
|
|
2968
|
-
function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visitedObjects, options, errors) {
|
|
3364
|
+
function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visitedObjects, options, errors, warnings) {
|
|
2969
3365
|
if (visitedObjects.has(nodeObj)) {
|
|
2970
3366
|
errors.push({
|
|
2971
3367
|
code: "TREE_CYCLE_DETECTED",
|
|
@@ -3074,12 +3470,22 @@ function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visite
|
|
|
3074
3470
|
const childIsKnown = !options.componentRegistry || options.componentRegistry.has(childType);
|
|
3075
3471
|
const childCategory = options.componentRegistry?.get(childType)?.category;
|
|
3076
3472
|
if (componentDef?.allowedChildren && childType && childIsKnown && !componentDef.allowedChildren.includes(childType) && !componentDef.allowedChildren.includes("*") && !(childCategory && componentDef.allowedChildren.includes(childCategory))) {
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3473
|
+
const violationMessage = `Component type "${childType}" is not allowed as a child of "${effectiveNodeType}". Allowed types: ${componentDef.allowedChildren.join(", ")}`;
|
|
3474
|
+
if (options.strictChildPolicy) {
|
|
3475
|
+
errors.push({
|
|
3476
|
+
code: "CHILD_POLICY_VIOLATION",
|
|
3477
|
+
message: violationMessage,
|
|
3478
|
+
path: `${childPath}/type`,
|
|
3479
|
+
nodeId: typeof childRecord.id === "string" ? childRecord.id : void 0
|
|
3480
|
+
});
|
|
3481
|
+
} else {
|
|
3482
|
+
warnings.push({
|
|
3483
|
+
code: "CHILD_POLICY_VIOLATION",
|
|
3484
|
+
message: violationMessage,
|
|
3485
|
+
path: `${childPath}/type`,
|
|
3486
|
+
nodeId: typeof childRecord.id === "string" ? childRecord.id : void 0
|
|
3487
|
+
});
|
|
3488
|
+
}
|
|
3083
3489
|
}
|
|
3084
3490
|
validateNodeRecursive(
|
|
3085
3491
|
childRecord,
|
|
@@ -3088,7 +3494,8 @@ function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visite
|
|
|
3088
3494
|
seenIds,
|
|
3089
3495
|
visitedObjects,
|
|
3090
3496
|
options,
|
|
3091
|
-
errors
|
|
3497
|
+
errors,
|
|
3498
|
+
warnings
|
|
3092
3499
|
);
|
|
3093
3500
|
}
|
|
3094
3501
|
}
|
|
@@ -5730,6 +6137,7 @@ function isFormValid(errors) {
|
|
|
5730
6137
|
defaultIdGenerator,
|
|
5731
6138
|
defaultMigrationRegistry,
|
|
5732
6139
|
defaultRenameAssetStrategy,
|
|
6140
|
+
dispatchServerTracking,
|
|
5733
6141
|
duplicateNode,
|
|
5734
6142
|
evaluateActionCondition,
|
|
5735
6143
|
evaluateCondition,
|
|
@@ -5749,6 +6157,7 @@ function isFormValid(errors) {
|
|
|
5749
6157
|
findMissingComponentNodes,
|
|
5750
6158
|
findNodeById,
|
|
5751
6159
|
findNodeLocation,
|
|
6160
|
+
generateTrackingEventId,
|
|
5752
6161
|
getActiveArtboard,
|
|
5753
6162
|
getAncestorChain,
|
|
5754
6163
|
getComponentArtboards,
|
|
@@ -5758,6 +6167,7 @@ function isFormValid(errors) {
|
|
|
5758
6167
|
getPageArtboards,
|
|
5759
6168
|
getParentNodeId,
|
|
5760
6169
|
hasTemplateExpressions,
|
|
6170
|
+
hashSha256,
|
|
5761
6171
|
importPackage,
|
|
5762
6172
|
importStoraPackage,
|
|
5763
6173
|
insertNode,
|
|
@@ -5775,6 +6185,9 @@ function isFormValid(errors) {
|
|
|
5775
6185
|
loadProjectDocument,
|
|
5776
6186
|
migrateDocument,
|
|
5777
6187
|
moveNode,
|
|
6188
|
+
normalizeEmail,
|
|
6189
|
+
normalizePhone,
|
|
6190
|
+
normalizeText,
|
|
5778
6191
|
preflightPackage,
|
|
5779
6192
|
previewImportPackage,
|
|
5780
6193
|
remapAssetReferences,
|
|
@@ -5790,6 +6203,10 @@ function isFormValid(errors) {
|
|
|
5790
6203
|
sanitizeHtml,
|
|
5791
6204
|
sanitizeUrl,
|
|
5792
6205
|
saveDraftAsTemplate,
|
|
6206
|
+
sendCustomWebhookEvent,
|
|
6207
|
+
sendGa4MeasurementEvent,
|
|
6208
|
+
sendMetaCapiEvent,
|
|
6209
|
+
sendTikTokEventsApi,
|
|
5793
6210
|
setActiveArtboard,
|
|
5794
6211
|
sha256Sync,
|
|
5795
6212
|
ungroupNodeFrame,
|