saasco-sdk 0.2.5 → 0.2.6
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/README.md +31 -0
- package/dist/index.cjs +454 -305
- package/dist/index.d.cts +12 -8
- package/dist/index.d.ts +12 -8
- package/dist/index.js +454 -305
- package/dist/support.cjs +199 -192
- package/dist/support.js +127 -120
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,7 +38,187 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
var import_psl = require("psl");
|
|
39
39
|
|
|
40
40
|
// package.json
|
|
41
|
-
var version = "0.2.
|
|
41
|
+
var version = "0.2.6";
|
|
42
|
+
|
|
43
|
+
// src/lib/deliverOnce.ts
|
|
44
|
+
var sent = /* @__PURE__ */ new Set();
|
|
45
|
+
var pending = /* @__PURE__ */ new Map();
|
|
46
|
+
function deliverOnce(key, send) {
|
|
47
|
+
if (!key || typeof window === "undefined") {
|
|
48
|
+
return Promise.resolve().then(send);
|
|
49
|
+
}
|
|
50
|
+
if (sent.has(key)) {
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
if (window.sessionStorage.getItem(key)) {
|
|
55
|
+
return Promise.resolve();
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
const existing = pending.get(key);
|
|
60
|
+
if (existing) {
|
|
61
|
+
return existing;
|
|
62
|
+
}
|
|
63
|
+
const task = Promise.resolve().then(send).then(() => {
|
|
64
|
+
sent.add(key);
|
|
65
|
+
try {
|
|
66
|
+
window.sessionStorage.setItem(key, "true");
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}).finally(() => pending.delete(key));
|
|
70
|
+
pending.set(key, task);
|
|
71
|
+
return task;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ../shared/src/lib/analyticsIngestError.ts
|
|
75
|
+
var import_zod = require("zod");
|
|
76
|
+
var IDENTIFY_INGEST_ERROR_SOURCE = "saasco-identify";
|
|
77
|
+
var ANALYTICS_INGEST_ERROR_SOURCE = "saasco-analytics";
|
|
78
|
+
var AnalyticsIngestErrorCodeSchema = import_zod.z.enum([
|
|
79
|
+
"CREDENTIAL_INVALID",
|
|
80
|
+
"RESOURCE_FORBIDDEN",
|
|
81
|
+
"RESOURCE_UNSPECIFIED",
|
|
82
|
+
"ENVIRONMENT_UNREACHABLE",
|
|
83
|
+
"INGEST_FAILED"
|
|
84
|
+
]);
|
|
85
|
+
var AnalyticsIngestSurfaceSchema = import_zod.z.enum(["identify", "events"]);
|
|
86
|
+
var AnalyticsIngestErrorSchema = import_zod.z.object({
|
|
87
|
+
affected: import_zod.z.string(),
|
|
88
|
+
code: AnalyticsIngestErrorCodeSchema,
|
|
89
|
+
message: import_zod.z.string(),
|
|
90
|
+
projectId: import_zod.z.string().nullable(),
|
|
91
|
+
recovery: import_zod.z.string(),
|
|
92
|
+
resource: import_zod.z.string().nullable(),
|
|
93
|
+
surface: AnalyticsIngestSurfaceSchema
|
|
94
|
+
});
|
|
95
|
+
var IDENTIFY_AFFECTED = "Saasco identification only: CRM contact properties and identity stitching. Page views, charts, and the host application UI are not this failure.";
|
|
96
|
+
var ANALYTICS_EVENT_AFFECTED = "Saasco event tracking only. The host application UI is not this failure.";
|
|
97
|
+
function analyticsIngestError({
|
|
98
|
+
code,
|
|
99
|
+
message,
|
|
100
|
+
projectId,
|
|
101
|
+
resource,
|
|
102
|
+
surface
|
|
103
|
+
}) {
|
|
104
|
+
const copy = ingestCopy({ code, resource, surface });
|
|
105
|
+
return {
|
|
106
|
+
affected: surface === "identify" ? IDENTIFY_AFFECTED : ANALYTICS_EVENT_AFFECTED,
|
|
107
|
+
code,
|
|
108
|
+
message: message ?? copy.message,
|
|
109
|
+
projectId,
|
|
110
|
+
recovery: copy.recovery,
|
|
111
|
+
resource,
|
|
112
|
+
surface
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function ingestCopy({
|
|
116
|
+
code,
|
|
117
|
+
resource,
|
|
118
|
+
surface
|
|
119
|
+
}) {
|
|
120
|
+
const named = resource ? `\`${resource}\`` : "the requested analytics resource";
|
|
121
|
+
const didNotComplete = surface === "identify" ? "Identification did not complete." : "Event tracking did not complete.";
|
|
122
|
+
switch (code) {
|
|
123
|
+
case "CREDENTIAL_INVALID": {
|
|
124
|
+
return {
|
|
125
|
+
message: "Saasco analytics credentials are invalid or missing. This is not an application login or permissions problem.",
|
|
126
|
+
recovery: "Check TINYBIRD_ANALYTICS_TOKEN on the Saasco ingest worker. Do not change host-app auth. Charts and UI styling are unrelated."
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
case "RESOURCE_FORBIDDEN": {
|
|
130
|
+
return {
|
|
131
|
+
message: `Saasco analytics is not allowed to use ${named}. ${didNotComplete}`,
|
|
132
|
+
recovery: surface === "identify" ? `Grant the ingest worker access to ${named} (PIPES:READ or DATASOURCES:APPEND). Page tracking may still work.` : `Grant the ingest worker access to ${named} (PIPES:READ or DATASOURCES:APPEND).`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
case "RESOURCE_UNSPECIFIED": {
|
|
136
|
+
return {
|
|
137
|
+
message: `Saasco analytics was denied access without a named pipe or datasource. ${didNotComplete}`,
|
|
138
|
+
recovery: "This is a Saasco ingest configuration issue: the worker could not name the Tinybird resource it tried to use. Host-app login is unrelated."
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
case "ENVIRONMENT_UNREACHABLE": {
|
|
142
|
+
return {
|
|
143
|
+
message: surface === "identify" ? "The Saasco ingest host could not be reached, so identification was not sent." : "The Saasco ingest host could not be reached, so this event was not sent.",
|
|
144
|
+
recovery: "If `proxy` points at localhost, start the analytics worker (`pnpm worker:dev`) or use https://t.saasco.com/. This does not mean the host app is broken."
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
default: {
|
|
148
|
+
return {
|
|
149
|
+
message: surface === "identify" ? "Saasco identification could not be completed." : "Saasco event tracking could not be completed.",
|
|
150
|
+
recovery: "Retry. If it keeps failing, this is a Saasco analytics ingest issue, not host-app login or chart configuration."
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function ingestErrorSource(surface) {
|
|
156
|
+
return surface === "identify" ? IDENTIFY_INGEST_ERROR_SOURCE : ANALYTICS_INGEST_ERROR_SOURCE;
|
|
157
|
+
}
|
|
158
|
+
function redactSecrets(text) {
|
|
159
|
+
return text.replaceAll(/Bearer\s+\S+/giu, "Bearer [redacted]").replaceAll(/\bp\.[A-Za-z0-9._-]+/gu, "[redacted]").replaceAll(/token=[^&\s]+/giu, "token=[redacted]");
|
|
160
|
+
}
|
|
161
|
+
function isUnsafeIngestMessage(text) {
|
|
162
|
+
return /Bearer \[redacted\]|token=\[redacted\]/iu.test(text) || /token you have provided|doesn't have access to this resource|not enough permissions|invalid token/iu.test(
|
|
163
|
+
text
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/lib/formatAnalyticsRequestFailure.ts
|
|
168
|
+
function formatAnalyticsRequestFailure(input) {
|
|
169
|
+
const surface = input.path === "identify" ? "identify" : "events";
|
|
170
|
+
const projectId = input.projectId ?? null;
|
|
171
|
+
if (input.reason === "http") {
|
|
172
|
+
const parsed = AnalyticsIngestErrorSchema.safeParse(input.body);
|
|
173
|
+
if (parsed.success) {
|
|
174
|
+
return parsed.data;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (input.reason === "unreachable") {
|
|
178
|
+
return analyticsIngestError({
|
|
179
|
+
code: "ENVIRONMENT_UNREACHABLE",
|
|
180
|
+
projectId,
|
|
181
|
+
resource: null,
|
|
182
|
+
surface
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const legacy = input.body && typeof input.body === "object" && !Array.isArray(input.body) && "message" in input.body && typeof input.body.message === "string" ? input.body.message : "";
|
|
186
|
+
const safeMessage = redactSecrets(legacy).trim();
|
|
187
|
+
return analyticsIngestError({
|
|
188
|
+
code: "INGEST_FAILED",
|
|
189
|
+
message: safeMessage && !isUnsafeIngestMessage(safeMessage) ? safeMessage : void 0,
|
|
190
|
+
projectId,
|
|
191
|
+
resource: null,
|
|
192
|
+
surface
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function reportIngestFailure({
|
|
196
|
+
failure,
|
|
197
|
+
logger,
|
|
198
|
+
path,
|
|
199
|
+
seen
|
|
200
|
+
}) {
|
|
201
|
+
const key = `${path}:${failure.code}:${failure.resource ?? ""}`;
|
|
202
|
+
if (!seen.has(key)) {
|
|
203
|
+
seen.add(key);
|
|
204
|
+
logger.warn(...analyticsFailureLogLines(failure, path));
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
message: failure.message
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function analyticsFailureLogLines(failure, path) {
|
|
212
|
+
const lines = [
|
|
213
|
+
`${ingestErrorSource(failure.surface)} ${path} failed (${failure.code})`,
|
|
214
|
+
failure.message,
|
|
215
|
+
failure.resource ? `Resource: ${failure.resource}` : null,
|
|
216
|
+
failure.projectId ? `Project: ${failure.projectId}` : null,
|
|
217
|
+
`Affected: ${failure.affected}`,
|
|
218
|
+
`Recovery: ${failure.recovery}`
|
|
219
|
+
];
|
|
220
|
+
return lines.filter((line) => line !== null);
|
|
221
|
+
}
|
|
42
222
|
|
|
43
223
|
// src/lib/timezones.ts
|
|
44
224
|
var timezones = {
|
|
@@ -518,12 +698,10 @@ var AnalyticsLogger = class {
|
|
|
518
698
|
);
|
|
519
699
|
}
|
|
520
700
|
/**
|
|
521
|
-
*
|
|
701
|
+
* Warnings always print. Ingest failures use this so they stay visible when
|
|
702
|
+
* the default log level is ERROR, without `console.error` (Next.js overlays it).
|
|
522
703
|
*/
|
|
523
704
|
warn(...args) {
|
|
524
|
-
if (this.config.level < 1 /* WARN */) {
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
705
|
const icon = "\u25CD";
|
|
528
706
|
const message = `${icon} ${this.config.label}`;
|
|
529
707
|
console.warn(
|
|
@@ -669,6 +847,50 @@ function resolveAdParams(params) {
|
|
|
669
847
|
|
|
670
848
|
// src/lib/integrations/facebook-pixel.ts
|
|
671
849
|
var import_js_sha256 = require("js-sha256");
|
|
850
|
+
|
|
851
|
+
// src/lib/integrations/loadPixelScript.ts
|
|
852
|
+
var loads = /* @__PURE__ */ new Map();
|
|
853
|
+
function loadPixelScript(src) {
|
|
854
|
+
const existingLoad = loads.get(src);
|
|
855
|
+
if (existingLoad) {
|
|
856
|
+
return existingLoad;
|
|
857
|
+
}
|
|
858
|
+
const existingScript = Array.from(document.scripts).find(
|
|
859
|
+
(script2) => script2.src === src
|
|
860
|
+
);
|
|
861
|
+
const script = existingScript ?? document.createElement("script");
|
|
862
|
+
const task = new Promise((resolve, reject) => {
|
|
863
|
+
const cleanup = () => {
|
|
864
|
+
clearTimeout(timeout);
|
|
865
|
+
script.removeEventListener("load", loaded);
|
|
866
|
+
script.removeEventListener("error", failed);
|
|
867
|
+
};
|
|
868
|
+
const loaded = () => {
|
|
869
|
+
cleanup();
|
|
870
|
+
resolve();
|
|
871
|
+
};
|
|
872
|
+
const failed = () => {
|
|
873
|
+
cleanup();
|
|
874
|
+
script.remove();
|
|
875
|
+
reject(new Error(`Pixel script unavailable: ${src}`));
|
|
876
|
+
};
|
|
877
|
+
const timeout = setTimeout(failed, 1e4);
|
|
878
|
+
script.addEventListener("load", loaded);
|
|
879
|
+
script.addEventListener("error", failed);
|
|
880
|
+
if (!existingScript) {
|
|
881
|
+
script.async = true;
|
|
882
|
+
script.src = src;
|
|
883
|
+
document.head.append(script);
|
|
884
|
+
}
|
|
885
|
+
}).catch((error) => {
|
|
886
|
+
loads.delete(src);
|
|
887
|
+
throw error;
|
|
888
|
+
});
|
|
889
|
+
loads.set(src, task);
|
|
890
|
+
return task;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// src/lib/integrations/facebook-pixel.ts
|
|
672
894
|
var isBrowser2 = typeof window !== "undefined";
|
|
673
895
|
var isServer2 = !isBrowser2;
|
|
674
896
|
var standardFacebookEvents = [
|
|
@@ -710,70 +932,32 @@ function createFacebookPixelIntegration(config, debug) {
|
|
|
710
932
|
return;
|
|
711
933
|
}
|
|
712
934
|
logger.info("Initializing Facebook Pixel", { pixelId: config.pixelId });
|
|
713
|
-
if (window.fbq
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
try {
|
|
720
|
-
(function init(f, b, e, v, n, t, s) {
|
|
721
|
-
if (f.fbq) {
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
n = f.fbq = function fbq2() {
|
|
725
|
-
n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
|
|
726
|
-
};
|
|
727
|
-
if (!f._fbq) {
|
|
728
|
-
f._fbq = n;
|
|
729
|
-
}
|
|
730
|
-
n.push = n;
|
|
731
|
-
n.loaded = true;
|
|
732
|
-
n.version = "2.0";
|
|
733
|
-
n.queue = [];
|
|
734
|
-
t = b.createElement(e);
|
|
735
|
-
t.async = true;
|
|
736
|
-
t.src = v;
|
|
737
|
-
t.addEventListener("load", () => {
|
|
738
|
-
isPixelReady = true;
|
|
739
|
-
logger.info("Facebook Pixel script loaded successfully");
|
|
740
|
-
resolve();
|
|
741
|
-
});
|
|
742
|
-
t.addEventListener("error", () => {
|
|
743
|
-
logger.error("Failed to load Facebook Pixel script");
|
|
744
|
-
reject(new Error("Failed to load Facebook Pixel script"));
|
|
745
|
-
});
|
|
746
|
-
s = b.getElementsByTagName(e)[0];
|
|
747
|
-
s.parentNode.insertBefore(t, s);
|
|
748
|
-
})(
|
|
749
|
-
window,
|
|
750
|
-
document,
|
|
751
|
-
"script",
|
|
752
|
-
"https://connect.facebook.net/en_US/fbevents.js"
|
|
753
|
-
);
|
|
754
|
-
const { fbq } = window;
|
|
755
|
-
if (!fbq) {
|
|
756
|
-
reject(new Error("Facebook Pixel failed to initialize"));
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
fbq.disablePushState = true;
|
|
760
|
-
fbq.allowDuplicatePageViews = true;
|
|
761
|
-
if (config.automaticConfiguration === false) {
|
|
762
|
-
logger.debug("Disabling automatic configuration");
|
|
763
|
-
fbq("set", "autoConfig", false, config.pixelId);
|
|
935
|
+
if (!window.fbq) {
|
|
936
|
+
const fbq2 = (...args) => {
|
|
937
|
+
if (fbq2.callMethod) {
|
|
938
|
+
fbq2.callMethod(...args);
|
|
939
|
+
} else {
|
|
940
|
+
fbq2.queue.push(args);
|
|
764
941
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
942
|
+
};
|
|
943
|
+
fbq2.queue = [];
|
|
944
|
+
fbq2.push = fbq2;
|
|
945
|
+
fbq2.loaded = true;
|
|
946
|
+
fbq2.version = "2.0";
|
|
947
|
+
window.fbq = fbq2;
|
|
948
|
+
window._fbq = fbq2;
|
|
949
|
+
}
|
|
950
|
+
const { fbq } = window;
|
|
951
|
+
fbq.disablePushState = true;
|
|
952
|
+
fbq.allowDuplicatePageViews = true;
|
|
953
|
+
if (config.automaticConfiguration === false) {
|
|
954
|
+
fbq("set", "autoConfig", false, config.pixelId);
|
|
955
|
+
}
|
|
956
|
+
fbq("init", config.pixelId);
|
|
957
|
+
if (!fbq.callMethod) {
|
|
958
|
+
await loadPixelScript("https://connect.facebook.net/en_US/fbevents.js");
|
|
959
|
+
}
|
|
960
|
+
isPixelReady = true;
|
|
777
961
|
},
|
|
778
962
|
track: (eventName, properties, _context) => {
|
|
779
963
|
const { fbq } = window;
|
|
@@ -781,9 +965,11 @@ function createFacebookPixelIntegration(config, debug) {
|
|
|
781
965
|
logger.warn("Facebook Pixel not ready, skipping track event", {
|
|
782
966
|
eventName
|
|
783
967
|
});
|
|
784
|
-
|
|
968
|
+
throw new Error("Facebook Pixel not ready");
|
|
785
969
|
}
|
|
786
970
|
const fbEventName = getFacebookEventName(eventName, config.eventMapping);
|
|
971
|
+
const eventId = properties?.["event_id"];
|
|
972
|
+
const eventOptions = typeof eventId === "string" && eventId.trim().length > 0 ? { eventID: eventId } : void 0;
|
|
787
973
|
const eventsWithParams = ["Purchase", "StartTrial", "Subscribe"];
|
|
788
974
|
const isStandardEvent = standardFacebookEvents.includes(
|
|
789
975
|
fbEventName
|
|
@@ -811,10 +997,18 @@ function createFacebookPixelIntegration(config, debug) {
|
|
|
811
997
|
event: fbEventName,
|
|
812
998
|
params: fbParams
|
|
813
999
|
});
|
|
814
|
-
|
|
1000
|
+
if (eventOptions) {
|
|
1001
|
+
fbq(trackType, fbEventName, fbParams, eventOptions);
|
|
1002
|
+
} else {
|
|
1003
|
+
fbq(trackType, fbEventName, fbParams);
|
|
1004
|
+
}
|
|
815
1005
|
} else {
|
|
816
1006
|
logger.info("Tracking Facebook Pixel event", { event: fbEventName });
|
|
817
|
-
|
|
1007
|
+
if (eventOptions) {
|
|
1008
|
+
fbq(trackType, fbEventName, {}, eventOptions);
|
|
1009
|
+
} else {
|
|
1010
|
+
fbq(trackType, fbEventName);
|
|
1011
|
+
}
|
|
818
1012
|
}
|
|
819
1013
|
},
|
|
820
1014
|
identify: (userId, properties, _context) => {
|
|
@@ -1168,12 +1362,12 @@ var IntegrationManager = class {
|
|
|
1168
1362
|
globalQueue = [];
|
|
1169
1363
|
config;
|
|
1170
1364
|
logger;
|
|
1171
|
-
initTime;
|
|
1172
1365
|
currentEnvironment;
|
|
1173
1366
|
flushTimer;
|
|
1174
1367
|
unloadHandler;
|
|
1175
1368
|
constructor(config = {}) {
|
|
1176
1369
|
this.config = {
|
|
1370
|
+
deduplicationNamespace: config.deduplicationNamespace ?? "default",
|
|
1177
1371
|
flushInterval: config.flushInterval ?? 5e3,
|
|
1178
1372
|
loggerLevel: config.loggerLevel ?? 0 /* ERROR */,
|
|
1179
1373
|
maxIntegrationWaitTime: config.maxIntegrationWaitTime ?? 1e4,
|
|
@@ -1183,7 +1377,6 @@ var IntegrationManager = class {
|
|
|
1183
1377
|
label: "Saasco Integrations Debug",
|
|
1184
1378
|
level: this.config.loggerLevel
|
|
1185
1379
|
});
|
|
1186
|
-
this.initTime = Date.now();
|
|
1187
1380
|
this.currentEnvironment = typeof window === "undefined" ? "server" : "client";
|
|
1188
1381
|
this.setupPeriodicFlushing();
|
|
1189
1382
|
this.setupUnloadHandler();
|
|
@@ -1260,6 +1453,8 @@ var IntegrationManager = class {
|
|
|
1260
1453
|
*/
|
|
1261
1454
|
send(partial) {
|
|
1262
1455
|
const envelope = {
|
|
1456
|
+
delivered: /* @__PURE__ */ new Set(),
|
|
1457
|
+
pending: /* @__PURE__ */ new Set(),
|
|
1263
1458
|
context: { ...this.context },
|
|
1264
1459
|
id: uuid(),
|
|
1265
1460
|
name: partial.name,
|
|
@@ -1267,65 +1462,55 @@ var IntegrationManager = class {
|
|
|
1267
1462
|
timestamp: Date.now(),
|
|
1268
1463
|
type: partial.type
|
|
1269
1464
|
};
|
|
1270
|
-
if (
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
this.logger.warn("Queue full \u2192 dropped oldest");
|
|
1274
|
-
}
|
|
1275
|
-
this.globalQueue.push(envelope);
|
|
1276
|
-
this.logger.debug(`Queued (${this.globalQueue.length})`, envelope);
|
|
1277
|
-
return;
|
|
1465
|
+
if (this.globalQueue.length >= this.config.maxQueueSize) {
|
|
1466
|
+
this.globalQueue.shift();
|
|
1467
|
+
this.logger.warn("Queue full \u2192 dropped oldest");
|
|
1278
1468
|
}
|
|
1279
|
-
this.
|
|
1469
|
+
this.globalQueue.push(envelope);
|
|
1470
|
+
this.flush();
|
|
1280
1471
|
}
|
|
1281
|
-
async deliver(evt) {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
await integration.identify(
|
|
1300
|
-
evt.context.distinctId,
|
|
1301
|
-
evt.properties,
|
|
1302
|
-
evt.context
|
|
1303
|
-
);
|
|
1304
|
-
}
|
|
1305
|
-
} catch (error) {
|
|
1306
|
-
this.logger.error(
|
|
1307
|
-
`deliver error in ${integration.name} (${evt.type})`,
|
|
1308
|
-
error
|
|
1472
|
+
async deliver(evt, state) {
|
|
1473
|
+
const { integration } = state;
|
|
1474
|
+
evt.pending.add(integration.name);
|
|
1475
|
+
try {
|
|
1476
|
+
if (evt.type === "track" && integration.track && evt.name) {
|
|
1477
|
+
const eventId = evt.properties?.["event_id"];
|
|
1478
|
+
const key = typeof eventId === "string" && eventId.trim() ? `saasco:${this.config.deduplicationNamespace}:${integration.name}:${evt.name}:${eventId}` : void 0;
|
|
1479
|
+
const { track } = integration;
|
|
1480
|
+
const { name } = evt;
|
|
1481
|
+
await deliverOnce(
|
|
1482
|
+
key,
|
|
1483
|
+
() => track.call(integration, name, evt.properties, evt.context)
|
|
1484
|
+
);
|
|
1485
|
+
} else if (evt.type === "identify" && integration.identify) {
|
|
1486
|
+
await integration.identify(
|
|
1487
|
+
evt.context.distinctId,
|
|
1488
|
+
evt.properties,
|
|
1489
|
+
evt.context
|
|
1309
1490
|
);
|
|
1310
1491
|
}
|
|
1492
|
+
evt.delivered.add(integration.name);
|
|
1493
|
+
} catch (error) {
|
|
1494
|
+
this.logger.error(
|
|
1495
|
+
`deliver error in ${integration.name} (${evt.type})`,
|
|
1496
|
+
error
|
|
1497
|
+
);
|
|
1498
|
+
} finally {
|
|
1499
|
+
evt.pending.delete(integration.name);
|
|
1311
1500
|
}
|
|
1312
1501
|
}
|
|
1313
|
-
/**
|
|
1314
|
-
*
|
|
1315
|
-
*/
|
|
1502
|
+
/** Each ready destination drains its own copy; a slow/blocked pixel cannot
|
|
1503
|
+
* discard another pixel's queued events or hold up the ready destinations. */
|
|
1316
1504
|
flush() {
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
for (const evt of toSend) {
|
|
1327
|
-
this.deliver(evt);
|
|
1328
|
-
}
|
|
1505
|
+
this.globalQueue = this.globalQueue.filter((evt) => {
|
|
1506
|
+
for (const state of this.integrations.values()) {
|
|
1507
|
+
const { name } = state.integration;
|
|
1508
|
+
if (state.status === "ready" && !evt.delivered.has(name) && !evt.pending.has(name)) {
|
|
1509
|
+
void this.deliver(evt, state);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
return evt.delivered.size < this.integrations.size && Date.now() - evt.timestamp < this.config.maxIntegrationWaitTime;
|
|
1513
|
+
});
|
|
1329
1514
|
}
|
|
1330
1515
|
readyCount() {
|
|
1331
1516
|
let n = 0;
|
|
@@ -1336,18 +1521,6 @@ var IntegrationManager = class {
|
|
|
1336
1521
|
}
|
|
1337
1522
|
return n;
|
|
1338
1523
|
}
|
|
1339
|
-
isReady() {
|
|
1340
|
-
const timeElapsed = Date.now() - this.initTime;
|
|
1341
|
-
if (this.readyCount() < this.integrations.size && timeElapsed < this.config.maxIntegrationWaitTime) {
|
|
1342
|
-
return false;
|
|
1343
|
-
}
|
|
1344
|
-
if (this.readyCount() < this.integrations.size) {
|
|
1345
|
-
this.logger.info(
|
|
1346
|
-
`proceeding with ${this.readyCount()}/${this.integrations.size} integrations ready after ${timeElapsed}ms wait`
|
|
1347
|
-
);
|
|
1348
|
-
}
|
|
1349
|
-
return true;
|
|
1350
|
-
}
|
|
1351
1524
|
/**
|
|
1352
1525
|
* Setup periodic flushing if enabled
|
|
1353
1526
|
*/
|
|
@@ -1431,50 +1604,20 @@ function createPinterestTagIntegration(config, debug) {
|
|
|
1431
1604
|
return;
|
|
1432
1605
|
}
|
|
1433
1606
|
logger.info("Initializing Pinterest Tag", { tagId: config.tagId });
|
|
1434
|
-
if (window.pintrk
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1607
|
+
if (!window.pintrk) {
|
|
1608
|
+
const pintrk = (...args) => pintrk.queue.push(args);
|
|
1609
|
+
pintrk.queue = [];
|
|
1610
|
+
pintrk.version = "3.0";
|
|
1611
|
+
window.pintrk = pintrk;
|
|
1438
1612
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
window.pintrk = function pintrk(...args) {
|
|
1444
|
-
window.pintrk.queue.push(args);
|
|
1445
|
-
};
|
|
1446
|
-
const n = window.pintrk;
|
|
1447
|
-
n.queue = [];
|
|
1448
|
-
n.version = "3.0";
|
|
1449
|
-
const t = document.createElement("script");
|
|
1450
|
-
t.async = true;
|
|
1451
|
-
t.src = e;
|
|
1452
|
-
t.addEventListener("load", () => {
|
|
1453
|
-
window.pintrk("load", config.tagId);
|
|
1454
|
-
window.pintrk("page");
|
|
1455
|
-
setTimeout(() => {
|
|
1456
|
-
logger.debug("Pinterest Tag initialized");
|
|
1457
|
-
isTagReady = true;
|
|
1458
|
-
resolve();
|
|
1459
|
-
}, 500);
|
|
1460
|
-
});
|
|
1461
|
-
t.addEventListener("error", () => {
|
|
1462
|
-
logger.error("Failed to load Pinterest Tag script");
|
|
1463
|
-
reject(new Error("Failed to load Pinterest Tag script"));
|
|
1464
|
-
});
|
|
1465
|
-
const r = document.getElementsByTagName("script")[0];
|
|
1466
|
-
r.parentNode.insertBefore(t, r);
|
|
1467
|
-
}
|
|
1468
|
-
})("https://s.pinimg.com/ct/core.js");
|
|
1469
|
-
} catch (error) {
|
|
1470
|
-
logger.error("Failed to initialize Pinterest Tag", error);
|
|
1471
|
-
reject(error);
|
|
1472
|
-
}
|
|
1473
|
-
});
|
|
1613
|
+
await loadPixelScript("https://s.pinimg.com/ct/core.js");
|
|
1614
|
+
window.pintrk("load", config.tagId);
|
|
1615
|
+
window.pintrk("page");
|
|
1616
|
+
isTagReady = true;
|
|
1474
1617
|
},
|
|
1475
1618
|
track: (eventName, properties) => {
|
|
1476
1619
|
if (!isTagReady || !window.pintrk) {
|
|
1477
|
-
|
|
1620
|
+
throw new Error("Pinterest Tag not ready");
|
|
1478
1621
|
}
|
|
1479
1622
|
const pinterestEventName = getPinterestEventName(
|
|
1480
1623
|
eventName,
|
|
@@ -1603,8 +1746,8 @@ function createTikTokPixelIntegration(config, debug) {
|
|
|
1603
1746
|
return;
|
|
1604
1747
|
}
|
|
1605
1748
|
logger.info("Initializing TikTok Pixel", { pixelId: config.pixelId });
|
|
1606
|
-
if (window.ttq) {
|
|
1607
|
-
|
|
1749
|
+
if (window.ttq?.ready) {
|
|
1750
|
+
await new Promise((resolve) => window.ttq.ready(resolve));
|
|
1608
1751
|
isPixelReady = true;
|
|
1609
1752
|
return;
|
|
1610
1753
|
}
|
|
@@ -1656,28 +1799,15 @@ function createTikTokPixelIntegration(config, debug) {
|
|
|
1656
1799
|
ttq._t[e] = Date.now();
|
|
1657
1800
|
ttq._o ||= {};
|
|
1658
1801
|
ttq._o[e] = n || {};
|
|
1659
|
-
|
|
1660
|
-
script.type = "text/javascript";
|
|
1661
|
-
script.async = true;
|
|
1662
|
-
script.src = `${r}?sdkid=${e}&lib=${t}`;
|
|
1663
|
-
script.addEventListener("load", () => {
|
|
1802
|
+
loadPixelScript(`${r}?sdkid=${e}&lib=${t}`).then(() => {
|
|
1664
1803
|
isPixelReady = true;
|
|
1665
1804
|
resolve();
|
|
1666
|
-
});
|
|
1667
|
-
script.addEventListener("error", () => {
|
|
1668
|
-
reject(new Error("Failed to load TikTok Pixel script"));
|
|
1669
|
-
});
|
|
1670
|
-
const firstScript = document.getElementsByTagName("script")[0];
|
|
1671
|
-
firstScript.parentNode.insertBefore(script, firstScript);
|
|
1805
|
+
}).catch(reject);
|
|
1672
1806
|
};
|
|
1673
1807
|
ttq.load(
|
|
1674
1808
|
config.pixelId,
|
|
1675
1809
|
config.testMode ? { test_mode: true } : void 0
|
|
1676
1810
|
);
|
|
1677
|
-
if (window.ttq && typeof window.ttq === "function") {
|
|
1678
|
-
isPixelReady = true;
|
|
1679
|
-
resolve();
|
|
1680
|
-
}
|
|
1681
1811
|
})(window, document, "ttq");
|
|
1682
1812
|
} catch (error) {
|
|
1683
1813
|
reject(error);
|
|
@@ -1686,8 +1816,8 @@ function createTikTokPixelIntegration(config, debug) {
|
|
|
1686
1816
|
},
|
|
1687
1817
|
track: (eventName, properties, _context) => {
|
|
1688
1818
|
const { ttq } = window;
|
|
1689
|
-
if (!isPixelReady || !ttq) {
|
|
1690
|
-
|
|
1819
|
+
if (!isPixelReady || !ttq?.track) {
|
|
1820
|
+
throw new Error("TikTok Pixel not ready");
|
|
1691
1821
|
}
|
|
1692
1822
|
const ttEventName = getTikTokEventName(eventName, config.eventMapping);
|
|
1693
1823
|
if (ttEventName === "PageView") {
|
|
@@ -1695,7 +1825,10 @@ function createTikTokPixelIntegration(config, debug) {
|
|
|
1695
1825
|
return;
|
|
1696
1826
|
}
|
|
1697
1827
|
const ttParams = mapTikTokEventParameters(ttEventName, properties);
|
|
1698
|
-
|
|
1828
|
+
const eventId = properties?.["event_id"];
|
|
1829
|
+
if (typeof eventId === "string" && eventId.trim().length > 0) {
|
|
1830
|
+
ttq.track?.(ttEventName, ttParams ?? {}, { event_id: eventId });
|
|
1831
|
+
} else if (ttParams && Object.keys(ttParams).length > 0) {
|
|
1699
1832
|
ttq.track?.(ttEventName, ttParams);
|
|
1700
1833
|
} else {
|
|
1701
1834
|
ttq.track?.(ttEventName);
|
|
@@ -2215,6 +2348,15 @@ function migrateFromLocalStorage() {
|
|
|
2215
2348
|
if (isServer5) {
|
|
2216
2349
|
return;
|
|
2217
2350
|
}
|
|
2351
|
+
let storage;
|
|
2352
|
+
try {
|
|
2353
|
+
storage = globalThis.localStorage ?? null;
|
|
2354
|
+
} catch {
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
if (!storage) {
|
|
2358
|
+
return;
|
|
2359
|
+
}
|
|
2218
2360
|
const keysToMigrate = [
|
|
2219
2361
|
`${PREF}-session-id`,
|
|
2220
2362
|
`${PREF}-anonymous-id`,
|
|
@@ -2224,20 +2366,23 @@ function migrateFromLocalStorage() {
|
|
|
2224
2366
|
];
|
|
2225
2367
|
for (const key of keysToMigrate) {
|
|
2226
2368
|
try {
|
|
2227
|
-
const value =
|
|
2369
|
+
const value = storage.getItem(key);
|
|
2228
2370
|
if (value) {
|
|
2229
2371
|
const item = JSON.parse(value);
|
|
2230
2372
|
const now = Date.now();
|
|
2231
2373
|
if (item.expiry > now) {
|
|
2232
2374
|
const remainingTtl = item.expiry - now;
|
|
2233
2375
|
setCookie(key, JSON.stringify(item.value), remainingTtl);
|
|
2234
|
-
|
|
2376
|
+
storage.removeItem(key);
|
|
2235
2377
|
} else {
|
|
2236
|
-
|
|
2378
|
+
storage.removeItem(key);
|
|
2237
2379
|
}
|
|
2238
2380
|
}
|
|
2239
2381
|
} catch {
|
|
2240
|
-
|
|
2382
|
+
try {
|
|
2383
|
+
storage.removeItem(key);
|
|
2384
|
+
} catch {
|
|
2385
|
+
}
|
|
2241
2386
|
}
|
|
2242
2387
|
}
|
|
2243
2388
|
}
|
|
@@ -2468,7 +2613,8 @@ var Saasco = class {
|
|
|
2468
2613
|
};
|
|
2469
2614
|
this.integrationManager = new IntegrationManager({
|
|
2470
2615
|
loggerLevel,
|
|
2471
|
-
maxQueueSize: 1e3
|
|
2616
|
+
maxQueueSize: 1e3,
|
|
2617
|
+
deduplicationNamespace: this.config.projectId
|
|
2472
2618
|
});
|
|
2473
2619
|
this.integrationManager.setContext({});
|
|
2474
2620
|
void (async () => {
|
|
@@ -2491,6 +2637,7 @@ var Saasco = class {
|
|
|
2491
2637
|
// here so an `identify()` that fires before the widget bundle finishes
|
|
2492
2638
|
// loading is replayed once it does.
|
|
2493
2639
|
lastSupportIdentity = null;
|
|
2640
|
+
ingestFailureKeys = /* @__PURE__ */ new Set();
|
|
2494
2641
|
init() {
|
|
2495
2642
|
if (this.isInitialized) {
|
|
2496
2643
|
this.logger.info(
|
|
@@ -2542,48 +2689,52 @@ var Saasco = class {
|
|
|
2542
2689
|
);
|
|
2543
2690
|
return;
|
|
2544
2691
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2692
|
+
await Promise.all(
|
|
2693
|
+
this.config.integrations.map(async (integrationConfig) => {
|
|
2694
|
+
try {
|
|
2695
|
+
if (integrationConfig.type === "facebook-pixel") {
|
|
2696
|
+
this.logger.info(
|
|
2697
|
+
"Registering Facebook Pixel integration with ID:",
|
|
2698
|
+
integrationConfig.config.pixelId
|
|
2699
|
+
);
|
|
2700
|
+
const fbIntegration = createFacebookPixelIntegration(
|
|
2701
|
+
integrationConfig.config,
|
|
2702
|
+
integrationConfig.debug
|
|
2703
|
+
);
|
|
2704
|
+
await this.integrationManager.registerIntegration(fbIntegration);
|
|
2705
|
+
} else if (integrationConfig.type === "pinterest-tag") {
|
|
2706
|
+
this.logger.info(
|
|
2707
|
+
"Registering Pinterest Tag integration with ID:",
|
|
2708
|
+
integrationConfig.config.tagId
|
|
2709
|
+
);
|
|
2710
|
+
const pinterestIntegration = createPinterestTagIntegration(
|
|
2711
|
+
integrationConfig.config,
|
|
2712
|
+
integrationConfig.debug
|
|
2713
|
+
);
|
|
2714
|
+
await this.integrationManager.registerIntegration(
|
|
2715
|
+
pinterestIntegration
|
|
2716
|
+
);
|
|
2717
|
+
} else if (integrationConfig.type === "tiktok-pixel") {
|
|
2718
|
+
this.logger.info(
|
|
2719
|
+
"Registering TikTok Pixel integration with ID:",
|
|
2720
|
+
integrationConfig.config.pixelId
|
|
2721
|
+
);
|
|
2722
|
+
const tiktokIntegration = createTikTokPixelIntegration(
|
|
2723
|
+
integrationConfig.config,
|
|
2724
|
+
integrationConfig.debug
|
|
2725
|
+
);
|
|
2726
|
+
await this.integrationManager.registerIntegration(
|
|
2727
|
+
tiktokIntegration
|
|
2728
|
+
);
|
|
2729
|
+
}
|
|
2730
|
+
} catch (error) {
|
|
2570
2731
|
this.logger.info(
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
);
|
|
2574
|
-
const tiktokIntegration = createTikTokPixelIntegration(
|
|
2575
|
-
integrationConfig.config,
|
|
2576
|
-
integrationConfig.debug
|
|
2732
|
+
`Failed to register ${integrationConfig.type} integration:`,
|
|
2733
|
+
error
|
|
2577
2734
|
);
|
|
2578
|
-
await this.integrationManager.registerIntegration(tiktokIntegration);
|
|
2579
2735
|
}
|
|
2580
|
-
}
|
|
2581
|
-
|
|
2582
|
-
`Failed to register ${integrationConfig.type} integration:`,
|
|
2583
|
-
error
|
|
2584
|
-
);
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2736
|
+
})
|
|
2737
|
+
);
|
|
2587
2738
|
}
|
|
2588
2739
|
track(actionOrPayload, propertiesOrNothing, contextOrNothing) {
|
|
2589
2740
|
if (!this.config.projectId) {
|
|
@@ -2640,7 +2791,19 @@ var Saasco = class {
|
|
|
2640
2791
|
});
|
|
2641
2792
|
}
|
|
2642
2793
|
this.integrationManager.track(action, properties);
|
|
2643
|
-
|
|
2794
|
+
const eventId = properties?.["event_id"];
|
|
2795
|
+
if (!isBrowser5 || typeof eventId !== "string" || !eventId.trim()) {
|
|
2796
|
+
return this.doRequest("events", requestData);
|
|
2797
|
+
}
|
|
2798
|
+
return deliverOnce(
|
|
2799
|
+
`saasco:${this.config.projectId}:ingest:${action}:${eventId}`,
|
|
2800
|
+
async () => {
|
|
2801
|
+
const result = await this.doRequest("events", requestData);
|
|
2802
|
+
if (!result.success) {
|
|
2803
|
+
throw new Error(result.message);
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
).then(() => ({ success: true, message: "Event dispatched" })).catch((error) => ({ success: false, message: String(error) }));
|
|
2644
2807
|
}
|
|
2645
2808
|
/**
|
|
2646
2809
|
* The page method lets you record page views on your website
|
|
@@ -2740,7 +2903,10 @@ var Saasco = class {
|
|
|
2740
2903
|
},
|
|
2741
2904
|
context: context || {}
|
|
2742
2905
|
};
|
|
2743
|
-
this.logger.info("identify",
|
|
2906
|
+
this.logger.info("identify", {
|
|
2907
|
+
distinctId,
|
|
2908
|
+
projectId: this.config.projectId
|
|
2909
|
+
});
|
|
2744
2910
|
if (!this.config.enabled) {
|
|
2745
2911
|
return Promise.resolve({
|
|
2746
2912
|
success: true,
|
|
@@ -2776,6 +2942,13 @@ var Saasco = class {
|
|
|
2776
2942
|
message: "Analytics is disabled"
|
|
2777
2943
|
};
|
|
2778
2944
|
}
|
|
2945
|
+
const projectId = requestData.projectId ?? null;
|
|
2946
|
+
const fail = (input) => reportIngestFailure({
|
|
2947
|
+
failure: formatAnalyticsRequestFailure({ path, projectId, ...input }),
|
|
2948
|
+
logger: this.logger,
|
|
2949
|
+
path,
|
|
2950
|
+
seen: this.ingestFailureKeys
|
|
2951
|
+
});
|
|
2779
2952
|
let response;
|
|
2780
2953
|
try {
|
|
2781
2954
|
response = await fetch(url, {
|
|
@@ -2785,46 +2958,22 @@ var Saasco = class {
|
|
|
2785
2958
|
},
|
|
2786
2959
|
body: JSON.stringify(requestData)
|
|
2787
2960
|
});
|
|
2788
|
-
} catch
|
|
2789
|
-
|
|
2790
|
-
this.logger.warn(
|
|
2791
|
-
`Network request failed`,
|
|
2792
|
-
`
|
|
2793
|
-
Error Message: "${message}"`,
|
|
2794
|
-
`
|
|
2795
|
-
Url: "${url}"`
|
|
2796
|
-
);
|
|
2797
|
-
return {
|
|
2798
|
-
success: false,
|
|
2799
|
-
message
|
|
2800
|
-
};
|
|
2961
|
+
} catch {
|
|
2962
|
+
return fail({ reason: "unreachable" });
|
|
2801
2963
|
}
|
|
2964
|
+
let responseBody;
|
|
2802
2965
|
try {
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
}
|
|
2809
|
-
return {
|
|
2810
|
-
success: true,
|
|
2811
|
-
message: responseBody.message ?? ""
|
|
2812
|
-
};
|
|
2813
|
-
} catch (error) {
|
|
2814
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2815
|
-
this.logger.error(
|
|
2816
|
-
`
|
|
2817
|
-
Error Message: "${message}"`,
|
|
2818
|
-
`
|
|
2819
|
-
Path: "/${path}"`,
|
|
2820
|
-
`
|
|
2821
|
-
Request Data: ${JSON.stringify(requestData, null, 2)}`
|
|
2822
|
-
);
|
|
2823
|
-
return {
|
|
2824
|
-
success: false,
|
|
2825
|
-
message
|
|
2826
|
-
};
|
|
2966
|
+
responseBody = await response.json();
|
|
2967
|
+
} catch {
|
|
2968
|
+
return fail({ reason: "http" });
|
|
2969
|
+
}
|
|
2970
|
+
if (!response.ok) {
|
|
2971
|
+
return fail({ reason: "http", body: responseBody });
|
|
2827
2972
|
}
|
|
2973
|
+
return {
|
|
2974
|
+
success: true,
|
|
2975
|
+
message: responseBody && typeof responseBody === "object" && "message" in responseBody && typeof responseBody.message === "string" ? responseBody.message : ""
|
|
2976
|
+
};
|
|
2828
2977
|
}
|
|
2829
2978
|
/**
|
|
2830
2979
|
* If autoPageTracking is enabled, this will automatically track page views
|
|
@@ -3052,31 +3201,31 @@ function getLoggerLevel(config) {
|
|
|
3052
3201
|
}
|
|
3053
3202
|
|
|
3054
3203
|
// ../shared/src/lib/types/browserContext.ts
|
|
3055
|
-
var
|
|
3056
|
-
var BrowserContextSchema =
|
|
3057
|
-
$href:
|
|
3058
|
-
$locale:
|
|
3059
|
-
$location:
|
|
3060
|
-
$pathname:
|
|
3061
|
-
$referrer:
|
|
3062
|
-
$referringDomain:
|
|
3063
|
-
$screenDPI:
|
|
3064
|
-
$screenHeight:
|
|
3065
|
-
$screenWidth:
|
|
3066
|
-
$title:
|
|
3067
|
-
$userAgent:
|
|
3068
|
-
$utmAdId:
|
|
3069
|
-
$utmAdSource:
|
|
3070
|
-
$utmCampaign:
|
|
3071
|
-
$utmCampaignId:
|
|
3072
|
-
$utmContent:
|
|
3073
|
-
$utmCreativeFormat:
|
|
3074
|
-
$utmId:
|
|
3075
|
-
$utmMarketingTactic:
|
|
3076
|
-
$utmMedium:
|
|
3077
|
-
$utmSource:
|
|
3078
|
-
$utmSourcePlatform:
|
|
3079
|
-
$utmTerm:
|
|
3204
|
+
var import_zod2 = require("zod");
|
|
3205
|
+
var BrowserContextSchema = import_zod2.z.object({
|
|
3206
|
+
$href: import_zod2.z.string(),
|
|
3207
|
+
$locale: import_zod2.z.string(),
|
|
3208
|
+
$location: import_zod2.z.string(),
|
|
3209
|
+
$pathname: import_zod2.z.string(),
|
|
3210
|
+
$referrer: import_zod2.z.string(),
|
|
3211
|
+
$referringDomain: import_zod2.z.string(),
|
|
3212
|
+
$screenDPI: import_zod2.z.number(),
|
|
3213
|
+
$screenHeight: import_zod2.z.number(),
|
|
3214
|
+
$screenWidth: import_zod2.z.number(),
|
|
3215
|
+
$title: import_zod2.z.string(),
|
|
3216
|
+
$userAgent: import_zod2.z.string(),
|
|
3217
|
+
$utmAdId: import_zod2.z.string().nullable(),
|
|
3218
|
+
$utmAdSource: import_zod2.z.string().nullable(),
|
|
3219
|
+
$utmCampaign: import_zod2.z.string().nullable(),
|
|
3220
|
+
$utmCampaignId: import_zod2.z.string().nullable(),
|
|
3221
|
+
$utmContent: import_zod2.z.string().nullable(),
|
|
3222
|
+
$utmCreativeFormat: import_zod2.z.string().nullable(),
|
|
3223
|
+
$utmId: import_zod2.z.string().nullable(),
|
|
3224
|
+
$utmMarketingTactic: import_zod2.z.string().nullable(),
|
|
3225
|
+
$utmMedium: import_zod2.z.string().nullable(),
|
|
3226
|
+
$utmSource: import_zod2.z.string().nullable(),
|
|
3227
|
+
$utmSourcePlatform: import_zod2.z.string().nullable(),
|
|
3228
|
+
$utmTerm: import_zod2.z.string().nullable()
|
|
3080
3229
|
});
|
|
3081
3230
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3082
3231
|
0 && (module.exports = {
|