@nuxt/scripts 1.0.0-beta.23 → 1.0.0-beta.25
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/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/{Bh9fd9qr.js → C-7nRtzO.js} +1 -1
- package/dist/client/_nuxt/{UTi7FhVv.js → D5k4eN9O.js} +1 -1
- package/dist/client/_nuxt/DjhmCJlE.js +162 -0
- package/dist/client/_nuxt/{B7aPLMNo.js → TJ5JFHov.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/2ec0342e-5e00-4781-82aa-c3c0f9154516.json +1 -0
- package/dist/client/_nuxt/entry.C5SUNdim.css +1 -0
- package/dist/client/_nuxt/error-404.C_3_IG5y.css +1 -0
- package/dist/client/_nuxt/error-500.DSv6YikH.css +1 -0
- package/dist/client/index.html +1 -1
- package/dist/module.d.mts +6 -20
- package/dist/module.d.ts +6 -20
- package/dist/module.json +1 -1
- package/dist/module.mjs +331 -280
- package/dist/registry.mjs +121 -71
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +5 -1
- package/dist/runtime/composables/useScriptTriggerConsent.d.ts +10 -0
- package/dist/runtime/composables/useScriptTriggerConsent.js +32 -19
- package/dist/runtime/registry/bing-uet.d.ts +20 -0
- package/dist/runtime/registry/bing-uet.js +29 -0
- package/dist/runtime/registry/bluesky-embed.d.ts +1 -1
- package/dist/runtime/registry/crisp.d.ts +1 -1
- package/dist/runtime/registry/fathom-analytics.d.ts +1 -1
- package/dist/runtime/registry/google-adsense.d.ts +1 -1
- package/dist/runtime/registry/hotjar.d.ts +1 -1
- package/dist/runtime/registry/instagram-embed.d.ts +1 -1
- package/dist/runtime/registry/intercom.d.ts +1 -1
- package/dist/runtime/registry/matomo-analytics.d.ts +1 -1
- package/dist/runtime/registry/meta-pixel.d.ts +1 -1
- package/dist/runtime/registry/mixpanel-analytics.d.ts +22 -0
- package/dist/runtime/registry/mixpanel-analytics.js +46 -0
- package/dist/runtime/registry/npm.d.ts +1 -1
- package/dist/runtime/registry/reddit-pixel.d.ts +1 -1
- package/dist/runtime/registry/schemas.d.ts +19 -0
- package/dist/runtime/registry/schemas.js +19 -0
- package/dist/runtime/registry/snapchat-pixel.d.ts +1 -1
- package/dist/runtime/registry/tiktok-pixel.d.ts +1 -1
- package/dist/runtime/registry/vercel-analytics.d.ts +1 -1
- package/dist/runtime/registry/x-embed.d.ts +1 -1
- package/dist/runtime/registry/x-pixel.d.ts +1 -1
- package/dist/runtime/server/proxy-handler.js +36 -23
- package/dist/runtime/server/utils/privacy.d.ts +1 -2
- package/dist/runtime/server/utils/privacy.js +9 -11
- package/dist/runtime/types.d.ts +30 -18
- package/dist/runtime/utils/pure.d.ts +1 -1
- package/dist/runtime/utils.js +1 -1
- package/dist/shared/scripts.ViOoYQXH.mjs +381 -0
- package/dist/stats.d.mts +78 -3
- package/dist/stats.d.ts +78 -3
- package/dist/stats.mjs +2261 -162
- package/dist/types-source.mjs +47 -0
- package/package.json +13 -13
- package/dist/client/_nuxt/BNNMZFwZ.js +0 -162
- package/dist/client/_nuxt/builds/meta/39ee5395-65bb-4a46-82e0-e68853f94418.json +0 -1
- package/dist/client/_nuxt/entry.CACgbLJl.css +0 -1
- package/dist/client/_nuxt/error-404.DMdWw4vT.css +0 -1
- package/dist/client/_nuxt/error-500.CROTF27X.css +0 -1
- package/dist/shared/scripts.Crpn87WB.mjs +0 -318
package/dist/runtime/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Script } from '@unhead/vue/types';
|
|
|
3
3
|
import type { Import } from 'unimport';
|
|
4
4
|
import type { InferInput, ObjectSchema, UnionSchema, ValiError } from 'valibot';
|
|
5
5
|
import type { ComputedRef, Ref } from 'vue';
|
|
6
|
+
import type { BingUetInput } from './registry/bing-uet.js';
|
|
6
7
|
import type { BlueskyEmbedInput } from './registry/bluesky-embed.js';
|
|
7
8
|
import type { ClarityInput } from './registry/clarity.js';
|
|
8
9
|
import type { CloudflareWebAnalyticsInput } from './registry/cloudflare-web-analytics.js';
|
|
@@ -17,10 +18,12 @@ import type { GoogleSignInInput } from './registry/google-sign-in.js';
|
|
|
17
18
|
import type { GoogleTagManagerInput } from './registry/google-tag-manager.js';
|
|
18
19
|
import type { GravatarInput } from './registry/gravatar.js';
|
|
19
20
|
import type { HotjarInput } from './registry/hotjar.js';
|
|
21
|
+
import type { InstagramEmbedInput } from './registry/instagram-embed.js';
|
|
20
22
|
import type { IntercomInput } from './registry/intercom.js';
|
|
21
23
|
import type { LemonSqueezyInput } from './registry/lemon-squeezy.js';
|
|
22
24
|
import type { MatomoAnalyticsInput } from './registry/matomo-analytics.js';
|
|
23
25
|
import type { MetaPixelInput } from './registry/meta-pixel.js';
|
|
26
|
+
import type { MixpanelAnalyticsInput } from './registry/mixpanel-analytics.js';
|
|
24
27
|
import type { NpmInput } from './registry/npm.js';
|
|
25
28
|
import type { PayPalInput } from './registry/paypal.js';
|
|
26
29
|
import type { PlausibleAnalyticsInput } from './registry/plausible-analytics.js';
|
|
@@ -34,6 +37,7 @@ import type { TikTokPixelInput } from './registry/tiktok-pixel.js';
|
|
|
34
37
|
import type { UmamiAnalyticsInput } from './registry/umami-analytics.js';
|
|
35
38
|
import type { VercelAnalyticsInput } from './registry/vercel-analytics.js';
|
|
36
39
|
import type { VimeoPlayerInput } from './registry/vimeo-player.js';
|
|
40
|
+
import type { XEmbedInput } from './registry/x-embed.js';
|
|
37
41
|
import type { XPixelInput } from './registry/x-pixel.js';
|
|
38
42
|
import type { YouTubePlayerInput } from './registry/youtube-player.js';
|
|
39
43
|
export type WarmupStrategy = false | 'preload' | 'preconnect' | 'dns-prefetch';
|
|
@@ -156,13 +160,16 @@ export interface NuxtDevToolsScriptInstance {
|
|
|
156
160
|
}[];
|
|
157
161
|
}
|
|
158
162
|
export interface ScriptRegistry {
|
|
163
|
+
bingUet?: BingUetInput;
|
|
159
164
|
blueskyEmbed?: BlueskyEmbedInput;
|
|
165
|
+
carbonAds?: true;
|
|
160
166
|
crisp?: CrispInput;
|
|
161
167
|
clarity?: ClarityInput;
|
|
162
168
|
cloudflareWebAnalytics?: CloudflareWebAnalyticsInput;
|
|
163
169
|
databuddyAnalytics?: DatabuddyAnalyticsInput;
|
|
164
170
|
metaPixel?: MetaPixelInput;
|
|
165
171
|
fathomAnalytics?: FathomAnalyticsInput;
|
|
172
|
+
instagramEmbed?: InstagramEmbedInput;
|
|
166
173
|
plausibleAnalytics?: PlausibleAnalyticsInput;
|
|
167
174
|
googleAdsense?: GoogleAdsenseInput;
|
|
168
175
|
googleAnalytics?: GoogleAnalyticsInput;
|
|
@@ -176,11 +183,13 @@ export interface ScriptRegistry {
|
|
|
176
183
|
paypal?: PayPalInput;
|
|
177
184
|
posthog?: PostHogInput;
|
|
178
185
|
matomoAnalytics?: MatomoAnalyticsInput;
|
|
186
|
+
mixpanelAnalytics?: MixpanelAnalyticsInput;
|
|
179
187
|
rybbitAnalytics?: RybbitAnalyticsInput;
|
|
180
188
|
redditPixel?: RedditPixelInput;
|
|
181
189
|
segment?: SegmentInput;
|
|
182
190
|
stripe?: StripeInput;
|
|
183
191
|
tiktokPixel?: TikTokPixelInput;
|
|
192
|
+
xEmbed?: XEmbedInput;
|
|
184
193
|
xPixel?: XPixelInput;
|
|
185
194
|
snapchatPixel?: SnapTrPixelInput;
|
|
186
195
|
youtubePlayer?: YouTubePlayerInput;
|
|
@@ -188,9 +197,20 @@ export interface ScriptRegistry {
|
|
|
188
197
|
vimeoPlayer?: VimeoPlayerInput;
|
|
189
198
|
umamiAnalytics?: UmamiAnalyticsInput;
|
|
190
199
|
gravatar?: GravatarInput;
|
|
200
|
+
npm?: NpmInput;
|
|
191
201
|
[key: `${string}-npm`]: NpmInput;
|
|
192
202
|
}
|
|
193
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Built-in registry script keys — not affected by module augmentation.
|
|
205
|
+
* Use this to type-check records that must enumerate all built-in scripts (logos, meta, etc.).
|
|
206
|
+
*/
|
|
207
|
+
export type BuiltInRegistryScriptKey = 'bingUet' | 'blueskyEmbed' | 'carbonAds' | 'crisp' | 'clarity' | 'cloudflareWebAnalytics' | 'databuddyAnalytics' | 'metaPixel' | 'fathomAnalytics' | 'instagramEmbed' | 'plausibleAnalytics' | 'googleAdsense' | 'googleAnalytics' | 'googleMaps' | 'googleRecaptcha' | 'googleSignIn' | 'lemonSqueezy' | 'googleTagManager' | 'hotjar' | 'intercom' | 'paypal' | 'posthog' | 'matomoAnalytics' | 'mixpanelAnalytics' | 'rybbitAnalytics' | 'redditPixel' | 'segment' | 'stripe' | 'tiktokPixel' | 'xEmbed' | 'xPixel' | 'snapchatPixel' | 'youtubePlayer' | 'vercelAnalytics' | 'vimeoPlayer' | 'umamiAnalytics' | 'gravatar' | 'npm';
|
|
208
|
+
/**
|
|
209
|
+
* Union of all explicit registry script keys (excludes npm pattern).
|
|
210
|
+
* Includes both built-in and augmented keys.
|
|
211
|
+
*/
|
|
212
|
+
export type RegistryScriptKey = Exclude<keyof ScriptRegistry, `${string}-npm`>;
|
|
213
|
+
export type NuxtConfigScriptRegistryEntry<T> = true | false | 'mock' | T | [T, NuxtUseScriptOptionsSerializable];
|
|
194
214
|
export type NuxtConfigScriptRegistry<T extends keyof ScriptRegistry = keyof ScriptRegistry> = Partial<{
|
|
195
215
|
[key in T]: NuxtConfigScriptRegistryEntry<ScriptRegistry[key]>;
|
|
196
216
|
}> & Record<string & {}, NuxtConfigScriptRegistryEntry<any>>;
|
|
@@ -201,21 +221,15 @@ declare const _emptyOptions: ObjectSchema<{}, undefined>;
|
|
|
201
221
|
export type EmptyOptionsSchema = typeof _emptyOptions;
|
|
202
222
|
type ScriptInput = Script;
|
|
203
223
|
export type InferIfSchema<T> = T extends ObjectSchema<any, any> | UnionSchema<any, any> ? InferInput<T> : T;
|
|
204
|
-
export
|
|
224
|
+
export interface RegistryScriptInputExtras<Bundelable extends boolean = true, Usable extends boolean = false> {
|
|
205
225
|
/**
|
|
206
226
|
* A unique key to use for the script, this can be used to load multiple of the same script with different options.
|
|
207
227
|
*/
|
|
208
228
|
key?: string;
|
|
209
229
|
scriptInput?: ScriptInput;
|
|
210
230
|
scriptOptions?: Omit<NuxtUseScriptOptions, Bundelable extends true ? '' : 'bundle' | Usable extends true ? '' : 'use'>;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
* A unique key to use for the script, this can be used to load multiple of the same script with different options.
|
|
214
|
-
*/
|
|
215
|
-
key?: string;
|
|
216
|
-
scriptInput: Required<Pick<ScriptInput, 'src'>> & ScriptInput;
|
|
217
|
-
scriptOptions?: Omit<NuxtUseScriptOptions, Bundelable extends true ? '' : 'bundle' | Usable extends true ? '' : 'use'>;
|
|
218
|
-
} : never);
|
|
231
|
+
}
|
|
232
|
+
export type RegistryScriptInput<T = EmptyOptionsSchema, Bundelable extends boolean = true, Usable extends boolean = false> = Partial<InferIfSchema<T>> & RegistryScriptInputExtras<Bundelable, Usable>;
|
|
219
233
|
export interface RegistryScriptServerHandler {
|
|
220
234
|
route: string;
|
|
221
235
|
handler: string;
|
|
@@ -226,20 +240,18 @@ export interface RegistryScript {
|
|
|
226
240
|
* The config key used in `scripts.registry` in nuxt.config (e.g., 'googleAnalytics', 'plausibleAnalytics').
|
|
227
241
|
* Used for direct lookup from config to script — avoids fragile import name convention matching.
|
|
228
242
|
*/
|
|
229
|
-
registryKey?:
|
|
243
|
+
registryKey?: RegistryScriptKey;
|
|
230
244
|
import?: Import;
|
|
231
245
|
scriptBundling?: false | ((options?: any) => string | false);
|
|
232
246
|
/**
|
|
233
|
-
* First-party
|
|
234
|
-
*
|
|
235
|
-
* - `false` - Explicitly disable first-party routing for this script
|
|
236
|
-
* - `undefined` - Use the default key derived from the function name
|
|
247
|
+
* First-party proxy config alias. Only needed when a script shares another script's
|
|
248
|
+
* proxy config (e.g., googleAdsense uses `proxy: 'googleAnalytics'`).
|
|
237
249
|
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
250
|
+
* By default, the proxy config is looked up by `registryKey`. Set to `false` to
|
|
251
|
+
* explicitly disable first-party routing for this script.
|
|
240
252
|
* @internal
|
|
241
253
|
*/
|
|
242
|
-
proxy?:
|
|
254
|
+
proxy?: RegistryScriptKey | false;
|
|
243
255
|
label?: string;
|
|
244
256
|
src?: string | false;
|
|
245
257
|
category?: string;
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
export interface ProxyRewrite {
|
|
5
5
|
/** Domain and path to match (e.g., 'www.google-analytics.com/g/collect') */
|
|
6
6
|
from: string;
|
|
7
|
-
/** Local path to rewrite to (e.g., '/_scripts/
|
|
7
|
+
/** Local path to rewrite to (e.g., '/_scripts/p/ga/g/collect') */
|
|
8
8
|
to: string;
|
|
9
9
|
}
|
package/dist/runtime/utils.js
CHANGED
|
@@ -32,7 +32,7 @@ export function requireRegistryEndpoint(componentName, registryKey) {
|
|
|
32
32
|
}
|
|
33
33
|
export function useRegistryScript(registryKey, optionsFn, _userOptions) {
|
|
34
34
|
const scriptConfig = scriptRuntimeConfig(registryKey);
|
|
35
|
-
const userOptions =
|
|
35
|
+
const userOptions = defu(_userOptions || {}, typeof scriptConfig === "object" ? scriptConfig : {});
|
|
36
36
|
const options = optionsFn(userOptions, { scriptInput: userOptions.scriptInput });
|
|
37
37
|
if (options.scriptMode === "npm") {
|
|
38
38
|
return createNpmScriptStub({
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
const GA_COLLECT_RE = /([\w$])?"https:\/\/"\+\(.*?\)\+"\.google-analytics\.com\/g\/collect"/g;
|
|
2
|
+
const GA_ANALYTICS_COLLECT_RE = /([\w$])?"https:\/\/"\+\(.*?\)\+"\.analytics\.google\.com\/g\/collect"/g;
|
|
3
|
+
const FATHOM_SELF_HOSTED_RE = /\.src\.indexOf\("cdn\.usefathom\.com"\)\s*<\s*0/;
|
|
4
|
+
const RYBBIT_HOST_SPLIT_RE = /\w+\.split\(["']\/script\.js["']\)\[0\]/g;
|
|
5
|
+
const PRIVACY_NONE = { ip: false, userAgent: false, language: false, screen: false, timezone: false, hardware: false };
|
|
6
|
+
const PRIVACY_FULL = { ip: true, userAgent: true, language: true, screen: true, timezone: true, hardware: true };
|
|
7
|
+
const PRIVACY_HEATMAP = { ip: true, userAgent: false, language: true, screen: false, timezone: false, hardware: true };
|
|
8
|
+
const PRIVACY_IP_ONLY = { ip: true, userAgent: false, language: false, screen: false, timezone: false, hardware: false };
|
|
9
|
+
function deriveRewrites(domains, proxyPrefix) {
|
|
10
|
+
return domains.map(([domain, alias]) => ({
|
|
11
|
+
from: domain,
|
|
12
|
+
to: `${proxyPrefix}/${alias}`
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
function deriveRoutes(domains, proxyPrefix) {
|
|
16
|
+
const routes = {};
|
|
17
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18
|
+
for (const [domain, alias] of domains) {
|
|
19
|
+
if (seen.has(alias))
|
|
20
|
+
continue;
|
|
21
|
+
seen.add(alias);
|
|
22
|
+
routes[`${proxyPrefix}/${alias}/**`] = { proxy: `https://${domain}/**` };
|
|
23
|
+
}
|
|
24
|
+
return routes;
|
|
25
|
+
}
|
|
26
|
+
function fromDomains(domains, proxyPrefix, opts) {
|
|
27
|
+
const { extraRewrites, ...rest } = opts;
|
|
28
|
+
const rewrites = deriveRewrites(domains, proxyPrefix);
|
|
29
|
+
if (extraRewrites) {
|
|
30
|
+
for (const r of extraRewrites)
|
|
31
|
+
rewrites.push({ from: r.from, to: `${proxyPrefix}/${r.to}` });
|
|
32
|
+
}
|
|
33
|
+
return { rewrite: rewrites, routes: deriveRoutes(domains, proxyPrefix), ...rest };
|
|
34
|
+
}
|
|
35
|
+
function buildProxyConfig(proxyPrefix) {
|
|
36
|
+
return {
|
|
37
|
+
googleAnalytics: fromDomains(
|
|
38
|
+
[
|
|
39
|
+
["www.google-analytics.com", "ga"],
|
|
40
|
+
["analytics.google.com", "ga"],
|
|
41
|
+
["stats.g.doubleclick.net", "ga-dc"],
|
|
42
|
+
["pagead2.googlesyndication.com", "ga-syn"],
|
|
43
|
+
["www.googleadservices.com", "ga-ads"],
|
|
44
|
+
["googleads.g.doubleclick.net", "ga-gads"]
|
|
45
|
+
],
|
|
46
|
+
proxyPrefix,
|
|
47
|
+
{
|
|
48
|
+
// GA4: screen/timezone/UA needed for device, time, and OS reports; rest anonymized safely
|
|
49
|
+
privacy: PRIVACY_HEATMAP,
|
|
50
|
+
extraRewrites: [
|
|
51
|
+
// Modern gtag.js uses www.google.com/g/collect
|
|
52
|
+
{ from: "www.google.com/g/collect", to: "ga/g/collect" },
|
|
53
|
+
// Suffix patterns for dynamically constructed URLs
|
|
54
|
+
{ from: ".google-analytics.com/g/collect", to: "ga/g/collect" },
|
|
55
|
+
{ from: ".analytics.google.com/g/collect", to: "ga/g/collect" },
|
|
56
|
+
// Full domain + path patterns
|
|
57
|
+
{ from: "www.google-analytics.com/g/collect", to: "ga/g/collect" },
|
|
58
|
+
{ from: "analytics.google.com/g/collect", to: "ga/g/collect" },
|
|
59
|
+
// DoubleClick collect endpoint
|
|
60
|
+
{ from: "stats.g.doubleclick.net/g/collect", to: "ga/g/collect" }
|
|
61
|
+
],
|
|
62
|
+
// GA4 dynamically constructs collect URLs via string concatenation that can't be
|
|
63
|
+
// caught by AST rewriting. These regex patches handle the remaining patterns.
|
|
64
|
+
postProcess(output, rewrites) {
|
|
65
|
+
const gaRewrite = rewrites.find((r) => r.from.includes("google-analytics.com/g/collect"));
|
|
66
|
+
if (gaRewrite) {
|
|
67
|
+
output = output.replace(
|
|
68
|
+
GA_COLLECT_RE,
|
|
69
|
+
(_, prevChar) => `${prevChar ? `${prevChar} ` : ""}self.location.origin+"${gaRewrite.to}"`
|
|
70
|
+
);
|
|
71
|
+
output = output.replace(
|
|
72
|
+
GA_ANALYTICS_COLLECT_RE,
|
|
73
|
+
(_, prevChar) => `${prevChar ? `${prevChar} ` : ""}self.location.origin+"${gaRewrite.to}"`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return output;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
googleTagManager: fromDomains(
|
|
81
|
+
[["www.googletagmanager.com", "gtm"]],
|
|
82
|
+
proxyPrefix,
|
|
83
|
+
{ privacy: PRIVACY_NONE }
|
|
84
|
+
),
|
|
85
|
+
metaPixel: fromDomains(
|
|
86
|
+
[
|
|
87
|
+
["connect.facebook.net", "meta"],
|
|
88
|
+
["www.facebook.com/tr", "meta-tr"],
|
|
89
|
+
["facebook.com/tr", "meta-tr"],
|
|
90
|
+
["pixel.facebook.com", "meta-px"],
|
|
91
|
+
["www.facebook.com/plugins", "meta-plugins"]
|
|
92
|
+
],
|
|
93
|
+
proxyPrefix,
|
|
94
|
+
{ privacy: PRIVACY_FULL }
|
|
95
|
+
),
|
|
96
|
+
tiktokPixel: fromDomains(
|
|
97
|
+
[["analytics.tiktok.com", "tiktok"]],
|
|
98
|
+
proxyPrefix,
|
|
99
|
+
{ privacy: PRIVACY_FULL }
|
|
100
|
+
),
|
|
101
|
+
segment: fromDomains(
|
|
102
|
+
[
|
|
103
|
+
["api.segment.io", "segment"],
|
|
104
|
+
["cdn.segment.com", "segment-cdn"]
|
|
105
|
+
],
|
|
106
|
+
proxyPrefix,
|
|
107
|
+
{ privacy: PRIVACY_NONE }
|
|
108
|
+
),
|
|
109
|
+
xPixel: fromDomains(
|
|
110
|
+
[
|
|
111
|
+
["analytics.twitter.com", "x"],
|
|
112
|
+
["static.ads-twitter.com", "x-ads"],
|
|
113
|
+
["t.co", "x-t"]
|
|
114
|
+
],
|
|
115
|
+
proxyPrefix,
|
|
116
|
+
{ privacy: PRIVACY_FULL }
|
|
117
|
+
),
|
|
118
|
+
snapchatPixel: fromDomains(
|
|
119
|
+
[
|
|
120
|
+
["sc-static.net", "snap-cdn"],
|
|
121
|
+
["tr.snapchat.com", "snap"],
|
|
122
|
+
["pixel.tapad.com", "snap-tapad"]
|
|
123
|
+
],
|
|
124
|
+
proxyPrefix,
|
|
125
|
+
{ privacy: PRIVACY_FULL }
|
|
126
|
+
),
|
|
127
|
+
redditPixel: fromDomains(
|
|
128
|
+
[
|
|
129
|
+
["www.redditstatic.com", "reddit-cdn"],
|
|
130
|
+
["alb.reddit.com", "reddit"],
|
|
131
|
+
["pixel-config.reddit.com", "reddit-cfg"]
|
|
132
|
+
],
|
|
133
|
+
proxyPrefix,
|
|
134
|
+
{ privacy: PRIVACY_FULL }
|
|
135
|
+
),
|
|
136
|
+
clarity: fromDomains(
|
|
137
|
+
[
|
|
138
|
+
["www.clarity.ms", "clarity"],
|
|
139
|
+
["scripts.clarity.ms", "clarity-scripts"],
|
|
140
|
+
["d.clarity.ms", "clarity-data"],
|
|
141
|
+
["e.clarity.ms", "clarity-events"],
|
|
142
|
+
["k.clarity.ms", "clarity-collect"]
|
|
143
|
+
],
|
|
144
|
+
proxyPrefix,
|
|
145
|
+
{ privacy: PRIVACY_HEATMAP }
|
|
146
|
+
),
|
|
147
|
+
posthog: {
|
|
148
|
+
// No rewrites needed - PostHog uses NPM mode, SDK URLs are set via api_host config
|
|
149
|
+
privacy: PRIVACY_NONE,
|
|
150
|
+
routes: {
|
|
151
|
+
// US region
|
|
152
|
+
[`${proxyPrefix}/ph/static/**`]: { proxy: "https://us-assets.i.posthog.com/static/**" },
|
|
153
|
+
[`${proxyPrefix}/ph/**`]: { proxy: "https://us.i.posthog.com/**" },
|
|
154
|
+
// EU region
|
|
155
|
+
[`${proxyPrefix}/ph-eu/static/**`]: { proxy: "https://eu-assets.i.posthog.com/static/**" },
|
|
156
|
+
[`${proxyPrefix}/ph-eu/**`]: { proxy: "https://eu.i.posthog.com/**" }
|
|
157
|
+
},
|
|
158
|
+
autoInject: {
|
|
159
|
+
configField: "apiHost",
|
|
160
|
+
computeValue: (proxyPrefix2, config) => {
|
|
161
|
+
const region = config.region || "us";
|
|
162
|
+
return region === "eu" ? `${proxyPrefix2}/ph-eu` : `${proxyPrefix2}/ph`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
hotjar: fromDomains(
|
|
167
|
+
[
|
|
168
|
+
["static.hotjar.com", "hotjar"],
|
|
169
|
+
["script.hotjar.com", "hotjar-script"],
|
|
170
|
+
["vars.hotjar.com", "hotjar-vars"],
|
|
171
|
+
["in.hotjar.com", "hotjar-in"],
|
|
172
|
+
["vc.hotjar.com", "hotjar-vc"],
|
|
173
|
+
["vc.hotjar.io", "hotjar-vc"],
|
|
174
|
+
["metrics.hotjar.io", "hotjar-metrics"],
|
|
175
|
+
["insights.hotjar.com", "hotjar-insights"],
|
|
176
|
+
["ask.hotjar.io", "hotjar-ask"],
|
|
177
|
+
["events.hotjar.io", "hotjar-events"],
|
|
178
|
+
["identify.hotjar.com", "hotjar-identify"],
|
|
179
|
+
["surveystats.hotjar.io", "hotjar-surveys"]
|
|
180
|
+
],
|
|
181
|
+
proxyPrefix,
|
|
182
|
+
{ privacy: PRIVACY_HEATMAP }
|
|
183
|
+
),
|
|
184
|
+
plausibleAnalytics: fromDomains(
|
|
185
|
+
[["plausible.io", "plausible"]],
|
|
186
|
+
proxyPrefix,
|
|
187
|
+
{
|
|
188
|
+
privacy: PRIVACY_NONE,
|
|
189
|
+
autoInject: {
|
|
190
|
+
configField: "endpoint",
|
|
191
|
+
computeValue: (proxyPrefix2) => `${proxyPrefix2}/plausible/api/event`
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
cloudflareWebAnalytics: fromDomains(
|
|
196
|
+
[
|
|
197
|
+
["static.cloudflareinsights.com", "cfwa"],
|
|
198
|
+
["cloudflareinsights.com", "cfwa-beacon"]
|
|
199
|
+
],
|
|
200
|
+
proxyPrefix,
|
|
201
|
+
{ privacy: PRIVACY_NONE }
|
|
202
|
+
),
|
|
203
|
+
rybbitAnalytics: fromDomains(
|
|
204
|
+
[["app.rybbit.io", "rybbit"]],
|
|
205
|
+
proxyPrefix,
|
|
206
|
+
{
|
|
207
|
+
privacy: PRIVACY_NONE,
|
|
208
|
+
autoInject: {
|
|
209
|
+
configField: "analyticsHost",
|
|
210
|
+
computeValue: (proxyPrefix2) => `${proxyPrefix2}/rybbit/api`
|
|
211
|
+
},
|
|
212
|
+
// Rybbit SDK derives API host via `e.split("/script.js")[0]` from the script tag's
|
|
213
|
+
// src attribute. When bundled, src becomes /_scripts/assets/<hash>.js so the split fails.
|
|
214
|
+
postProcess(output, rewrites) {
|
|
215
|
+
const rybbitRewrite = rewrites.find((r) => r.from === "app.rybbit.io");
|
|
216
|
+
if (rybbitRewrite) {
|
|
217
|
+
output = output.replace(
|
|
218
|
+
RYBBIT_HOST_SPLIT_RE,
|
|
219
|
+
`self.location.origin+"${rybbitRewrite.to}/api"`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
return output;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
umamiAnalytics: fromDomains(
|
|
227
|
+
[["cloud.umami.is", "umami"]],
|
|
228
|
+
proxyPrefix,
|
|
229
|
+
{
|
|
230
|
+
privacy: PRIVACY_NONE,
|
|
231
|
+
extraRewrites: [
|
|
232
|
+
{ from: "api-gateway.umami.dev", to: "umami" }
|
|
233
|
+
],
|
|
234
|
+
autoInject: {
|
|
235
|
+
configField: "hostUrl",
|
|
236
|
+
computeValue: (proxyPrefix2) => `${proxyPrefix2}/umami`
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
),
|
|
240
|
+
databuddyAnalytics: fromDomains(
|
|
241
|
+
[
|
|
242
|
+
["cdn.databuddy.cc", "databuddy"],
|
|
243
|
+
["basket.databuddy.cc", "databuddy-api"]
|
|
244
|
+
],
|
|
245
|
+
proxyPrefix,
|
|
246
|
+
{
|
|
247
|
+
privacy: PRIVACY_NONE,
|
|
248
|
+
autoInject: {
|
|
249
|
+
configField: "apiUrl",
|
|
250
|
+
computeValue: (proxyPrefix2) => `${proxyPrefix2}/databuddy-api`
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
fathomAnalytics: fromDomains(
|
|
255
|
+
[["cdn.usefathom.com", "fathom"]],
|
|
256
|
+
proxyPrefix,
|
|
257
|
+
{
|
|
258
|
+
privacy: PRIVACY_NONE,
|
|
259
|
+
// Fathom SDK checks if script src contains "cdn.usefathom.com" to detect self-hosted
|
|
260
|
+
// mode, then overrides trackerUrl with the script host's root. After AST rewrite already
|
|
261
|
+
// set trackerUrl to the proxy URL, neutralize this check so it doesn't override it.
|
|
262
|
+
postProcess(output) {
|
|
263
|
+
return output.replace(
|
|
264
|
+
FATHOM_SELF_HOSTED_RE,
|
|
265
|
+
'.src.indexOf("cdn.usefathom.com")<-1'
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
),
|
|
270
|
+
intercom: fromDomains(
|
|
271
|
+
[
|
|
272
|
+
["widget.intercom.io", "intercom"],
|
|
273
|
+
["api-iam.intercom.io", "intercom-api"],
|
|
274
|
+
["api-iam.eu.intercom.io", "intercom-api-eu"],
|
|
275
|
+
["api-iam.au.intercom.io", "intercom-api-au"],
|
|
276
|
+
["js.intercomcdn.com", "intercom-cdn"],
|
|
277
|
+
["downloads.intercomcdn.com", "intercom-downloads"],
|
|
278
|
+
["video-messages.intercomcdn.com", "intercom-video"]
|
|
279
|
+
],
|
|
280
|
+
proxyPrefix,
|
|
281
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
282
|
+
),
|
|
283
|
+
crisp: fromDomains(
|
|
284
|
+
[
|
|
285
|
+
["client.crisp.chat", "crisp"],
|
|
286
|
+
["client.relay.crisp.chat", "crisp-relay"],
|
|
287
|
+
["assets.crisp.chat", "crisp-assets"],
|
|
288
|
+
["go.crisp.chat", "crisp-go"],
|
|
289
|
+
["image.crisp.chat", "crisp-image"]
|
|
290
|
+
],
|
|
291
|
+
proxyPrefix,
|
|
292
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
293
|
+
),
|
|
294
|
+
vercelAnalytics: fromDomains(
|
|
295
|
+
[["va.vercel-scripts.com", "vercel"]],
|
|
296
|
+
proxyPrefix,
|
|
297
|
+
{ privacy: PRIVACY_NONE }
|
|
298
|
+
),
|
|
299
|
+
gravatar: fromDomains(
|
|
300
|
+
[
|
|
301
|
+
["secure.gravatar.com", "gravatar"],
|
|
302
|
+
["gravatar.com/avatar", "gravatar-avatar"]
|
|
303
|
+
],
|
|
304
|
+
proxyPrefix,
|
|
305
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
306
|
+
),
|
|
307
|
+
carbonAds: fromDomains(
|
|
308
|
+
[["cdn.carbonads.com", "carbon"]],
|
|
309
|
+
proxyPrefix,
|
|
310
|
+
{ privacy: PRIVACY_NONE }
|
|
311
|
+
),
|
|
312
|
+
lemonSqueezy: fromDomains(
|
|
313
|
+
[["assets.lemonsqueezy.com", "lemonsqueezy"]],
|
|
314
|
+
proxyPrefix,
|
|
315
|
+
{ privacy: PRIVACY_NONE }
|
|
316
|
+
),
|
|
317
|
+
matomoAnalytics: fromDomains(
|
|
318
|
+
[["cdn.matomo.cloud", "matomo"]],
|
|
319
|
+
proxyPrefix,
|
|
320
|
+
{ privacy: PRIVACY_NONE }
|
|
321
|
+
),
|
|
322
|
+
stripe: fromDomains(
|
|
323
|
+
[["js.stripe.com", "stripe"]],
|
|
324
|
+
proxyPrefix,
|
|
325
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
326
|
+
),
|
|
327
|
+
paypal: fromDomains(
|
|
328
|
+
[["www.paypal.com", "paypal"]],
|
|
329
|
+
proxyPrefix,
|
|
330
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
331
|
+
),
|
|
332
|
+
youtubePlayer: fromDomains(
|
|
333
|
+
[["www.youtube.com", "youtube"]],
|
|
334
|
+
proxyPrefix,
|
|
335
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
336
|
+
),
|
|
337
|
+
vimeoPlayer: fromDomains(
|
|
338
|
+
[["player.vimeo.com", "vimeo"]],
|
|
339
|
+
proxyPrefix,
|
|
340
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
341
|
+
),
|
|
342
|
+
googleRecaptcha: {
|
|
343
|
+
privacy: PRIVACY_IP_ONLY,
|
|
344
|
+
rewrite: [
|
|
345
|
+
{ from: "www.gstatic.com", to: `${proxyPrefix}/gstatic` },
|
|
346
|
+
// www.google.com is shared with GA — only rewrite /recaptcha paths
|
|
347
|
+
{ from: "www.google.com/recaptcha", to: `${proxyPrefix}/grecaptcha` },
|
|
348
|
+
{ from: "www.recaptcha.net/recaptcha", to: `${proxyPrefix}/grecaptcha` }
|
|
349
|
+
],
|
|
350
|
+
routes: {
|
|
351
|
+
[`${proxyPrefix}/gstatic/**`]: { proxy: "https://www.gstatic.com/**" },
|
|
352
|
+
[`${proxyPrefix}/grecaptcha/**`]: { proxy: "https://www.google.com/recaptcha/**" }
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
googleSignIn: fromDomains(
|
|
356
|
+
[["accounts.google.com", "gsignin"]],
|
|
357
|
+
proxyPrefix,
|
|
358
|
+
{ privacy: PRIVACY_IP_ONLY }
|
|
359
|
+
)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function getAllProxyConfigs(proxyPrefix) {
|
|
363
|
+
return buildProxyConfig(proxyPrefix);
|
|
364
|
+
}
|
|
365
|
+
const PROXY_URL_RE = /^https?:\/\/([^/]+)(\/.*)?\/\*\*$/;
|
|
366
|
+
const ROUTE_WILDCARD_RE = /\/\*\*$/;
|
|
367
|
+
function routesToInterceptRules(routes) {
|
|
368
|
+
const rules = [];
|
|
369
|
+
for (const [localPath, { proxy }] of Object.entries(routes)) {
|
|
370
|
+
const match = proxy.match(PROXY_URL_RE);
|
|
371
|
+
if (match?.[1]) {
|
|
372
|
+
const domain = match[1];
|
|
373
|
+
const pathPrefix = match[2] || "";
|
|
374
|
+
const target = localPath.replace(ROUTE_WILDCARD_RE, "");
|
|
375
|
+
rules.push({ pattern: domain, pathPrefix, target });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return rules;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export { getAllProxyConfigs as g, routesToInterceptRules as r };
|
package/dist/stats.d.mts
CHANGED
|
@@ -17,6 +17,74 @@ interface ScriptSizeDetail {
|
|
|
17
17
|
initiatorType: string;
|
|
18
18
|
protocol: string;
|
|
19
19
|
}
|
|
20
|
+
interface ScriptApis {
|
|
21
|
+
cookies: boolean;
|
|
22
|
+
localStorage: boolean;
|
|
23
|
+
sessionStorage: boolean;
|
|
24
|
+
indexedDB: boolean;
|
|
25
|
+
canvas: boolean;
|
|
26
|
+
webgl: boolean;
|
|
27
|
+
audioContext: boolean;
|
|
28
|
+
userAgent: boolean;
|
|
29
|
+
hardwareConcurrency: boolean;
|
|
30
|
+
deviceMemory: boolean;
|
|
31
|
+
plugins: boolean;
|
|
32
|
+
languages: boolean;
|
|
33
|
+
screen: boolean;
|
|
34
|
+
sendBeacon: boolean;
|
|
35
|
+
fetch: boolean;
|
|
36
|
+
xhr: boolean;
|
|
37
|
+
websocket: boolean;
|
|
38
|
+
mutationObserver: boolean;
|
|
39
|
+
performanceObserver: boolean;
|
|
40
|
+
intersectionObserver: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface ApiPrivacyScore {
|
|
43
|
+
/** 0–100, higher = more invasive */
|
|
44
|
+
score: number;
|
|
45
|
+
/** Persistence APIs used (cookies, localStorage, sessionStorage, indexedDB) */
|
|
46
|
+
persistence: number;
|
|
47
|
+
/** Fingerprinting APIs used (canvas, webgl, audioContext, deviceMemory, hardwareConcurrency, plugins, screen, userAgent, languages) */
|
|
48
|
+
fingerprinting: number;
|
|
49
|
+
/** Behavioral monitoring APIs used (mutationObserver, intersectionObserver) */
|
|
50
|
+
monitoring: number;
|
|
51
|
+
}
|
|
52
|
+
interface ScriptCookie {
|
|
53
|
+
name: string;
|
|
54
|
+
domain: string;
|
|
55
|
+
path: string;
|
|
56
|
+
httpOnly: boolean;
|
|
57
|
+
secure: boolean;
|
|
58
|
+
sameSite: string;
|
|
59
|
+
session: boolean;
|
|
60
|
+
lifetimeDays: number;
|
|
61
|
+
firstParty: boolean;
|
|
62
|
+
}
|
|
63
|
+
interface NetworkSummary {
|
|
64
|
+
requestCount: number;
|
|
65
|
+
domains: string[];
|
|
66
|
+
outboundBytes: number;
|
|
67
|
+
inboundBytes: number;
|
|
68
|
+
injectedElements: {
|
|
69
|
+
tag: string;
|
|
70
|
+
src: string;
|
|
71
|
+
}[];
|
|
72
|
+
}
|
|
73
|
+
interface CwvEstimate {
|
|
74
|
+
/** Estimated LCP delay: scriptDurationMs blocks rendering during page load */
|
|
75
|
+
lcpImpactMs: number;
|
|
76
|
+
/** CLS risk: true if script injects visible DOM elements (iframes, images) without reserved space */
|
|
77
|
+
clsRisk: boolean;
|
|
78
|
+
/** Number of visible elements injected that could cause layout shifts */
|
|
79
|
+
clsElements: number;
|
|
80
|
+
/** INP risk level based on script weight + DOM observation */
|
|
81
|
+
inpRiskLevel: 'low' | 'medium' | 'high';
|
|
82
|
+
}
|
|
83
|
+
interface PerformanceSummary {
|
|
84
|
+
taskDurationMs: number;
|
|
85
|
+
scriptDurationMs: number;
|
|
86
|
+
heapDeltaKb: number;
|
|
87
|
+
}
|
|
20
88
|
interface ScriptStats {
|
|
21
89
|
id: string;
|
|
22
90
|
label: string;
|
|
@@ -25,10 +93,17 @@ interface ScriptStats {
|
|
|
25
93
|
totalTransferKb: number;
|
|
26
94
|
totalDecodedKb: number;
|
|
27
95
|
trackedData: TrackedDataType[];
|
|
96
|
+
collectsWebVitals: boolean;
|
|
97
|
+
apis: ScriptApis;
|
|
98
|
+
apiPrivacyScore: ApiPrivacyScore;
|
|
99
|
+
cookies: ScriptCookie[];
|
|
100
|
+
network: NetworkSummary;
|
|
101
|
+
performance: PerformanceSummary;
|
|
102
|
+
cwvEstimate: CwvEstimate;
|
|
28
103
|
hasBundling: boolean;
|
|
29
104
|
hasProxy: boolean;
|
|
30
|
-
|
|
31
|
-
|
|
105
|
+
proxyDomains: string[];
|
|
106
|
+
proxyEndpoints: number;
|
|
32
107
|
privacy: ScriptPrivacy | null;
|
|
33
108
|
privacyLevel: 'full' | 'partial' | 'none' | 'unknown';
|
|
34
109
|
loadingMethod: 'cdn' | 'npm' | 'dynamic';
|
|
@@ -36,4 +111,4 @@ interface ScriptStats {
|
|
|
36
111
|
declare function getScriptStats(): Promise<ScriptStats[]>;
|
|
37
112
|
|
|
38
113
|
export { getScriptStats };
|
|
39
|
-
export type { ScriptPrivacy, ScriptSizeDetail, ScriptStats, TrackedDataType };
|
|
114
|
+
export type { ApiPrivacyScore, CwvEstimate, NetworkSummary, PerformanceSummary, ScriptApis, ScriptCookie, ScriptPrivacy, ScriptSizeDetail, ScriptStats, TrackedDataType };
|