sitepong 0.1.13 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ require('web-vitals');
6
+
5
7
  // src/flags/anonymous-id.ts
6
8
  var STORAGE_KEY = "sitepong_anonymous_id";
7
9
  function generateUUID() {
@@ -520,6 +522,60 @@ function clearSession() {
520
522
  memorySessionTs = null;
521
523
  }
522
524
 
525
+ // src/analytics/utm.ts
526
+ var STORAGE_KEY2 = "sp_utm";
527
+ var UTM_KEYS = [
528
+ ["source", "utm_source"],
529
+ ["medium", "utm_medium"],
530
+ ["campaign", "utm_campaign"],
531
+ ["term", "utm_term"],
532
+ ["content", "utm_content"]
533
+ ];
534
+ function parseFromLocation() {
535
+ if (typeof window === "undefined" || !window.location || !window.location.search) return null;
536
+ let params;
537
+ try {
538
+ params = new URLSearchParams(window.location.search);
539
+ } catch {
540
+ return null;
541
+ }
542
+ const result = {};
543
+ let found = false;
544
+ for (const [key, queryKey] of UTM_KEYS) {
545
+ const value = params.get(queryKey);
546
+ if (value) {
547
+ result[key] = value;
548
+ found = true;
549
+ }
550
+ }
551
+ return found ? result : null;
552
+ }
553
+ function readStored() {
554
+ if (typeof sessionStorage === "undefined") return null;
555
+ try {
556
+ const raw = sessionStorage.getItem(STORAGE_KEY2);
557
+ if (!raw) return null;
558
+ const parsed = JSON.parse(raw);
559
+ return parsed && typeof parsed === "object" ? parsed : null;
560
+ } catch {
561
+ return null;
562
+ }
563
+ }
564
+ function writeStored(utm) {
565
+ if (typeof sessionStorage === "undefined") return;
566
+ try {
567
+ sessionStorage.setItem(STORAGE_KEY2, JSON.stringify(utm));
568
+ } catch {
569
+ }
570
+ }
571
+ function getSessionUtm() {
572
+ const stored = readStored();
573
+ if (stored) return stored;
574
+ const fresh = parseFromLocation();
575
+ if (fresh) writeStored(fresh);
576
+ return fresh;
577
+ }
578
+
523
579
  // src/analytics/autocapture.ts
524
580
  var DEFAULT_BLOCK_SELECTORS = [
525
581
  "[data-sp-no-capture]",
@@ -926,7 +982,9 @@ var AnalyticsManager = class {
926
982
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
927
983
  url: typeof window !== "undefined" && window.location ? window.location.href : void 0,
928
984
  referrer: typeof document !== "undefined" && typeof document.referrer === "string" ? document.referrer : void 0,
929
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
985
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
986
+ utm: getSessionUtm() || void 0,
987
+ appVersion: this.config.appVersion || void 0
930
988
  };
931
989
  }
932
990
  enqueue(event) {
@@ -1624,7 +1682,7 @@ var DEFAULT_REMOTE_CONFIG = {
1624
1682
  };
1625
1683
 
1626
1684
  // src/remote-config/manager.ts
1627
- var STORAGE_KEY2 = "sitepong_remote_config";
1685
+ var STORAGE_KEY3 = "sitepong_remote_config";
1628
1686
  var STORAGE_TS_KEY = "sitepong_remote_config_ts";
1629
1687
  var RemoteConfigManager = class {
1630
1688
  constructor(options) {
@@ -1667,7 +1725,7 @@ var RemoteConfigManager = class {
1667
1725
  const storage = this.options.storage;
1668
1726
  if (!storage) return;
1669
1727
  try {
1670
- const cached = await storage.getItem(STORAGE_KEY2);
1728
+ const cached = await storage.getItem(STORAGE_KEY3);
1671
1729
  const cachedTs = await storage.getItem(STORAGE_TS_KEY);
1672
1730
  if (cached && cachedTs) {
1673
1731
  const age = Date.now() - parseInt(cachedTs, 10);
@@ -1728,7 +1786,7 @@ var RemoteConfigManager = class {
1728
1786
  const storage = this.options.storage;
1729
1787
  if (!storage) return;
1730
1788
  try {
1731
- await storage.setItem(STORAGE_KEY2, JSON.stringify(this.config));
1789
+ await storage.setItem(STORAGE_KEY3, JSON.stringify(this.config));
1732
1790
  await storage.setItem(STORAGE_TS_KEY, String(Date.now()));
1733
1791
  } catch {
1734
1792
  this.log("Failed to cache remote config");
@@ -1907,6 +1965,292 @@ var TracePropagator = class {
1907
1965
  }
1908
1966
  };
1909
1967
 
1968
+ // src/superlink/client.ts
1969
+ var DEFAULT_SUPERLINK_ENDPOINT = "https://pongl.ink";
1970
+ var SuperLinkClient = class {
1971
+ constructor(config = {}) {
1972
+ this.config = {
1973
+ endpoint: stripTrailingSlash(config.endpoint || DEFAULT_SUPERLINK_ENDPOINT),
1974
+ appId: config.appId,
1975
+ installId: config.installId,
1976
+ debug: config.debug ?? false
1977
+ };
1978
+ }
1979
+ /** Replace config in place (used by init() so module-level helpers see updates). */
1980
+ configure(config) {
1981
+ if (config.endpoint) this.config.endpoint = stripTrailingSlash(config.endpoint);
1982
+ if (config.appId !== void 0) this.config.appId = config.appId;
1983
+ if (config.installId !== void 0) this.config.installId = config.installId;
1984
+ if (config.debug !== void 0) this.config.debug = config.debug;
1985
+ }
1986
+ log(...args) {
1987
+ if (this.config.debug) console.warn("[SuperLink]", ...args);
1988
+ }
1989
+ /**
1990
+ * POST /match — ask the redirect engine to resolve a deferred deep link from
1991
+ * a click token (Android referrer / iOS clipboard) and/or a device
1992
+ * fingerprint. Returns `{ matched: false }` on any error.
1993
+ */
1994
+ async match(body) {
1995
+ const payload = {
1996
+ ...body,
1997
+ install_id: body.install_id ?? this.config.installId
1998
+ };
1999
+ try {
2000
+ const res = await fetch(`${this.config.endpoint}/match`, {
2001
+ method: "POST",
2002
+ headers: { "Content-Type": "application/json" },
2003
+ body: JSON.stringify(payload)
2004
+ });
2005
+ if (!res.ok) {
2006
+ this.log("match failed", res.status);
2007
+ return { matched: false };
2008
+ }
2009
+ const data = await res.json();
2010
+ return data ?? { matched: false };
2011
+ } catch (err) {
2012
+ this.log("match error", err);
2013
+ return { matched: false };
2014
+ }
2015
+ }
2016
+ /**
2017
+ * POST /events — report a lifecycle event (opened / converted) back to the
2018
+ * redirect engine, which fans out to analytics + webhooks. Best-effort.
2019
+ */
2020
+ async reportEvent(input) {
2021
+ try {
2022
+ const res = await fetch(`${this.config.endpoint}/events`, {
2023
+ method: "POST",
2024
+ headers: { "Content-Type": "application/json" },
2025
+ body: JSON.stringify({
2026
+ app_id: this.config.appId,
2027
+ install_id: this.config.installId,
2028
+ ...input
2029
+ })
2030
+ });
2031
+ if (!res.ok) this.log("event failed", input.type, res.status);
2032
+ return res.ok;
2033
+ } catch (err) {
2034
+ this.log("event error", err);
2035
+ return false;
2036
+ }
2037
+ }
2038
+ };
2039
+ function stripTrailingSlash(url) {
2040
+ return url.endsWith("/") ? url.slice(0, -1) : url;
2041
+ }
2042
+ var superlinkClient = new SuperLinkClient();
2043
+
2044
+ // src/superlink/parse.ts
2045
+ var UTM_KEYS2 = [
2046
+ ["source", "utm_source"],
2047
+ ["medium", "utm_medium"],
2048
+ ["campaign", "utm_campaign"],
2049
+ ["term", "utm_term"],
2050
+ ["content", "utm_content"]
2051
+ ];
2052
+ function parseUniversalLink(url) {
2053
+ let parsed;
2054
+ try {
2055
+ parsed = new URL(url);
2056
+ } catch {
2057
+ return null;
2058
+ }
2059
+ const params = parsed.searchParams;
2060
+ const utm = {};
2061
+ for (const [key, queryKey] of UTM_KEYS2) {
2062
+ const value = params.get(queryKey);
2063
+ if (value) utm[key] = value;
2064
+ }
2065
+ const referral = {};
2066
+ const deep_link_data = {};
2067
+ params.forEach((value, key) => {
2068
+ if (key.startsWith("r_")) {
2069
+ referral[key.slice(2)] = value;
2070
+ } else if (key.startsWith("~")) {
2071
+ deep_link_data[key.slice(1)] = value;
2072
+ }
2073
+ });
2074
+ const explicitPath = params.get("$deep_link_path") ?? params.get("dlp");
2075
+ const deep_link_path = explicitPath ?? (parsed.pathname && parsed.pathname !== "/" ? parsed.pathname : null);
2076
+ return {
2077
+ deep_link_path,
2078
+ deep_link_data,
2079
+ utm,
2080
+ referral,
2081
+ click_id: params.get("click_id"),
2082
+ match_type: "none",
2083
+ confidence: 1
2084
+ };
2085
+ }
2086
+
2087
+ // src/superlink/deferred.ts
2088
+ var handlers = /* @__PURE__ */ new Set();
2089
+ var lastMatched = null;
2090
+ function toDeepLink(res) {
2091
+ return {
2092
+ deep_link_path: res.deep_link_path ?? null,
2093
+ deep_link_data: res.deep_link_data ?? {},
2094
+ utm: res.utm ?? {},
2095
+ referral: res.referral ?? {},
2096
+ click_id: res.click_id ?? null,
2097
+ match_type: res.match_type ?? "fingerprint",
2098
+ confidence: res.confidence ?? (res.match_type && res.match_type !== "none" ? 1 : 0)
2099
+ };
2100
+ }
2101
+ function emitDeferredDeepLink(link) {
2102
+ lastMatched = link;
2103
+ for (const handler of handlers) {
2104
+ try {
2105
+ handler(link);
2106
+ } catch (err) {
2107
+ if (superlinkClient.config.debug) console.warn("[SuperLink] handler threw", err);
2108
+ }
2109
+ }
2110
+ }
2111
+ function onDeferredDeepLink(handler) {
2112
+ handlers.add(handler);
2113
+ if (lastMatched) {
2114
+ try {
2115
+ handler(lastMatched);
2116
+ } catch {
2117
+ }
2118
+ }
2119
+ return () => {
2120
+ handlers.delete(handler);
2121
+ };
2122
+ }
2123
+ function getMatchedDeepLink() {
2124
+ return lastMatched;
2125
+ }
2126
+
2127
+ // src/superlink/web.ts
2128
+ var STORAGE_KEY4 = "sp_superlink";
2129
+ var captured = null;
2130
+ var didCapture = false;
2131
+ function readStored2() {
2132
+ if (typeof sessionStorage === "undefined") return null;
2133
+ try {
2134
+ const raw = sessionStorage.getItem(STORAGE_KEY4);
2135
+ if (!raw) return null;
2136
+ const parsed = JSON.parse(raw);
2137
+ return parsed && typeof parsed === "object" ? parsed : null;
2138
+ } catch {
2139
+ return null;
2140
+ }
2141
+ }
2142
+ function writeStored2(link) {
2143
+ if (typeof sessionStorage === "undefined") return;
2144
+ try {
2145
+ sessionStorage.setItem(STORAGE_KEY4, JSON.stringify(link));
2146
+ } catch {
2147
+ }
2148
+ }
2149
+ function hasPayload(link) {
2150
+ return Boolean(
2151
+ link.deep_link_path || link.click_id || Object.keys(link.deep_link_data).length > 0 || Object.keys(link.referral).length > 0 || Object.keys(link.utm).length > 0
2152
+ );
2153
+ }
2154
+ function writeClipboardToken(clickId) {
2155
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
2156
+ const url = `${superlinkClient.config.endpoint}/c/${clickId}`;
2157
+ navigator.clipboard.writeText(url).catch(() => {
2158
+ });
2159
+ }
2160
+ function extractIdentityMetadata(url) {
2161
+ const href = url ?? (typeof window !== "undefined" && window.location ? window.location.href : null);
2162
+ if (!href) return void 0;
2163
+ let loc;
2164
+ try {
2165
+ loc = new URL(href);
2166
+ } catch {
2167
+ return void 0;
2168
+ }
2169
+ const email = loc.searchParams.get("email");
2170
+ const phone = loc.searchParams.get("phone");
2171
+ const userId = loc.searchParams.get("user_id");
2172
+ const id = loc.searchParams.get("id");
2173
+ const customRaw = loc.searchParams.get("custom");
2174
+ const identity = {};
2175
+ if (email) identity.email = email;
2176
+ if (phone) identity.phone = phone;
2177
+ if (userId) identity.user_id = userId;
2178
+ if (id) identity.id = id;
2179
+ if (customRaw) {
2180
+ try {
2181
+ const custom = JSON.parse(decodeURIComponent(customRaw));
2182
+ if (typeof custom === "object" && custom !== null) {
2183
+ identity.custom = custom;
2184
+ }
2185
+ } catch {
2186
+ }
2187
+ }
2188
+ return Object.keys(identity).length > 0 ? identity : void 0;
2189
+ }
2190
+ function captureWebDeepLink() {
2191
+ if (didCapture) return captured;
2192
+ didCapture = true;
2193
+ const stored = readStored2();
2194
+ if (stored) {
2195
+ captured = stored;
2196
+ return captured;
2197
+ }
2198
+ if (typeof window === "undefined" || !window.location) return null;
2199
+ const link = parseUniversalLink(window.location.href);
2200
+ if (link && hasPayload(link)) {
2201
+ captured = link;
2202
+ writeStored2(link);
2203
+ void superlinkClient.reportEvent({
2204
+ type: "opened",
2205
+ click_id: link.click_id,
2206
+ platform: "desktop",
2207
+ properties: { surface: "web" }
2208
+ });
2209
+ }
2210
+ return captured;
2211
+ }
2212
+ function getDeepLink() {
2213
+ if (!didCapture) return captureWebDeepLink();
2214
+ return captured;
2215
+ }
2216
+ function webFingerprint() {
2217
+ const fp = { platform: "desktop" };
2218
+ if (typeof navigator !== "undefined") {
2219
+ if (navigator.userAgent) fp.user_agent = navigator.userAgent;
2220
+ const lang = navigator.language || navigator.languages && navigator.languages[0];
2221
+ if (lang) fp.language = lang;
2222
+ }
2223
+ return fp;
2224
+ }
2225
+ async function identify(identity) {
2226
+ if (!identity || Object.keys(identity).length === 0) return null;
2227
+ const res = await superlinkClient.match({
2228
+ identity,
2229
+ fingerprint: webFingerprint()
2230
+ });
2231
+ if (!res.matched) return null;
2232
+ const link = toDeepLink(res);
2233
+ emitDeferredDeepLink(link);
2234
+ return link;
2235
+ }
2236
+ async function completeFromScan(scanned) {
2237
+ if (!scanned) return null;
2238
+ const res = await superlinkClient.match({
2239
+ qr_token: scanned,
2240
+ fingerprint: webFingerprint()
2241
+ });
2242
+ if (!res.matched) return null;
2243
+ const link = toDeepLink(res);
2244
+ emitDeferredDeepLink(link);
2245
+ return link;
2246
+ }
2247
+
2248
+ // src/superlink/index.ts
2249
+ function initSuperLink(config = {}) {
2250
+ superlinkClient.configure(config);
2251
+ captureWebDeepLink();
2252
+ }
2253
+
1910
2254
  // src/index.ts
1911
2255
  function installFallbackEnvironment() {
1912
2256
  if (getEnvironment()) return;
@@ -2116,6 +2460,10 @@ var SitePongClient = class {
2116
2460
  webVitals: config.performance.webVitals,
2117
2461
  navigationTiming: config.performance.navigationTiming,
2118
2462
  resourceTiming: config.performance.resourceTiming,
2463
+ capturePageLoadTimings: config.performance.capturePageLoadTimings,
2464
+ capturePageRenderTimings: config.performance.capturePageRenderTimings,
2465
+ excludedResourceUrls: config.performance.excludedResourceUrls,
2466
+ resourceNameSanitizer: config.performance.resourceNameSanitizer,
2119
2467
  sampleRate: config.performance.sampleRate,
2120
2468
  flushInterval: config.performance.flushInterval,
2121
2469
  performanceEndpoint: config.performance.performanceEndpoint,
@@ -2824,7 +3172,7 @@ var areFlagsReady = sitepong.areFlagsReady.bind(sitepong);
2824
3172
  var refreshFlags = sitepong.refreshFlags.bind(sitepong);
2825
3173
  var track = sitepong.track.bind(sitepong);
2826
3174
  var trackPageView = sitepong.trackPageView.bind(sitepong);
2827
- var identify = sitepong.identify.bind(sitepong);
3175
+ var identify2 = sitepong.identify.bind(sitepong);
2828
3176
  var group = sitepong.group.bind(sitepong);
2829
3177
  var resetAnalytics = sitepong.resetAnalytics.bind(sitepong);
2830
3178
  var getVisitorId = sitepong.getVisitorId.bind(sitepong);
@@ -2865,14 +3213,18 @@ var onRemoteConfigChange = sitepong.onRemoteConfigChange.bind(sitepong);
2865
3213
  var registerIdentifyHook = sitepong.registerIdentifyHook.bind(sitepong);
2866
3214
  var src_default = sitepong;
2867
3215
 
3216
+ exports.DEFAULT_SUPERLINK_ENDPOINT = DEFAULT_SUPERLINK_ENDPOINT;
3217
+ exports.SuperLinkClient = SuperLinkClient;
2868
3218
  exports.TracePropagator = TracePropagator;
2869
3219
  exports.addBreadcrumb = addBreadcrumb;
2870
3220
  exports.areFlagsReady = areFlagsReady;
2871
3221
  exports.captureError = captureError;
2872
3222
  exports.captureMessage = captureMessage;
3223
+ exports.captureWebDeepLink = captureWebDeepLink;
2873
3224
  exports.clearAnonymousId = clearAnonymousId;
2874
3225
  exports.clearUser = clearUser;
2875
3226
  exports.client = sitepong;
3227
+ exports.completeFromScan = completeFromScan;
2876
3228
  exports.createTraceContext = createTraceContext;
2877
3229
  exports.cronCheckin = cronCheckin;
2878
3230
  exports.cronStart = cronStart;
@@ -2882,6 +3234,7 @@ exports.dbTrackSync = dbTrackSync;
2882
3234
  exports.default = src_default;
2883
3235
  exports.endSpan = endSpan;
2884
3236
  exports.endTransaction = endTransaction;
3237
+ exports.extractIdentityMetadata = extractIdentityMetadata;
2885
3238
  exports.extractTrace = extractTrace;
2886
3239
  exports.flush = flush;
2887
3240
  exports.flushMetrics = flushMetrics;
@@ -2892,10 +3245,12 @@ exports.getAllFlags = getAllFlags;
2892
3245
  exports.getAnonymousId = getAnonymousId;
2893
3246
  exports.getDbNPlusOnePatterns = getDbNPlusOnePatterns;
2894
3247
  exports.getDbQueryCount = getDbQueryCount;
3248
+ exports.getDeepLink = getDeepLink;
2895
3249
  exports.getDeviceSignals = getDeviceSignals;
2896
3250
  exports.getFlag = getFlag;
2897
3251
  exports.getFraudCheck = getFraudCheck;
2898
3252
  exports.getLatestProfile = getLatestProfile;
3253
+ exports.getMatchedDeepLink = getMatchedDeepLink;
2899
3254
  exports.getProfiles = getProfiles;
2900
3255
  exports.getRemoteConfig = getRemoteConfig;
2901
3256
  exports.getReplaySessionId = getReplaySessionId;
@@ -2904,9 +3259,10 @@ exports.getVariantPayload = getVariantPayload2;
2904
3259
  exports.getVisitorId = getVisitorId;
2905
3260
  exports.getWebVitals = getWebVitals;
2906
3261
  exports.group = group;
2907
- exports.identify = identify;
3262
+ exports.identify = identify2;
2908
3263
  exports.init = init;
2909
3264
  exports.initRN = initRN;
3265
+ exports.initSuperLink = initSuperLink;
2910
3266
  exports.isInitialized = isInitialized;
2911
3267
  exports.isRemoteConfigFeatureEnabled = isRemoteConfigFeatureEnabled;
2912
3268
  exports.isReplayRecording = isReplayRecording;
@@ -2916,7 +3272,9 @@ exports.metricHistogram = metricHistogram;
2916
3272
  exports.metricIncrement = metricIncrement;
2917
3273
  exports.metricStartTimer = metricStartTimer;
2918
3274
  exports.metricTime = metricTime;
3275
+ exports.onDeferredDeepLink = onDeferredDeepLink;
2919
3276
  exports.onRemoteConfigChange = onRemoteConfigChange;
3277
+ exports.parseUniversalLink = parseUniversalLink;
2920
3278
  exports.profile = profile;
2921
3279
  exports.propagateTrace = propagateTrace;
2922
3280
  exports.refreshFlags = refreshFlags;
@@ -2936,8 +3294,11 @@ exports.startReplay = startReplay;
2936
3294
  exports.startSpan = startSpan;
2937
3295
  exports.startTransaction = startTransaction;
2938
3296
  exports.stopReplay = stopReplay;
3297
+ exports.superlinkClient = superlinkClient;
3298
+ exports.superlinkIdentify = identify;
2939
3299
  exports.track = track;
2940
3300
  exports.trackPageView = trackPageView;
2941
3301
  exports.waitForFlags = waitForFlags;
3302
+ exports.writeClipboardToken = writeClipboardToken;
2942
3303
  //# sourceMappingURL=index.js.map
2943
3304
  //# sourceMappingURL=index.js.map