sitepong 0.1.13 → 0.2.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.
@@ -1,4 +1,5 @@
1
1
  import { createContext, useRef, useEffect, Component, useContext, useCallback, useState } from 'react';
2
+ import 'web-vitals';
2
3
  import { jsx, jsxs } from 'react/jsx-runtime';
3
4
 
4
5
  // src/react/provider.tsx
@@ -1908,6 +1909,292 @@ var TracePropagator = class {
1908
1909
  }
1909
1910
  };
1910
1911
 
1912
+ // src/superlink/client.ts
1913
+ var DEFAULT_SUPERLINK_ENDPOINT = "https://pongl.ink";
1914
+ var SuperLinkClient = class {
1915
+ constructor(config = {}) {
1916
+ this.config = {
1917
+ endpoint: stripTrailingSlash(config.endpoint || DEFAULT_SUPERLINK_ENDPOINT),
1918
+ appId: config.appId,
1919
+ installId: config.installId,
1920
+ debug: config.debug ?? false
1921
+ };
1922
+ }
1923
+ /** Replace config in place (used by init() so module-level helpers see updates). */
1924
+ configure(config) {
1925
+ if (config.endpoint) this.config.endpoint = stripTrailingSlash(config.endpoint);
1926
+ if (config.appId !== void 0) this.config.appId = config.appId;
1927
+ if (config.installId !== void 0) this.config.installId = config.installId;
1928
+ if (config.debug !== void 0) this.config.debug = config.debug;
1929
+ }
1930
+ log(...args) {
1931
+ if (this.config.debug) console.warn("[SuperLink]", ...args);
1932
+ }
1933
+ /**
1934
+ * POST /match — ask the redirect engine to resolve a deferred deep link from
1935
+ * a click token (Android referrer / iOS clipboard) and/or a device
1936
+ * fingerprint. Returns `{ matched: false }` on any error.
1937
+ */
1938
+ async match(body) {
1939
+ const payload = {
1940
+ ...body,
1941
+ install_id: body.install_id ?? this.config.installId
1942
+ };
1943
+ try {
1944
+ const res = await fetch(`${this.config.endpoint}/match`, {
1945
+ method: "POST",
1946
+ headers: { "Content-Type": "application/json" },
1947
+ body: JSON.stringify(payload)
1948
+ });
1949
+ if (!res.ok) {
1950
+ this.log("match failed", res.status);
1951
+ return { matched: false };
1952
+ }
1953
+ const data = await res.json();
1954
+ return data ?? { matched: false };
1955
+ } catch (err) {
1956
+ this.log("match error", err);
1957
+ return { matched: false };
1958
+ }
1959
+ }
1960
+ /**
1961
+ * POST /events — report a lifecycle event (opened / converted) back to the
1962
+ * redirect engine, which fans out to analytics + webhooks. Best-effort.
1963
+ */
1964
+ async reportEvent(input) {
1965
+ try {
1966
+ const res = await fetch(`${this.config.endpoint}/events`, {
1967
+ method: "POST",
1968
+ headers: { "Content-Type": "application/json" },
1969
+ body: JSON.stringify({
1970
+ app_id: this.config.appId,
1971
+ install_id: this.config.installId,
1972
+ ...input
1973
+ })
1974
+ });
1975
+ if (!res.ok) this.log("event failed", input.type, res.status);
1976
+ return res.ok;
1977
+ } catch (err) {
1978
+ this.log("event error", err);
1979
+ return false;
1980
+ }
1981
+ }
1982
+ };
1983
+ function stripTrailingSlash(url) {
1984
+ return url.endsWith("/") ? url.slice(0, -1) : url;
1985
+ }
1986
+ var superlinkClient = new SuperLinkClient();
1987
+
1988
+ // src/superlink/parse.ts
1989
+ var UTM_KEYS = [
1990
+ ["source", "utm_source"],
1991
+ ["medium", "utm_medium"],
1992
+ ["campaign", "utm_campaign"],
1993
+ ["term", "utm_term"],
1994
+ ["content", "utm_content"]
1995
+ ];
1996
+ function parseUniversalLink(url) {
1997
+ let parsed;
1998
+ try {
1999
+ parsed = new URL(url);
2000
+ } catch {
2001
+ return null;
2002
+ }
2003
+ const params = parsed.searchParams;
2004
+ const utm = {};
2005
+ for (const [key, queryKey] of UTM_KEYS) {
2006
+ const value = params.get(queryKey);
2007
+ if (value) utm[key] = value;
2008
+ }
2009
+ const referral = {};
2010
+ const deep_link_data = {};
2011
+ params.forEach((value, key) => {
2012
+ if (key.startsWith("r_")) {
2013
+ referral[key.slice(2)] = value;
2014
+ } else if (key.startsWith("~")) {
2015
+ deep_link_data[key.slice(1)] = value;
2016
+ }
2017
+ });
2018
+ const explicitPath = params.get("$deep_link_path") ?? params.get("dlp");
2019
+ const deep_link_path = explicitPath ?? (parsed.pathname && parsed.pathname !== "/" ? parsed.pathname : null);
2020
+ return {
2021
+ deep_link_path,
2022
+ deep_link_data,
2023
+ utm,
2024
+ referral,
2025
+ click_id: params.get("click_id"),
2026
+ match_type: "none",
2027
+ confidence: 1
2028
+ };
2029
+ }
2030
+
2031
+ // src/superlink/deferred.ts
2032
+ var handlers = /* @__PURE__ */ new Set();
2033
+ var lastMatched = null;
2034
+ function toDeepLink(res) {
2035
+ return {
2036
+ deep_link_path: res.deep_link_path ?? null,
2037
+ deep_link_data: res.deep_link_data ?? {},
2038
+ utm: res.utm ?? {},
2039
+ referral: res.referral ?? {},
2040
+ click_id: res.click_id ?? null,
2041
+ match_type: res.match_type ?? "fingerprint",
2042
+ confidence: res.confidence ?? (res.match_type && res.match_type !== "none" ? 1 : 0)
2043
+ };
2044
+ }
2045
+ function emitDeferredDeepLink(link) {
2046
+ lastMatched = link;
2047
+ for (const handler of handlers) {
2048
+ try {
2049
+ handler(link);
2050
+ } catch (err) {
2051
+ if (superlinkClient.config.debug) console.warn("[SuperLink] handler threw", err);
2052
+ }
2053
+ }
2054
+ }
2055
+ function onDeferredDeepLink(handler) {
2056
+ handlers.add(handler);
2057
+ if (lastMatched) {
2058
+ try {
2059
+ handler(lastMatched);
2060
+ } catch {
2061
+ }
2062
+ }
2063
+ return () => {
2064
+ handlers.delete(handler);
2065
+ };
2066
+ }
2067
+ function getMatchedDeepLink() {
2068
+ return lastMatched;
2069
+ }
2070
+
2071
+ // src/superlink/web.ts
2072
+ var STORAGE_KEY3 = "sp_superlink";
2073
+ var captured = null;
2074
+ var didCapture = false;
2075
+ function readStored() {
2076
+ if (typeof sessionStorage === "undefined") return null;
2077
+ try {
2078
+ const raw = sessionStorage.getItem(STORAGE_KEY3);
2079
+ if (!raw) return null;
2080
+ const parsed = JSON.parse(raw);
2081
+ return parsed && typeof parsed === "object" ? parsed : null;
2082
+ } catch {
2083
+ return null;
2084
+ }
2085
+ }
2086
+ function writeStored(link) {
2087
+ if (typeof sessionStorage === "undefined") return;
2088
+ try {
2089
+ sessionStorage.setItem(STORAGE_KEY3, JSON.stringify(link));
2090
+ } catch {
2091
+ }
2092
+ }
2093
+ function hasPayload(link) {
2094
+ return Boolean(
2095
+ 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
2096
+ );
2097
+ }
2098
+ function writeClipboardToken(clickId) {
2099
+ if (typeof navigator === "undefined" || !navigator.clipboard) return;
2100
+ const url = `${superlinkClient.config.endpoint}/c/${clickId}`;
2101
+ navigator.clipboard.writeText(url).catch(() => {
2102
+ });
2103
+ }
2104
+ function extractIdentityMetadata(url) {
2105
+ const href = url ?? (typeof window !== "undefined" && window.location ? window.location.href : null);
2106
+ if (!href) return void 0;
2107
+ let loc;
2108
+ try {
2109
+ loc = new URL(href);
2110
+ } catch {
2111
+ return void 0;
2112
+ }
2113
+ const email = loc.searchParams.get("email");
2114
+ const phone = loc.searchParams.get("phone");
2115
+ const userId = loc.searchParams.get("user_id");
2116
+ const id = loc.searchParams.get("id");
2117
+ const customRaw = loc.searchParams.get("custom");
2118
+ const identity = {};
2119
+ if (email) identity.email = email;
2120
+ if (phone) identity.phone = phone;
2121
+ if (userId) identity.user_id = userId;
2122
+ if (id) identity.id = id;
2123
+ if (customRaw) {
2124
+ try {
2125
+ const custom = JSON.parse(decodeURIComponent(customRaw));
2126
+ if (typeof custom === "object" && custom !== null) {
2127
+ identity.custom = custom;
2128
+ }
2129
+ } catch {
2130
+ }
2131
+ }
2132
+ return Object.keys(identity).length > 0 ? identity : void 0;
2133
+ }
2134
+ function captureWebDeepLink() {
2135
+ if (didCapture) return captured;
2136
+ didCapture = true;
2137
+ const stored = readStored();
2138
+ if (stored) {
2139
+ captured = stored;
2140
+ return captured;
2141
+ }
2142
+ if (typeof window === "undefined" || !window.location) return null;
2143
+ const link = parseUniversalLink(window.location.href);
2144
+ if (link && hasPayload(link)) {
2145
+ captured = link;
2146
+ writeStored(link);
2147
+ void superlinkClient.reportEvent({
2148
+ type: "opened",
2149
+ click_id: link.click_id,
2150
+ platform: "desktop",
2151
+ properties: { surface: "web" }
2152
+ });
2153
+ }
2154
+ return captured;
2155
+ }
2156
+ function getDeepLink() {
2157
+ if (!didCapture) return captureWebDeepLink();
2158
+ return captured;
2159
+ }
2160
+ function webFingerprint() {
2161
+ const fp = { platform: "desktop" };
2162
+ if (typeof navigator !== "undefined") {
2163
+ if (navigator.userAgent) fp.user_agent = navigator.userAgent;
2164
+ const lang = navigator.language || navigator.languages && navigator.languages[0];
2165
+ if (lang) fp.language = lang;
2166
+ }
2167
+ return fp;
2168
+ }
2169
+ async function identify(identity) {
2170
+ if (!identity || Object.keys(identity).length === 0) return null;
2171
+ const res = await superlinkClient.match({
2172
+ identity,
2173
+ fingerprint: webFingerprint()
2174
+ });
2175
+ if (!res.matched) return null;
2176
+ const link = toDeepLink(res);
2177
+ emitDeferredDeepLink(link);
2178
+ return link;
2179
+ }
2180
+ async function completeFromScan(scanned) {
2181
+ if (!scanned) return null;
2182
+ const res = await superlinkClient.match({
2183
+ qr_token: scanned,
2184
+ fingerprint: webFingerprint()
2185
+ });
2186
+ if (!res.matched) return null;
2187
+ const link = toDeepLink(res);
2188
+ emitDeferredDeepLink(link);
2189
+ return link;
2190
+ }
2191
+
2192
+ // src/superlink/index.ts
2193
+ function initSuperLink(config = {}) {
2194
+ superlinkClient.configure(config);
2195
+ captureWebDeepLink();
2196
+ }
2197
+
1911
2198
  // src/index.ts
1912
2199
  function installFallbackEnvironment() {
1913
2200
  if (getEnvironment()) return;
@@ -2117,6 +2404,10 @@ var SitePongClient = class {
2117
2404
  webVitals: config.performance.webVitals,
2118
2405
  navigationTiming: config.performance.navigationTiming,
2119
2406
  resourceTiming: config.performance.resourceTiming,
2407
+ capturePageLoadTimings: config.performance.capturePageLoadTimings,
2408
+ capturePageRenderTimings: config.performance.capturePageRenderTimings,
2409
+ excludedResourceUrls: config.performance.excludedResourceUrls,
2410
+ resourceNameSanitizer: config.performance.resourceNameSanitizer,
2120
2411
  sampleRate: config.performance.sampleRate,
2121
2412
  flushInterval: config.performance.flushInterval,
2122
2413
  performanceEndpoint: config.performance.performanceEndpoint,
@@ -2825,7 +3116,7 @@ var areFlagsReady = sitepong.areFlagsReady.bind(sitepong);
2825
3116
  var refreshFlags = sitepong.refreshFlags.bind(sitepong);
2826
3117
  var track = sitepong.track.bind(sitepong);
2827
3118
  var trackPageView = sitepong.trackPageView.bind(sitepong);
2828
- var identify = sitepong.identify.bind(sitepong);
3119
+ var identify2 = sitepong.identify.bind(sitepong);
2829
3120
  var group = sitepong.group.bind(sitepong);
2830
3121
  var resetAnalytics = sitepong.resetAnalytics.bind(sitepong);
2831
3122
  var getVisitorId = sitepong.getVisitorId.bind(sitepong);
@@ -3037,7 +3328,7 @@ function useTrackPageView() {
3037
3328
  function useIdentify() {
3038
3329
  return useCallback(
3039
3330
  (userId, traits) => {
3040
- identify(userId, traits);
3331
+ identify2(userId, traits);
3041
3332
  },
3042
3333
  []
3043
3334
  );
@@ -3233,6 +3524,6 @@ function useReplay() {
3233
3524
  return { recording, start, stop };
3234
3525
  }
3235
3526
 
3236
- export { SitePongContext, SitePongErrorBoundary, SitePongProvider, TracePropagator, addBreadcrumb, areFlagsReady, captureError, captureMessage, clearAnonymousId, clearUser, sitepong as client, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, endSpan, endTransaction, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload2 as getVariantPayload, getVisitorId, getWebVitals, group, identify, init, initRN, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onRemoteConfigChange, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, stopReplay, track, trackPageView, useAddBreadcrumb, useAllFlags, useCaptureException, useCaptureMessage, useErrorCapture, useExperiment, useFeatureFlag, useFeatureFlagPayload, useFraudCheck, useGroup, useIdentify, usePerformanceTransaction, useReplay, useSetUser, useSitePong, useTrack, useTrackPageView, useVisitorId, useWebVitals, waitForFlags };
3527
+ export { DEFAULT_SUPERLINK_ENDPOINT, SitePongContext, SitePongErrorBoundary, SitePongProvider, SuperLinkClient, TracePropagator, addBreadcrumb, areFlagsReady, captureError, captureMessage, captureWebDeepLink, clearAnonymousId, clearUser, sitepong as client, completeFromScan, createTraceContext, cronCheckin, cronStart, cronWrap, dbTrack, dbTrackSync, endSpan, endTransaction, extractIdentityMetadata, extractTrace, flush, flushMetrics, flushProfiles, generateSpanId, generateTraceId, getAllFlags, getAnonymousId, getDbNPlusOnePatterns, getDbQueryCount, getDeepLink, getDeviceSignals, getFlag, getFraudCheck, getLatestProfile, getMatchedDeepLink, getProfiles, getRemoteConfig, getReplaySessionId, getVariant, getVariantPayload2 as getVariantPayload, getVisitorId, getWebVitals, group, identify2 as identify, init, initRN, initSuperLink, isInitialized, isRemoteConfigFeatureEnabled, isReplayRecording, metricDistribution, metricGauge, metricHistogram, metricIncrement, metricStartTimer, metricTime, onDeferredDeepLink, onRemoteConfigChange, parseUniversalLink, profile, propagateTrace, refreshFlags, registerIdentifyHook, registerWebManagerFactories, resetAnalytics, resetDbQueryCount, setAnonymousId, setContext, setCurrentScreen, setEnvironment, setRNGetCurrentScreen, setTags, setUser, startProfileSpan, startReplay, startSpan, startTransaction, stopReplay, superlinkClient, identify as superlinkIdentify, track, trackPageView, useAddBreadcrumb, useAllFlags, useCaptureException, useCaptureMessage, useErrorCapture, useExperiment, useFeatureFlag, useFeatureFlagPayload, useFraudCheck, useGroup, useIdentify, usePerformanceTransaction, useReplay, useSetUser, useSitePong, useTrack, useTrackPageView, useVisitorId, useWebVitals, waitForFlags, writeClipboardToken };
3237
3528
  //# sourceMappingURL=index.mjs.map
3238
3529
  //# sourceMappingURL=index.mjs.map