@kubuild/core 0.6.0 → 0.7.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/document/document-utils.d.ts.map +1 -1
- package/dist/index.cjs +422 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +400 -82
- package/dist/index.js.map +1 -1
- package/dist/io/exporter.d.ts.map +1 -1
- package/dist/io/importer.d.ts +4 -2
- package/dist/io/importer.d.ts.map +1 -1
- package/dist/io/index.d.ts +1 -0
- package/dist/io/index.d.ts.map +1 -1
- package/dist/io/migration.d.ts +21 -2
- package/dist/io/migration.d.ts.map +1 -1
- package/dist/io/tracking-sanitizer.d.ts +23 -0
- package/dist/io/tracking-sanitizer.d.ts.map +1 -0
- package/dist/runtime/binding-resolver.d.ts.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 +40 -7
- package/dist/runtime/server-tracking.d.ts.map +1 -1
- package/dist/runtime/tracking-relay.d.ts +44 -0
- package/dist/runtime/tracking-relay.d.ts.map +1 -0
- package/dist/types/interfaces.d.ts +37 -1
- package/dist/types/interfaces.d.ts.map +1 -1
- package/dist/validation/validator.d.ts +24 -1
- package/dist/validation/validator.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/document/document-utils.ts
|
|
2
|
-
import { SCHEMA_NAME } from "@kubuild/schema";
|
|
2
|
+
import { SCHEMA_NAME, CURRENT_SCHEMA_VERSION } from "@kubuild/schema";
|
|
3
3
|
function createBlankDocument(title = "Untitled Page") {
|
|
4
4
|
return {
|
|
5
5
|
schema: SCHEMA_NAME,
|
|
6
|
-
version:
|
|
6
|
+
version: CURRENT_SCHEMA_VERSION,
|
|
7
7
|
metadata: {
|
|
8
8
|
title,
|
|
9
9
|
description: "",
|
|
@@ -889,7 +889,7 @@ import {
|
|
|
889
889
|
SCHEMA_NAME as SCHEMA_NAME2,
|
|
890
890
|
PROJECT_SCHEMA_NAME,
|
|
891
891
|
CURRENT_PROJECT_SCHEMA_VERSION,
|
|
892
|
-
CURRENT_SCHEMA_VERSION,
|
|
892
|
+
CURRENT_SCHEMA_VERSION as CURRENT_SCHEMA_VERSION2,
|
|
893
893
|
ARTBOARD_REFERENCE_NODE_TYPE
|
|
894
894
|
} from "@kubuild/schema";
|
|
895
895
|
var now = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -947,14 +947,14 @@ function createComponentArtboard(node, options = {}) {
|
|
|
947
947
|
const triggerId = options.triggerId ?? (typeof node.props?.modalId === "string" && node.props.modalId.trim().length > 0 ? node.props.modalId : node.id);
|
|
948
948
|
const document = {
|
|
949
949
|
schema: SCHEMA_NAME2,
|
|
950
|
-
version:
|
|
950
|
+
version: CURRENT_SCHEMA_VERSION2,
|
|
951
951
|
metadata: {
|
|
952
952
|
title: name,
|
|
953
953
|
description: "",
|
|
954
954
|
author: "",
|
|
955
955
|
tags: [],
|
|
956
956
|
category: "component",
|
|
957
|
-
version:
|
|
957
|
+
version: CURRENT_SCHEMA_VERSION2,
|
|
958
958
|
createdAt: now(),
|
|
959
959
|
updatedAt: now()
|
|
960
960
|
},
|
|
@@ -1411,6 +1411,15 @@ var DocumentHistoryManager = class {
|
|
|
1411
1411
|
var FORBIDDEN_KEY_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1412
1412
|
function resolveBinding(binding, context) {
|
|
1413
1413
|
const segments = binding.key.split(".").filter(Boolean);
|
|
1414
|
+
if (segments.some((segment) => FORBIDDEN_KEY_SEGMENTS.has(segment))) {
|
|
1415
|
+
return applyMissingPolicy(binding);
|
|
1416
|
+
}
|
|
1417
|
+
if (context?.variables && typeof context.variables === "object" && Object.prototype.hasOwnProperty.call(context.variables, binding.key)) {
|
|
1418
|
+
const directValue = context.variables[binding.key];
|
|
1419
|
+
if (directValue !== void 0 && typeof directValue !== "function") {
|
|
1420
|
+
return { status: "resolved", value: directValue };
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1414
1423
|
let current = context?.variables;
|
|
1415
1424
|
for (const segment of segments) {
|
|
1416
1425
|
if (FORBIDDEN_KEY_SEGMENTS.has(segment)) {
|
|
@@ -1982,14 +1991,14 @@ var ActionPipelineExecutor = class {
|
|
|
1982
1991
|
async executeSingleStep(step, context, parentSignal, options) {
|
|
1983
1992
|
const stepStartTime = Date.now();
|
|
1984
1993
|
if (step.condition && !evaluateActionCondition(step.condition, context)) {
|
|
1985
|
-
const
|
|
1994
|
+
const skippedResult2 = {
|
|
1986
1995
|
stepId: step.id,
|
|
1987
1996
|
stepType: step.type,
|
|
1988
1997
|
status: "skipped",
|
|
1989
1998
|
durationMs: Date.now() - stepStartTime
|
|
1990
1999
|
};
|
|
1991
|
-
options?.onStepComplete?.(step,
|
|
1992
|
-
return
|
|
2000
|
+
options?.onStepComplete?.(step, skippedResult2, context);
|
|
2001
|
+
return skippedResult2;
|
|
1993
2002
|
}
|
|
1994
2003
|
options?.onStepStart?.(step, context);
|
|
1995
2004
|
const stepTimeout = step.timeout;
|
|
@@ -2481,7 +2490,7 @@ function generateTrackingEventId(prefix = "evt") {
|
|
|
2481
2490
|
const randomPart = Math.random().toString(36).substring(2, 10);
|
|
2482
2491
|
return `${prefix}_${timestamp}_${randomPart}`;
|
|
2483
2492
|
}
|
|
2484
|
-
async function sendMetaCapiEvent(event, config, options) {
|
|
2493
|
+
async function sendMetaCapiEvent(event, config, secrets, options) {
|
|
2485
2494
|
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2486
2495
|
if (!config.pixelId) {
|
|
2487
2496
|
return {
|
|
@@ -2555,9 +2564,10 @@ async function sendMetaCapiEvent(event, config, options) {
|
|
|
2555
2564
|
const headers = {
|
|
2556
2565
|
"Content-Type": "application/json"
|
|
2557
2566
|
};
|
|
2558
|
-
if (
|
|
2559
|
-
|
|
2567
|
+
if (!secrets?.capiAccessToken) {
|
|
2568
|
+
return skippedResult("meta", "No Meta CAPI access token resolved for this credential");
|
|
2560
2569
|
}
|
|
2570
|
+
headers["Authorization"] = `Bearer ${secrets.capiAccessToken}`;
|
|
2561
2571
|
const res = await fetcher(url, {
|
|
2562
2572
|
method: "POST",
|
|
2563
2573
|
headers,
|
|
@@ -2587,7 +2597,7 @@ async function sendMetaCapiEvent(event, config, options) {
|
|
|
2587
2597
|
};
|
|
2588
2598
|
}
|
|
2589
2599
|
}
|
|
2590
|
-
async function sendTikTokEventsApi(event, config, options) {
|
|
2600
|
+
async function sendTikTokEventsApi(event, config, secrets, options) {
|
|
2591
2601
|
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2592
2602
|
if (!config.pixelId) {
|
|
2593
2603
|
return { provider: "tiktok", success: false, error: "TikTok Pixel ID is missing" };
|
|
@@ -2637,9 +2647,10 @@ async function sendTikTokEventsApi(event, config, options) {
|
|
|
2637
2647
|
const headers = {
|
|
2638
2648
|
"Content-Type": "application/json"
|
|
2639
2649
|
};
|
|
2640
|
-
if (
|
|
2641
|
-
|
|
2650
|
+
if (!secrets?.accessToken) {
|
|
2651
|
+
return skippedResult("tiktok", "No TikTok Events API access token resolved for this credential");
|
|
2642
2652
|
}
|
|
2653
|
+
headers["Access-Token"] = secrets.accessToken;
|
|
2643
2654
|
const res = await fetcher(url, {
|
|
2644
2655
|
method: "POST",
|
|
2645
2656
|
headers,
|
|
@@ -2664,7 +2675,7 @@ async function sendTikTokEventsApi(event, config, options) {
|
|
|
2664
2675
|
};
|
|
2665
2676
|
}
|
|
2666
2677
|
}
|
|
2667
|
-
async function sendGa4MeasurementEvent(event, config, options) {
|
|
2678
|
+
async function sendGa4MeasurementEvent(event, config, secrets, options) {
|
|
2668
2679
|
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2669
2680
|
if (!config.measurementId) {
|
|
2670
2681
|
return { provider: "google", success: false, error: "GA4 Measurement ID is missing" };
|
|
@@ -2688,12 +2699,10 @@ async function sendGa4MeasurementEvent(event, config, options) {
|
|
|
2688
2699
|
return { provider: "google", success: true, data: { simulated: true, payload: ga4Payload } };
|
|
2689
2700
|
}
|
|
2690
2701
|
try {
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
)}`;
|
|
2694
|
-
if (config.measurementProtocolSecret) {
|
|
2695
|
-
url += `&api_secret=${encodeURIComponent(config.measurementProtocolSecret)}`;
|
|
2702
|
+
if (!secrets?.measurementProtocolSecret) {
|
|
2703
|
+
return skippedResult("google", "No GA4 Measurement Protocol API secret resolved for this credential");
|
|
2696
2704
|
}
|
|
2705
|
+
const url = `https://www.google-analytics.com/mp/collect?measurement_id=${encodeURIComponent(config.measurementId)}&api_secret=${encodeURIComponent(secrets.measurementProtocolSecret)}`;
|
|
2697
2706
|
const res = await fetcher(url, {
|
|
2698
2707
|
method: "POST",
|
|
2699
2708
|
headers: { "Content-Type": "application/json" },
|
|
@@ -2713,11 +2722,8 @@ async function sendGa4MeasurementEvent(event, config, options) {
|
|
|
2713
2722
|
};
|
|
2714
2723
|
}
|
|
2715
2724
|
}
|
|
2716
|
-
async function sendCustomWebhookEvent(event,
|
|
2725
|
+
async function sendCustomWebhookEvent(event, _config, secrets, options) {
|
|
2717
2726
|
const fetcher = options?.fetchFn || globalThis.fetch;
|
|
2718
|
-
if (!config.endpointUrl) {
|
|
2719
|
-
return { provider: "custom", success: false, error: "Custom Webhook URL is missing" };
|
|
2720
|
-
}
|
|
2721
2727
|
const webhookPayload = {
|
|
2722
2728
|
event: event.eventName,
|
|
2723
2729
|
eventId: event.eventId,
|
|
@@ -2731,12 +2737,15 @@ async function sendCustomWebhookEvent(event, config, options) {
|
|
|
2731
2737
|
options.onLog?.("[Custom Webhook SIMULATED]", webhookPayload);
|
|
2732
2738
|
return { provider: "custom", success: true, data: { simulated: true, payload: webhookPayload } };
|
|
2733
2739
|
}
|
|
2740
|
+
if (!secrets?.endpointUrl) {
|
|
2741
|
+
return skippedResult("custom", "No custom webhook destination resolved for this credential");
|
|
2742
|
+
}
|
|
2734
2743
|
try {
|
|
2735
|
-
const res = await fetcher(
|
|
2744
|
+
const res = await fetcher(secrets.endpointUrl, {
|
|
2736
2745
|
method: "POST",
|
|
2737
2746
|
headers: {
|
|
2738
2747
|
"Content-Type": "application/json",
|
|
2739
|
-
...
|
|
2748
|
+
...secrets.headers || {}
|
|
2740
2749
|
},
|
|
2741
2750
|
body: JSON.stringify(webhookPayload)
|
|
2742
2751
|
});
|
|
@@ -2755,6 +2764,9 @@ async function sendCustomWebhookEvent(event, config, options) {
|
|
|
2755
2764
|
};
|
|
2756
2765
|
}
|
|
2757
2766
|
}
|
|
2767
|
+
function skippedResult(provider, reason) {
|
|
2768
|
+
return { provider, success: true, skipped: true, reason };
|
|
2769
|
+
}
|
|
2758
2770
|
async function dispatchServerTracking(event, config, options) {
|
|
2759
2771
|
const eventId = event.eventId || generateTrackingEventId();
|
|
2760
2772
|
const eventWithId = { ...event, eventId };
|
|
@@ -2779,65 +2791,233 @@ async function dispatchServerTracking(event, config, options) {
|
|
|
2779
2791
|
options?.onLog?.(msg, data);
|
|
2780
2792
|
}
|
|
2781
2793
|
};
|
|
2794
|
+
const target = options?.provider || "all";
|
|
2795
|
+
const wants = (key) => target === "all" || target === key;
|
|
2782
2796
|
const providers = config.providers || {};
|
|
2783
|
-
const
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
);
|
|
2797
|
+
const tasks = [];
|
|
2798
|
+
const meta = providers.meta;
|
|
2799
|
+
if (wants("meta") && meta && meta.enabled !== false && meta.capiEnabled) {
|
|
2800
|
+
tasks.push({
|
|
2801
|
+
key: "meta",
|
|
2802
|
+
credentialId: meta.credentialId,
|
|
2803
|
+
run: (s) => sendMetaCapiEvent(eventWithId, meta, s, mergedOptions)
|
|
2804
|
+
});
|
|
2791
2805
|
}
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
);
|
|
2806
|
+
const tiktok = providers.tiktok;
|
|
2807
|
+
if (wants("tiktok") && tiktok && tiktok.enabled !== false && tiktok.eventsApiEnabled) {
|
|
2808
|
+
tasks.push({
|
|
2809
|
+
key: "tiktok",
|
|
2810
|
+
credentialId: tiktok.credentialId,
|
|
2811
|
+
run: (s) => sendTikTokEventsApi(eventWithId, tiktok, s, mergedOptions)
|
|
2812
|
+
});
|
|
2799
2813
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
);
|
|
2814
|
+
const google = providers.google;
|
|
2815
|
+
if (wants("google") && google && google.enabled !== false && google.measurementId) {
|
|
2816
|
+
tasks.push({
|
|
2817
|
+
key: "google",
|
|
2818
|
+
credentialId: google.credentialId,
|
|
2819
|
+
run: (s) => sendGa4MeasurementEvent(eventWithId, google, s, mergedOptions)
|
|
2820
|
+
});
|
|
2807
2821
|
}
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
);
|
|
2822
|
+
const custom = providers.custom;
|
|
2823
|
+
if (wants("custom") && custom && custom.enabled !== false) {
|
|
2824
|
+
tasks.push({
|
|
2825
|
+
key: "custom",
|
|
2826
|
+
credentialId: custom.credentialId,
|
|
2827
|
+
run: (s) => sendCustomWebhookEvent(eventWithId, custom, s, mergedOptions)
|
|
2828
|
+
});
|
|
2829
|
+
}
|
|
2830
|
+
if (tasks.length === 0) {
|
|
2831
|
+
return {
|
|
2832
|
+
success: true,
|
|
2833
|
+
eventId,
|
|
2834
|
+
skipped: true,
|
|
2835
|
+
reason: target === "gtm" ? "GTM is client-side only (dataLayer); no server delivery" : "No server-side tracking provider is enabled",
|
|
2836
|
+
results: {}
|
|
2837
|
+
};
|
|
2815
2838
|
}
|
|
2816
|
-
const
|
|
2839
|
+
const resolve = options?.resolveSecrets;
|
|
2840
|
+
const runTask = async (task) => {
|
|
2841
|
+
let secrets = null;
|
|
2842
|
+
if (resolve) {
|
|
2843
|
+
try {
|
|
2844
|
+
secrets = await resolve({ provider: task.key, credentialId: task.credentialId, documentId: options?.documentId }) ?? null;
|
|
2845
|
+
} catch (err) {
|
|
2846
|
+
return {
|
|
2847
|
+
provider: task.key,
|
|
2848
|
+
success: false,
|
|
2849
|
+
error: `Secret resolution failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
if (!secrets && !simulate) {
|
|
2854
|
+
const reason = resolve ? `No secret resolved for provider "${task.key}"${task.credentialId ? ` (credentialId "${task.credentialId}")` : " (no credentialId linked)"}` : "No secret resolver configured (options.resolveSecrets)";
|
|
2855
|
+
mergedOptions.onLog?.(`[${task.key}] skipped: ${reason}`);
|
|
2856
|
+
return skippedResult(task.key, reason);
|
|
2857
|
+
}
|
|
2858
|
+
return task.run(secrets);
|
|
2859
|
+
};
|
|
2860
|
+
const settled = await Promise.allSettled(tasks.map((task) => runTask(task)));
|
|
2817
2861
|
const results = {};
|
|
2818
2862
|
let overallSuccess = true;
|
|
2819
|
-
|
|
2863
|
+
let delivered = 0;
|
|
2864
|
+
settled.forEach((item, index) => {
|
|
2865
|
+
const key = tasks[index].key;
|
|
2820
2866
|
if (item.status === "fulfilled") {
|
|
2821
|
-
results[
|
|
2822
|
-
if (!item.value.
|
|
2823
|
-
|
|
2824
|
-
}
|
|
2867
|
+
results[key] = item.value;
|
|
2868
|
+
if (!item.value.success) overallSuccess = false;
|
|
2869
|
+
if (!item.value.skipped) delivered++;
|
|
2825
2870
|
} else {
|
|
2826
2871
|
overallSuccess = false;
|
|
2872
|
+
results[key] = {
|
|
2873
|
+
provider: key,
|
|
2874
|
+
success: false,
|
|
2875
|
+
error: item.reason instanceof Error ? item.reason.message : String(item.reason)
|
|
2876
|
+
};
|
|
2827
2877
|
}
|
|
2828
|
-
}
|
|
2878
|
+
});
|
|
2879
|
+
const allSkipped = delivered === 0 && overallSuccess;
|
|
2829
2880
|
return {
|
|
2830
2881
|
success: overallSuccess,
|
|
2831
2882
|
eventId,
|
|
2883
|
+
...allSkipped ? { skipped: true, reason: "All server providers were skipped" } : {},
|
|
2832
2884
|
results
|
|
2833
2885
|
};
|
|
2834
2886
|
}
|
|
2835
2887
|
|
|
2888
|
+
// src/runtime/tracking-relay.ts
|
|
2889
|
+
import {
|
|
2890
|
+
TRACKING_RELAY_PROTOCOL_VERSION,
|
|
2891
|
+
TrackingRelayRequestSchema
|
|
2892
|
+
} from "@kubuild/schema";
|
|
2893
|
+
var DEFAULT_MAX_BODY_BYTES = 64 * 1024;
|
|
2894
|
+
function defaultClientIp(request) {
|
|
2895
|
+
const forwarded = request.headers.get("x-forwarded-for");
|
|
2896
|
+
if (forwarded) {
|
|
2897
|
+
const first = forwarded.split(",")[0]?.trim();
|
|
2898
|
+
if (first) return first;
|
|
2899
|
+
}
|
|
2900
|
+
return request.headers.get("cf-connecting-ip")?.trim() || request.headers.get("x-real-ip")?.trim() || void 0;
|
|
2901
|
+
}
|
|
2902
|
+
function isOriginAllowed(origin, allowed) {
|
|
2903
|
+
if (!allowed) return true;
|
|
2904
|
+
if (!origin) return false;
|
|
2905
|
+
if (typeof allowed === "function") return allowed(origin);
|
|
2906
|
+
return allowed.includes(origin);
|
|
2907
|
+
}
|
|
2908
|
+
function createTrackingRelayHandler(options) {
|
|
2909
|
+
const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
2910
|
+
return async (request) => {
|
|
2911
|
+
const origin = request.headers.get("origin");
|
|
2912
|
+
const corsHeaders = {};
|
|
2913
|
+
if (options.allowedOrigins && origin && isOriginAllowed(origin, options.allowedOrigins)) {
|
|
2914
|
+
corsHeaders["Access-Control-Allow-Origin"] = origin;
|
|
2915
|
+
corsHeaders["Vary"] = "Origin";
|
|
2916
|
+
}
|
|
2917
|
+
const json = (body, status, extra) => new Response(JSON.stringify(body), {
|
|
2918
|
+
status,
|
|
2919
|
+
headers: { "Content-Type": "application/json", ...corsHeaders, ...extra || {} }
|
|
2920
|
+
});
|
|
2921
|
+
const fail = (code, message, status, extra) => json({ version: TRACKING_RELAY_PROTOCOL_VERSION, success: false, error: { code, message } }, status, extra);
|
|
2922
|
+
if (!isOriginAllowed(origin, options.allowedOrigins)) {
|
|
2923
|
+
return fail("FORBIDDEN_ORIGIN", "Origin is not allowed", 403);
|
|
2924
|
+
}
|
|
2925
|
+
if (request.method === "OPTIONS") {
|
|
2926
|
+
return new Response(null, {
|
|
2927
|
+
status: 204,
|
|
2928
|
+
headers: {
|
|
2929
|
+
...corsHeaders,
|
|
2930
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
2931
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
2932
|
+
"Access-Control-Max-Age": "600"
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
if (request.method !== "POST") {
|
|
2937
|
+
return fail("METHOD_NOT_ALLOWED", "Only POST requests are accepted", 405, { Allow: "POST, OPTIONS" });
|
|
2938
|
+
}
|
|
2939
|
+
try {
|
|
2940
|
+
const text = await request.text();
|
|
2941
|
+
if (text.length > maxBodyBytes) {
|
|
2942
|
+
return fail("INVALID_REQUEST", `Request body exceeds ${maxBodyBytes} bytes`, 413);
|
|
2943
|
+
}
|
|
2944
|
+
let raw;
|
|
2945
|
+
try {
|
|
2946
|
+
raw = JSON.parse(text);
|
|
2947
|
+
} catch {
|
|
2948
|
+
return fail("INVALID_REQUEST", "Request body must be valid JSON", 400);
|
|
2949
|
+
}
|
|
2950
|
+
if (raw && typeof raw === "object" && "version" in raw && raw.version !== TRACKING_RELAY_PROTOCOL_VERSION) {
|
|
2951
|
+
return fail(
|
|
2952
|
+
"UNSUPPORTED_VERSION",
|
|
2953
|
+
`Unsupported relay protocol version; expected ${TRACKING_RELAY_PROTOCOL_VERSION}`,
|
|
2954
|
+
400
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2957
|
+
const parsed = TrackingRelayRequestSchema.safeParse(raw);
|
|
2958
|
+
if (!parsed.success) {
|
|
2959
|
+
const issues = parsed.error.issues.slice(0, 5).map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
2960
|
+
return fail("INVALID_REQUEST", `Invalid relay request: ${issues}`, 400);
|
|
2961
|
+
}
|
|
2962
|
+
const body = parsed.data;
|
|
2963
|
+
const config = await options.getConfig({
|
|
2964
|
+
request,
|
|
2965
|
+
documentId: body.documentId,
|
|
2966
|
+
credentialId: body.credentialId,
|
|
2967
|
+
provider: body.provider
|
|
2968
|
+
});
|
|
2969
|
+
if (!config) {
|
|
2970
|
+
return fail("CONFIG_NOT_FOUND", "No tracking configuration found for this page", 404);
|
|
2971
|
+
}
|
|
2972
|
+
const clientIp = (options.getClientIp ?? defaultClientIp)(request);
|
|
2973
|
+
const clientUserAgent = request.headers.get("user-agent") || void 0;
|
|
2974
|
+
const userData = { ...body.event.userData || {} };
|
|
2975
|
+
delete userData.clientIp;
|
|
2976
|
+
delete userData.clientUserAgent;
|
|
2977
|
+
const event = { ...body.event, userData };
|
|
2978
|
+
const outcome = await dispatchServerTracking(event, config, {
|
|
2979
|
+
resolveSecrets: options.resolveSecrets,
|
|
2980
|
+
documentId: body.documentId,
|
|
2981
|
+
provider: body.provider,
|
|
2982
|
+
fetchFn: options.fetchFn,
|
|
2983
|
+
clientIp,
|
|
2984
|
+
clientUserAgent,
|
|
2985
|
+
onLog: options.onLog
|
|
2986
|
+
});
|
|
2987
|
+
const results = {};
|
|
2988
|
+
for (const [key, r] of Object.entries(outcome.results)) {
|
|
2989
|
+
results[key] = {
|
|
2990
|
+
provider: r.provider,
|
|
2991
|
+
success: r.success,
|
|
2992
|
+
...r.status !== void 0 ? { status: r.status } : {},
|
|
2993
|
+
...r.skipped ? { skipped: true } : {},
|
|
2994
|
+
...r.reason ? { reason: r.reason } : {},
|
|
2995
|
+
...r.error ? { error: r.error } : {}
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
return json(
|
|
2999
|
+
{
|
|
3000
|
+
version: TRACKING_RELAY_PROTOCOL_VERSION,
|
|
3001
|
+
success: outcome.success,
|
|
3002
|
+
eventId: outcome.eventId,
|
|
3003
|
+
...outcome.skipped ? { skipped: true } : {},
|
|
3004
|
+
...outcome.reason ? { reason: outcome.reason } : {},
|
|
3005
|
+
results
|
|
3006
|
+
},
|
|
3007
|
+
200
|
|
3008
|
+
);
|
|
3009
|
+
} catch (err) {
|
|
3010
|
+
options.onLog?.("[Tracking relay] internal error", err);
|
|
3011
|
+
return fail("INTERNAL_ERROR", "Tracking relay failed", 500);
|
|
3012
|
+
}
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
3015
|
+
|
|
2836
3016
|
// src/io/exporter.ts
|
|
2837
3017
|
import { zipSync, strToU8 } from "fflate";
|
|
2838
3018
|
import {
|
|
2839
3019
|
SCHEMA_NAME as SCHEMA_NAME4,
|
|
2840
|
-
CURRENT_SCHEMA_VERSION as
|
|
3020
|
+
CURRENT_SCHEMA_VERSION as CURRENT_SCHEMA_VERSION3
|
|
2841
3021
|
} from "@kubuild/schema";
|
|
2842
3022
|
|
|
2843
3023
|
// src/validation/validator.ts
|
|
@@ -3380,7 +3560,8 @@ function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visite
|
|
|
3380
3560
|
`${currentPath}/props`,
|
|
3381
3561
|
effectiveNodeId,
|
|
3382
3562
|
options,
|
|
3383
|
-
errors
|
|
3563
|
+
errors,
|
|
3564
|
+
warnings
|
|
3384
3565
|
);
|
|
3385
3566
|
}
|
|
3386
3567
|
}
|
|
@@ -3395,7 +3576,10 @@ function validateNodeRecursive(nodeObj, currentPath, parentNode, seenIds, visite
|
|
|
3395
3576
|
}
|
|
3396
3577
|
}
|
|
3397
3578
|
}
|
|
3398
|
-
function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
3579
|
+
function validatePropsBindings(propsObj, propsPath, nodeId, options, errors, warnings) {
|
|
3580
|
+
const checkAssets = options.checkAssetReferences !== false;
|
|
3581
|
+
const checkVariables = options.checkVariableBindings !== false;
|
|
3582
|
+
const checkActions = options.checkActionBindings !== false;
|
|
3399
3583
|
for (const [key, value] of Object.entries(propsObj)) {
|
|
3400
3584
|
const currentPath = `${propsPath}/${key}`;
|
|
3401
3585
|
if (!value || typeof value !== "object") {
|
|
@@ -3409,7 +3593,8 @@ function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
|
3409
3593
|
`${currentPath}/${index}`,
|
|
3410
3594
|
nodeId,
|
|
3411
3595
|
options,
|
|
3412
|
-
errors
|
|
3596
|
+
errors,
|
|
3597
|
+
warnings
|
|
3413
3598
|
);
|
|
3414
3599
|
}
|
|
3415
3600
|
});
|
|
@@ -3417,7 +3602,9 @@ function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
|
3417
3602
|
}
|
|
3418
3603
|
const record = value;
|
|
3419
3604
|
if (record.type === "asset") {
|
|
3420
|
-
if (
|
|
3605
|
+
if (!checkAssets) continue;
|
|
3606
|
+
const assetId = typeof record.assetId === "string" && record.assetId.trim().length > 0 ? record.assetId : void 0;
|
|
3607
|
+
if (assetId === void 0) {
|
|
3421
3608
|
errors.push({
|
|
3422
3609
|
code: "INVALID_ASSET_REFERENCE",
|
|
3423
3610
|
message: 'Asset reference must have a non-empty "assetId"',
|
|
@@ -3433,7 +3620,27 @@ function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
|
3433
3620
|
nodeId
|
|
3434
3621
|
});
|
|
3435
3622
|
}
|
|
3623
|
+
if (assetId !== void 0 && options.knownAssetIds && !isKnownId(options.knownAssetIds, assetId)) {
|
|
3624
|
+
if (typeof record.fallbackUrl === "string" && record.fallbackUrl.length > 0) {
|
|
3625
|
+
warnings.push({
|
|
3626
|
+
code: "UNRESOLVED_ASSET_REFERENCE",
|
|
3627
|
+
message: `Asset "${assetId}" is not among the known assets; its fallbackUrl will be used`,
|
|
3628
|
+
path: `${currentPath}/assetId`,
|
|
3629
|
+
nodeId,
|
|
3630
|
+
details: { assetId }
|
|
3631
|
+
});
|
|
3632
|
+
} else {
|
|
3633
|
+
errors.push({
|
|
3634
|
+
code: "INVALID_ASSET_REFERENCE",
|
|
3635
|
+
message: `Asset "${assetId}" is not among the known assets and has no fallbackUrl`,
|
|
3636
|
+
path: `${currentPath}/assetId`,
|
|
3637
|
+
nodeId,
|
|
3638
|
+
details: { assetId }
|
|
3639
|
+
});
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3436
3642
|
} else if (record.type === "variable") {
|
|
3643
|
+
if (!checkVariables) continue;
|
|
3437
3644
|
if (typeof record.key !== "string" || record.key.trim().length === 0) {
|
|
3438
3645
|
errors.push({
|
|
3439
3646
|
code: "INVALID_VARIABLE_BINDING",
|
|
@@ -3443,6 +3650,7 @@ function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
|
3443
3650
|
});
|
|
3444
3651
|
}
|
|
3445
3652
|
} else if (key === "action" || typeof record.type === "string" && record.payload !== void 0) {
|
|
3653
|
+
if (!checkActions) continue;
|
|
3446
3654
|
if (typeof record.type !== "string" || record.type.trim().length === 0) {
|
|
3447
3655
|
errors.push({
|
|
3448
3656
|
code: "INVALID_ACTION_BINDING",
|
|
@@ -3452,10 +3660,62 @@ function validatePropsBindings(propsObj, propsPath, nodeId, options, errors) {
|
|
|
3452
3660
|
});
|
|
3453
3661
|
}
|
|
3454
3662
|
} else {
|
|
3455
|
-
validatePropsBindings(record, currentPath, nodeId, options, errors);
|
|
3663
|
+
validatePropsBindings(record, currentPath, nodeId, options, errors, warnings);
|
|
3456
3664
|
}
|
|
3457
3665
|
}
|
|
3458
3666
|
}
|
|
3667
|
+
function isKnownId(ids, id) {
|
|
3668
|
+
return Array.isArray(ids) ? ids.includes(id) : ids.has(id);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
// src/io/tracking-sanitizer.ts
|
|
3672
|
+
import { LEGACY_TRACKING_SECRET_KEYS } from "@kubuild/schema";
|
|
3673
|
+
function stripTrackingSecretsInPlace(tracking, basePath = "tracking") {
|
|
3674
|
+
const removed = [];
|
|
3675
|
+
if (!tracking || typeof tracking !== "object" || Array.isArray(tracking)) return removed;
|
|
3676
|
+
const providers = tracking.providers;
|
|
3677
|
+
if (!providers || typeof providers !== "object" || Array.isArray(providers)) return removed;
|
|
3678
|
+
for (const provider of Object.keys(LEGACY_TRACKING_SECRET_KEYS)) {
|
|
3679
|
+
const cfg = providers[provider];
|
|
3680
|
+
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) continue;
|
|
3681
|
+
for (const key of LEGACY_TRACKING_SECRET_KEYS[provider]) {
|
|
3682
|
+
if (Object.prototype.hasOwnProperty.call(cfg, key)) {
|
|
3683
|
+
delete cfg[key];
|
|
3684
|
+
removed.push(`${basePath}.providers.${provider}.${key}`);
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
return removed;
|
|
3689
|
+
}
|
|
3690
|
+
function stripDocumentTrackingSecretsInPlace(doc) {
|
|
3691
|
+
const removed = [];
|
|
3692
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc)) return removed;
|
|
3693
|
+
const record = doc;
|
|
3694
|
+
removed.push(...stripTrackingSecretsInPlace(record.tracking, "tracking"));
|
|
3695
|
+
const metadata = record.metadata;
|
|
3696
|
+
if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
|
|
3697
|
+
removed.push(
|
|
3698
|
+
...stripTrackingSecretsInPlace(metadata.tracking, "metadata.tracking")
|
|
3699
|
+
);
|
|
3700
|
+
}
|
|
3701
|
+
if (Array.isArray(record.artboards)) {
|
|
3702
|
+
record.artboards.forEach((artboard, index) => {
|
|
3703
|
+
if (artboard && typeof artboard === "object") {
|
|
3704
|
+
const inner = artboard.document;
|
|
3705
|
+
for (const path of stripDocumentTrackingSecretsInPlace(inner)) {
|
|
3706
|
+
removed.push(`artboards.${index}.document.${path}`);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
return removed;
|
|
3712
|
+
}
|
|
3713
|
+
function sanitizeDocumentTracking(doc) {
|
|
3714
|
+
if (!doc || typeof doc !== "object") return { document: doc, removed: [] };
|
|
3715
|
+
const copy = JSON.parse(JSON.stringify(doc));
|
|
3716
|
+
const removed = stripDocumentTrackingSecretsInPlace(copy);
|
|
3717
|
+
return { document: copy, removed };
|
|
3718
|
+
}
|
|
3459
3719
|
|
|
3460
3720
|
// src/io/exporter.ts
|
|
3461
3721
|
function sha256Sync(data) {
|
|
@@ -3676,6 +3936,7 @@ async function exportPackage(document, options = {}) {
|
|
|
3676
3936
|
};
|
|
3677
3937
|
}
|
|
3678
3938
|
const pageDoc = JSON.parse(JSON.stringify(validation.data));
|
|
3939
|
+
stripDocumentTrackingSecretsInPlace(pageDoc);
|
|
3679
3940
|
if (options.metadata) {
|
|
3680
3941
|
pageDoc.metadata = {
|
|
3681
3942
|
...pageDoc.metadata || {
|
|
@@ -3800,7 +4061,7 @@ async function exportPackage(document, options = {}) {
|
|
|
3800
4061
|
};
|
|
3801
4062
|
const manifest = {
|
|
3802
4063
|
schema: SCHEMA_NAME4,
|
|
3803
|
-
schemaVersion: pageDoc.version ||
|
|
4064
|
+
schemaVersion: pageDoc.version || CURRENT_SCHEMA_VERSION3,
|
|
3804
4065
|
packageVersion: options.packageVersion || "1.0.0",
|
|
3805
4066
|
builderCompatibility: options.builderCompatibility || ">=0.1.0",
|
|
3806
4067
|
requiredComponents: requirements.requiredComponents,
|
|
@@ -3827,12 +4088,12 @@ var exportStoraPackage = exportPackage;
|
|
|
3827
4088
|
import { unzipSync, strFromU8 } from "fflate";
|
|
3828
4089
|
import {
|
|
3829
4090
|
ManifestSchema,
|
|
3830
|
-
CURRENT_SCHEMA_VERSION as
|
|
4091
|
+
CURRENT_SCHEMA_VERSION as CURRENT_SCHEMA_VERSION5
|
|
3831
4092
|
} from "@kubuild/schema";
|
|
3832
4093
|
|
|
3833
4094
|
// src/io/migration.ts
|
|
3834
4095
|
import {
|
|
3835
|
-
CURRENT_SCHEMA_VERSION as
|
|
4096
|
+
CURRENT_SCHEMA_VERSION as CURRENT_SCHEMA_VERSION4,
|
|
3836
4097
|
SCHEMA_NAME as SCHEMA_NAME5
|
|
3837
4098
|
} from "@kubuild/schema";
|
|
3838
4099
|
var MigrationRegistry = class {
|
|
@@ -3987,17 +4248,36 @@ defaultMigrationRegistry.register({
|
|
|
3987
4248
|
return migrated;
|
|
3988
4249
|
}
|
|
3989
4250
|
});
|
|
3990
|
-
|
|
4251
|
+
defaultMigrationRegistry.register({
|
|
4252
|
+
fromVersion: "1.0.0",
|
|
4253
|
+
toVersion: "1.1.0",
|
|
4254
|
+
description: "Remove tracking secrets and server destinations (capiAccessToken, accessToken, measurementProtocolSecret, serverRelayUrl, custom endpointUrl/headers) from the document",
|
|
4255
|
+
migrate: (rawDoc, context) => {
|
|
4256
|
+
const migrated = deepClone(rawDoc);
|
|
4257
|
+
migrated.version = "1.1.0";
|
|
4258
|
+
const removed = stripDocumentTrackingSecretsInPlace(migrated);
|
|
4259
|
+
if (removed.length > 0) {
|
|
4260
|
+
context.warn({
|
|
4261
|
+
code: "TRACKING_SECRET_REMOVED",
|
|
4262
|
+
message: "Tracking secret removed; re-link credential via credentialId (secrets are now stored by the host and resolved server-side).",
|
|
4263
|
+
step: "1.0.0->1.1.0",
|
|
4264
|
+
paths: removed
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
4267
|
+
return migrated;
|
|
4268
|
+
}
|
|
4269
|
+
});
|
|
4270
|
+
function canMigrate(sourceVersion, targetVersion = CURRENT_SCHEMA_VERSION4, registry = defaultMigrationRegistry) {
|
|
3991
4271
|
if (!sourceVersion || !targetVersion) return false;
|
|
3992
4272
|
if (sourceVersion === targetVersion) return true;
|
|
3993
4273
|
return registry.hasPath(sourceVersion, targetVersion);
|
|
3994
4274
|
}
|
|
3995
|
-
function getMigrationPath(sourceVersion, targetVersion =
|
|
4275
|
+
function getMigrationPath(sourceVersion, targetVersion = CURRENT_SCHEMA_VERSION4, registry = defaultMigrationRegistry) {
|
|
3996
4276
|
if (!sourceVersion || !targetVersion) return null;
|
|
3997
4277
|
return registry.findPath(sourceVersion, targetVersion);
|
|
3998
4278
|
}
|
|
3999
4279
|
function migrateDocument(rawDocument, options = {}) {
|
|
4000
|
-
const targetVersion = options.targetVersion ??
|
|
4280
|
+
const targetVersion = options.targetVersion ?? CURRENT_SCHEMA_VERSION4;
|
|
4001
4281
|
const dryRun = options.dryRun ?? false;
|
|
4002
4282
|
const registry = options.registry ?? defaultMigrationRegistry;
|
|
4003
4283
|
const validate = options.validate ?? true;
|
|
@@ -4025,6 +4305,14 @@ function migrateDocument(rawDocument, options = {}) {
|
|
|
4025
4305
|
const sourceVersion = typeof doc.version === "string" ? doc.version.trim() : "unknown";
|
|
4026
4306
|
if (sourceVersion === targetVersion) {
|
|
4027
4307
|
const cloned = deepClone(doc);
|
|
4308
|
+
const removedSecrets = stripDocumentTrackingSecretsInPlace(cloned);
|
|
4309
|
+
const currentWarnings = removedSecrets.length > 0 ? [
|
|
4310
|
+
{
|
|
4311
|
+
code: "TRACKING_SECRET_REMOVED",
|
|
4312
|
+
message: "Tracking secret removed; re-link credential via credentialId (secrets are stored by the host and resolved server-side).",
|
|
4313
|
+
paths: removedSecrets
|
|
4314
|
+
}
|
|
4315
|
+
] : [];
|
|
4028
4316
|
if (validate) {
|
|
4029
4317
|
const validation = validateDocument(cloned);
|
|
4030
4318
|
if (!validation.valid) {
|
|
@@ -4056,7 +4344,8 @@ function migrateDocument(rawDocument, options = {}) {
|
|
|
4056
4344
|
targetVersion,
|
|
4057
4345
|
migrationPath: [sourceVersion],
|
|
4058
4346
|
stepsApplied: 0,
|
|
4059
|
-
dryRun
|
|
4347
|
+
dryRun,
|
|
4348
|
+
...currentWarnings.length > 0 ? { warnings: currentWarnings } : {}
|
|
4060
4349
|
}
|
|
4061
4350
|
};
|
|
4062
4351
|
}
|
|
@@ -4096,6 +4385,8 @@ function migrateDocument(rawDocument, options = {}) {
|
|
|
4096
4385
|
}
|
|
4097
4386
|
let currentDoc = deepClone(doc);
|
|
4098
4387
|
let stepsApplied = 0;
|
|
4388
|
+
const warnings = [];
|
|
4389
|
+
const stepContext = { warn: (w) => warnings.push(w) };
|
|
4099
4390
|
for (let i = 0; i < path.length - 1; i++) {
|
|
4100
4391
|
const fromVer = path[i];
|
|
4101
4392
|
const toVer = path[i + 1];
|
|
@@ -4121,7 +4412,7 @@ function migrateDocument(rawDocument, options = {}) {
|
|
|
4121
4412
|
};
|
|
4122
4413
|
}
|
|
4123
4414
|
try {
|
|
4124
|
-
currentDoc = step.migrate(currentDoc);
|
|
4415
|
+
currentDoc = step.migrate(currentDoc, stepContext);
|
|
4125
4416
|
stepsApplied++;
|
|
4126
4417
|
} catch (err) {
|
|
4127
4418
|
const error = {
|
|
@@ -4177,7 +4468,8 @@ function migrateDocument(rawDocument, options = {}) {
|
|
|
4177
4468
|
targetVersion,
|
|
4178
4469
|
migrationPath: path,
|
|
4179
4470
|
stepsApplied,
|
|
4180
|
-
dryRun: false
|
|
4471
|
+
dryRun: false,
|
|
4472
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
4181
4473
|
}
|
|
4182
4474
|
};
|
|
4183
4475
|
}
|
|
@@ -4212,7 +4504,7 @@ async function preflightPackage(archiveData, options = {}) {
|
|
|
4212
4504
|
...DEFAULT_SECURITY_LIMITS,
|
|
4213
4505
|
...options.securityLimits
|
|
4214
4506
|
};
|
|
4215
|
-
const targetVersion = options.targetSchemaVersion ||
|
|
4507
|
+
const targetVersion = options.targetSchemaVersion || CURRENT_SCHEMA_VERSION5;
|
|
4216
4508
|
const migrationRegistry = options.migrationRegistry || defaultMigrationRegistry;
|
|
4217
4509
|
const diagnostics = [];
|
|
4218
4510
|
let dependencyPolicy = options.dependencyPolicy || "cancel";
|
|
@@ -4375,6 +4667,16 @@ async function preflightPackage(archiveData, options = {}) {
|
|
|
4375
4667
|
let rawPageDoc;
|
|
4376
4668
|
try {
|
|
4377
4669
|
rawPageDoc = JSON.parse(strFromU8(pageEntry));
|
|
4670
|
+
const secretScan = sanitizeDocumentTracking(rawPageDoc);
|
|
4671
|
+
if (secretScan.removed.length > 0) {
|
|
4672
|
+
diagnostics.push({
|
|
4673
|
+
code: "TRACKING_SECRET_REMOVED",
|
|
4674
|
+
severity: "warning",
|
|
4675
|
+
message: "Tracking secrets found in page.json will be removed on import; re-link credentials via credentialId.",
|
|
4676
|
+
path: "page.json",
|
|
4677
|
+
details: { paths: secretScan.removed }
|
|
4678
|
+
});
|
|
4679
|
+
}
|
|
4378
4680
|
const pageProtoCheck = containsProhibitedKeys(rawPageDoc);
|
|
4379
4681
|
if (pageProtoCheck.found) {
|
|
4380
4682
|
diagnostics.push({
|
|
@@ -4621,7 +4923,7 @@ function buildReport(valid, canImport, fields) {
|
|
|
4621
4923
|
return {
|
|
4622
4924
|
valid,
|
|
4623
4925
|
canImport,
|
|
4624
|
-
targetVersion: fields.targetVersion ||
|
|
4926
|
+
targetVersion: fields.targetVersion || CURRENT_SCHEMA_VERSION5,
|
|
4625
4927
|
requiresMigration: fields.requiresMigration || false,
|
|
4626
4928
|
missingComponents: fields.missingComponents || [],
|
|
4627
4929
|
missingCapabilities: fields.missingCapabilities || [],
|
|
@@ -4694,7 +4996,7 @@ async function importPackage(archiveData, options = {}) {
|
|
|
4694
4996
|
if (preflight.requiresMigration) {
|
|
4695
4997
|
const migrationRegistry = options.migrationRegistry || defaultMigrationRegistry;
|
|
4696
4998
|
const migrationRes = migrateDocument(pageRaw, {
|
|
4697
|
-
targetVersion: options.targetSchemaVersion ||
|
|
4999
|
+
targetVersion: options.targetSchemaVersion || CURRENT_SCHEMA_VERSION5,
|
|
4698
5000
|
registry: migrationRegistry,
|
|
4699
5001
|
validate: true
|
|
4700
5002
|
});
|
|
@@ -4716,13 +5018,24 @@ async function importPackage(archiveData, options = {}) {
|
|
|
4716
5018
|
} else {
|
|
4717
5019
|
finalDocument = pageRaw;
|
|
4718
5020
|
}
|
|
5021
|
+
const importWarnings = [];
|
|
5022
|
+
const strippedSecrets = stripDocumentTrackingSecretsInPlace(finalDocument);
|
|
5023
|
+
if (strippedSecrets.length > 0) {
|
|
5024
|
+
importWarnings.push({
|
|
5025
|
+
code: "TRACKING_SECRET_REMOVED",
|
|
5026
|
+
severity: "warning",
|
|
5027
|
+
message: "Tracking secret removed from imported document; re-link credential via credentialId.",
|
|
5028
|
+
path: "page.json",
|
|
5029
|
+
details: { paths: strippedSecrets }
|
|
5030
|
+
});
|
|
5031
|
+
}
|
|
4719
5032
|
let metadata = finalDocument.metadata || {
|
|
4720
5033
|
title: "Imported Page",
|
|
4721
5034
|
description: "",
|
|
4722
5035
|
author: "",
|
|
4723
5036
|
tags: [],
|
|
4724
5037
|
category: "general",
|
|
4725
|
-
version: finalDocument.version ||
|
|
5038
|
+
version: finalDocument.version || CURRENT_SCHEMA_VERSION5
|
|
4726
5039
|
};
|
|
4727
5040
|
if (unzipped["metadata.json"]) {
|
|
4728
5041
|
try {
|
|
@@ -4874,7 +5187,8 @@ async function importPackage(archiveData, options = {}) {
|
|
|
4874
5187
|
metadata,
|
|
4875
5188
|
extractedAssets,
|
|
4876
5189
|
renamedAssets: Object.keys(renameMap).length > 0 ? renameMap : void 0,
|
|
4877
|
-
preflight
|
|
5190
|
+
preflight,
|
|
5191
|
+
...importWarnings.length > 0 ? { warnings: importWarnings } : {}
|
|
4878
5192
|
};
|
|
4879
5193
|
}
|
|
4880
5194
|
var importStoraPackage = importPackage;
|
|
@@ -6017,6 +6331,7 @@ export {
|
|
|
6017
6331
|
createPageArtboard,
|
|
6018
6332
|
createRuntimeStore,
|
|
6019
6333
|
createTemplateRecord,
|
|
6334
|
+
createTrackingRelayHandler,
|
|
6020
6335
|
deepClone,
|
|
6021
6336
|
defaultIdGenerator,
|
|
6022
6337
|
defaultMigrationRegistry,
|
|
@@ -6083,6 +6398,7 @@ export {
|
|
|
6083
6398
|
resolveBinding,
|
|
6084
6399
|
resolveBindingValue,
|
|
6085
6400
|
resolvePropertyPath,
|
|
6401
|
+
sanitizeDocumentTracking,
|
|
6086
6402
|
sanitizeFilename,
|
|
6087
6403
|
sanitizeHtml,
|
|
6088
6404
|
sanitizeUrl,
|
|
@@ -6093,6 +6409,8 @@ export {
|
|
|
6093
6409
|
sendTikTokEventsApi,
|
|
6094
6410
|
setActiveArtboard,
|
|
6095
6411
|
sha256Sync,
|
|
6412
|
+
stripDocumentTrackingSecretsInPlace,
|
|
6413
|
+
stripTrackingSecretsInPlace,
|
|
6096
6414
|
ungroupNodeFrame,
|
|
6097
6415
|
updateActions,
|
|
6098
6416
|
updateAnimation,
|