@nuxt/scripts 1.1.1 → 1.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/devtools-client/200.html +1 -1
- package/dist/devtools-client/404.html +1 -1
- package/dist/devtools-client/_nuxt/{CpUjVpvL.js → BTXw0v4h.js} +1 -1
- package/dist/devtools-client/_nuxt/{d96VI30H.js → Bf6N2ObH.js} +1 -1
- package/dist/devtools-client/_nuxt/C5Bq9Qgz.js +1 -0
- package/dist/devtools-client/_nuxt/{CpodaK4k.js → CSw0kWhI.js} +1 -1
- package/dist/devtools-client/_nuxt/DWvCkA0U.js +195 -0
- package/dist/devtools-client/_nuxt/{CZLtBO2f.js → TPgAGQc8.js} +1 -1
- package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
- package/dist/devtools-client/_nuxt/builds/meta/32b705e4-fcb6-4eea-92d5-dbdced5169df.json +1 -0
- package/dist/devtools-client/_nuxt/{DkOU4Aaf.js → dvDf1_6X.js} +1 -1
- package/dist/devtools-client/_nuxt/entry.VwiedW44.css +1 -0
- package/dist/devtools-client/_nuxt/error-404.DBJH6QEN.css +1 -0
- package/dist/devtools-client/_nuxt/error-500.BIIPjeaA.css +1 -0
- package/dist/devtools-client/docs/index.html +1 -1
- package/dist/devtools-client/first-party/index.html +1 -1
- package/dist/devtools-client/index.html +1 -1
- package/dist/devtools-client/registry/index.html +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +37 -3
- package/dist/registry.mjs +16 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.d.vue.ts +18 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +7 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue.d.ts +18 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.d.vue.ts +9 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +6 -5
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue.d.ts +9 -0
- package/dist/runtime/components/ScriptGravatar.vue +2 -0
- package/dist/runtime/components/ScriptLoadingIndicator.vue +1 -1
- package/dist/runtime/components/ScriptVimeoPlayer.vue +27 -4
- package/dist/runtime/components/ScriptYouTubePlayer.vue +25 -4
- package/dist/runtime/composables/useScript.js +4 -3
- package/dist/runtime/registry/schemas.d.ts +76 -0
- package/dist/runtime/registry/schemas.js +82 -2
- package/dist/runtime/registry/speedcurve.d.ts +21 -0
- package/dist/runtime/registry/speedcurve.js +95 -0
- package/dist/runtime/registry/stripe.js +1 -1
- package/dist/runtime/server/instagram-embed.js +37 -10
- package/dist/runtime/server/proxy-handler.d.ts +1 -0
- package/dist/runtime/server/proxy-handler.js +16 -0
- package/dist/runtime/server/utils/instagram-embed.d.ts +1 -0
- package/dist/runtime/server/utils/instagram-embed.js +5 -0
- package/dist/runtime/types.d.ts +3 -1
- package/dist/runtime/utils/after-next-paint.d.ts +1 -0
- package/dist/runtime/utils/after-next-paint.js +3 -0
- package/dist/stats.d.mts +1 -1
- package/dist/stats.d.ts +1 -1
- package/dist/stats.mjs +5 -0
- package/dist/types-source.mjs +109 -3
- package/package.json +9 -4
- package/dist/devtools-client/_nuxt/B-0LGYiZ.js +0 -188
- package/dist/devtools-client/_nuxt/BHdEFiuu.js +0 -1
- package/dist/devtools-client/_nuxt/builds/meta/7cf30d77-8399-4375-9a20-302132331b02.json +0 -1
- package/dist/devtools-client/_nuxt/entry.DFx-MLUa.css +0 -1
- package/dist/devtools-client/_nuxt/error-404.aORtIbIE.css +0 -1
- package/dist/devtools-client/_nuxt/error-500.FkAdJQFV.css +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { any, array, boolean, custom, literal, minLength, number, object, optional, pipe, record, string, union } from "valibot";
|
|
1
|
+
import { any, array, boolean, custom, function_, literal, maxValue, minLength, minValue, number, object, optional, pipe, record, string, union } from "valibot";
|
|
2
2
|
const consentCategoryValue = union([literal("granted"), literal("denied")]);
|
|
3
3
|
export const gcmConsentState = object({
|
|
4
4
|
ad_storage: optional(consentCategoryValue),
|
|
@@ -947,6 +947,79 @@ export const InitObjectPropertiesSchema = object({
|
|
|
947
947
|
*/
|
|
948
948
|
age: optional(string())
|
|
949
949
|
});
|
|
950
|
+
export const SpeedCurveOptions = object({
|
|
951
|
+
// -- Composable-only options (consumed by useScriptSpeedCurve, not forwarded to LUX) --
|
|
952
|
+
/**
|
|
953
|
+
* Your SpeedCurve customer ID.
|
|
954
|
+
* @see https://support.speedcurve.com/docs/add-rum-to-your-site
|
|
955
|
+
*/
|
|
956
|
+
id: pipe(string(), minLength(1)),
|
|
957
|
+
/**
|
|
958
|
+
* Enable SPA (single-page application) mode.
|
|
959
|
+
* When true, lux.js tracks soft navigations instead of full page loads.
|
|
960
|
+
* @see https://support.speedcurve.com/docs/single-page-applications
|
|
961
|
+
*/
|
|
962
|
+
spaMode: optional(boolean()),
|
|
963
|
+
/**
|
|
964
|
+
* Automatically wire Vue Router hooks for SPA tracking when spaMode is true.
|
|
965
|
+
* Set to false to instrument navigations manually.
|
|
966
|
+
* @default true (when spaMode is true)
|
|
967
|
+
*/
|
|
968
|
+
autoTrackSpaNavigations: optional(boolean()),
|
|
969
|
+
// -- LUX UserConfig passthrough (forwarded onto window.LUX before lux.js loads) --
|
|
970
|
+
// Property names match upstream LUX UserConfig casing exactly. Keep this list in
|
|
971
|
+
// sync with the LUX_USER_CONFIG_KEYS filter in speedcurve.ts.
|
|
972
|
+
/**
|
|
973
|
+
* Page label shown in the SpeedCurve dashboard.
|
|
974
|
+
* Accepts a static string, a function `(to) => string | false` for per-navigation labels,
|
|
975
|
+
* or `false` to disable labeling entirely. A callback returning `false` skips updating
|
|
976
|
+
* the label for that navigation.
|
|
977
|
+
* @default String(to.name ?? to.path)
|
|
978
|
+
*/
|
|
979
|
+
label: optional(union([string(), function_(), literal(false)])),
|
|
980
|
+
/**
|
|
981
|
+
* Sampling rate (0–100). Percentage of sessions that send beacons.
|
|
982
|
+
* Upstream spelling is lowercase — matches LUX UserConfig.
|
|
983
|
+
*/
|
|
984
|
+
samplerate: optional(pipe(number(), minValue(0), maxValue(100))),
|
|
985
|
+
/**
|
|
986
|
+
* Send the beacon when the page is hidden (pagehide event).
|
|
987
|
+
* @default true
|
|
988
|
+
*/
|
|
989
|
+
sendBeaconOnPageHidden: optional(boolean()),
|
|
990
|
+
/**
|
|
991
|
+
* Track JavaScript errors.
|
|
992
|
+
* @default true
|
|
993
|
+
*/
|
|
994
|
+
trackErrors: optional(boolean()),
|
|
995
|
+
/**
|
|
996
|
+
* Maximum number of errors to track per page view.
|
|
997
|
+
* @default 5
|
|
998
|
+
*/
|
|
999
|
+
maxErrors: optional(number()),
|
|
1000
|
+
/**
|
|
1001
|
+
* Minimum time (ms) before a beacon can be sent.
|
|
1002
|
+
*/
|
|
1003
|
+
minMeasureTime: optional(number()),
|
|
1004
|
+
/**
|
|
1005
|
+
* Maximum time (ms) after which the beacon is sent regardless of load state.
|
|
1006
|
+
* @default 60000
|
|
1007
|
+
*/
|
|
1008
|
+
maxMeasureTime: optional(number()),
|
|
1009
|
+
/**
|
|
1010
|
+
* Start a new beacon when the page becomes visible after being hidden.
|
|
1011
|
+
*/
|
|
1012
|
+
newBeaconOnPageShow: optional(boolean()),
|
|
1013
|
+
/**
|
|
1014
|
+
* Track pages loaded in background tabs.
|
|
1015
|
+
* @default false
|
|
1016
|
+
*/
|
|
1017
|
+
trackHiddenPages: optional(boolean()),
|
|
1018
|
+
/**
|
|
1019
|
+
* Cookie domain for cross-subdomain session tracking.
|
|
1020
|
+
*/
|
|
1021
|
+
cookieDomain: optional(string())
|
|
1022
|
+
});
|
|
950
1023
|
export const SnapTrPixelOptions = object({
|
|
951
1024
|
/**
|
|
952
1025
|
* Your Snapchat Pixel ID.
|
|
@@ -966,7 +1039,14 @@ export const StripeOptions = object({
|
|
|
966
1039
|
* @default true
|
|
967
1040
|
* @see https://docs.stripe.com/disputes/prevention/advanced-fraud-detection
|
|
968
1041
|
*/
|
|
969
|
-
advancedFraudSignals: optional(boolean())
|
|
1042
|
+
advancedFraudSignals: optional(boolean()),
|
|
1043
|
+
/**
|
|
1044
|
+
* The Stripe.js SDK version to load.
|
|
1045
|
+
* Named releases get autocomplete; any future codename is also accepted.
|
|
1046
|
+
* @default 'basil'
|
|
1047
|
+
* @see https://docs.stripe.com/sdks/stripejs-versioning
|
|
1048
|
+
*/
|
|
1049
|
+
version: optional(union([literal("v3"), literal("acacia"), literal("basil"), literal("clover"), literal("dahlia"), string()]))
|
|
970
1050
|
});
|
|
971
1051
|
export const TikTokPixelOptions = object({
|
|
972
1052
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LuxGlobal, UserConfig } from '@speedcurve/lux';
|
|
2
|
+
import type { RouteLocationNormalized } from 'vue-router';
|
|
3
|
+
import type { RegistryScriptInput, UseScriptContext } from '#nuxt-scripts/types';
|
|
4
|
+
import { SpeedCurveOptions } from './schemas.js';
|
|
5
|
+
export { SpeedCurveOptions };
|
|
6
|
+
export interface SpeedCurveApi {
|
|
7
|
+
LUX: LuxGlobal;
|
|
8
|
+
}
|
|
9
|
+
declare global {
|
|
10
|
+
interface Window {
|
|
11
|
+
LUX?: LuxGlobal;
|
|
12
|
+
LUX_ae?: ErrorEvent[];
|
|
13
|
+
LUX_al?: PerformanceEntry[];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export type SpeedCurveInput = Omit<RegistryScriptInput<typeof SpeedCurveOptions>, 'label'> & Omit<UserConfig, 'label'> & {
|
|
17
|
+
label?: string | ((to: RouteLocationNormalized) => string | false) | false;
|
|
18
|
+
};
|
|
19
|
+
export declare function useScriptSpeedCurve<T extends SpeedCurveApi>(_options?: SpeedCurveInput): UseScriptContext<T>;
|
|
20
|
+
export declare function applyConfig(options: SpeedCurveInput): void;
|
|
21
|
+
export declare function installAutoTracker(options?: SpeedCurveInput): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useHead, useNuxtApp, useRouter } from "nuxt/app";
|
|
2
|
+
import { speedcurveLuxSnippet } from "#build/nuxt-scripts-snippets";
|
|
3
|
+
import { useRegistryScript } from "../utils.js";
|
|
4
|
+
import { afterNextPaint } from "../utils/after-next-paint.js";
|
|
5
|
+
import { SpeedCurveOptions } from "./schemas.js";
|
|
6
|
+
export { SpeedCurveOptions };
|
|
7
|
+
const LUX_USER_CONFIG_KEYS = Object.keys(SpeedCurveOptions.entries).filter(
|
|
8
|
+
(k) => k !== "id" && k !== "autoTrackSpaNavigations" && k !== "spaMode"
|
|
9
|
+
);
|
|
10
|
+
let luxWired = false;
|
|
11
|
+
export function useScriptSpeedCurve(_options) {
|
|
12
|
+
return useRegistryScript("speedcurve", (options) => ({
|
|
13
|
+
scriptInput: {
|
|
14
|
+
src: `https://cdn.speedcurve.com/js/lux.js?id=${options.id}`,
|
|
15
|
+
crossorigin: "anonymous"
|
|
16
|
+
},
|
|
17
|
+
schema: import.meta.dev ? SpeedCurveOptions : void 0,
|
|
18
|
+
scriptOptions: {
|
|
19
|
+
trigger: "client",
|
|
20
|
+
use: () => ({ LUX: window.LUX }),
|
|
21
|
+
beforeInit: () => {
|
|
22
|
+
if (!speedcurveLuxSnippet)
|
|
23
|
+
return;
|
|
24
|
+
useHead({
|
|
25
|
+
script: [{
|
|
26
|
+
key: "speedcurve-lux-primer",
|
|
27
|
+
tagPosition: "head",
|
|
28
|
+
tagPriority: "critical",
|
|
29
|
+
innerHTML: speedcurveLuxSnippet
|
|
30
|
+
}]
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
clientInit: import.meta.server ? void 0 : () => {
|
|
35
|
+
const input = options;
|
|
36
|
+
applyConfig(input);
|
|
37
|
+
if (options.spaMode && options.autoTrackSpaNavigations !== false)
|
|
38
|
+
installAutoTracker(input);
|
|
39
|
+
}
|
|
40
|
+
}), _options);
|
|
41
|
+
}
|
|
42
|
+
export function applyConfig(options) {
|
|
43
|
+
const lux = window.LUX;
|
|
44
|
+
if (!lux)
|
|
45
|
+
return;
|
|
46
|
+
for (const k of LUX_USER_CONFIG_KEYS) {
|
|
47
|
+
const v = options[k];
|
|
48
|
+
if (v === void 0)
|
|
49
|
+
continue;
|
|
50
|
+
if (k === "label" && typeof v !== "string")
|
|
51
|
+
continue;
|
|
52
|
+
lux[k] = v;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function installAutoTracker(options) {
|
|
56
|
+
if (luxWired)
|
|
57
|
+
return;
|
|
58
|
+
luxWired = true;
|
|
59
|
+
const router = useRouter();
|
|
60
|
+
const nuxt = useNuxtApp();
|
|
61
|
+
let pendingInitial = nuxt.payload?.serverRendered === false;
|
|
62
|
+
const label = options?.label === false ? null : typeof options?.label === "function" ? options.label : (to) => String(to.name ?? to.path);
|
|
63
|
+
router.beforeEach((to) => {
|
|
64
|
+
const lux = window.LUX;
|
|
65
|
+
if (!lux)
|
|
66
|
+
return;
|
|
67
|
+
if (pendingInitial) {
|
|
68
|
+
pendingInitial = false;
|
|
69
|
+
if (label) {
|
|
70
|
+
const nextLabel = label(to);
|
|
71
|
+
if (nextLabel !== false)
|
|
72
|
+
lux.label = nextLabel;
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
lux.startSoftNavigation();
|
|
77
|
+
if (label) {
|
|
78
|
+
const nextLabel = label(to);
|
|
79
|
+
if (nextLabel !== false)
|
|
80
|
+
lux.label = nextLabel;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
router.afterEach((_to, _from, failure) => {
|
|
84
|
+
if (!failure)
|
|
85
|
+
return;
|
|
86
|
+
const lux = window.LUX;
|
|
87
|
+
if (!lux)
|
|
88
|
+
return;
|
|
89
|
+
lux.markLoadTime();
|
|
90
|
+
lux.addData("luxNavFailed", "1");
|
|
91
|
+
});
|
|
92
|
+
nuxt.hook("page:finish", () => {
|
|
93
|
+
afterNextPaint(() => window.LUX?.markLoadTime());
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -6,7 +6,7 @@ export function useScriptStripe(_options) {
|
|
|
6
6
|
return useRegistryScript("stripe", (options) => ({
|
|
7
7
|
scriptInput: {
|
|
8
8
|
src: withQuery(
|
|
9
|
-
`https://js.stripe.com
|
|
9
|
+
`https://js.stripe.com/${options?.version || "basil"}/stripe.js`,
|
|
10
10
|
typeof options?.advancedFraudSignals === "boolean" && !options?.advancedFraudSignals ? { advancedFraudSignals: false } : {}
|
|
11
11
|
),
|
|
12
12
|
// opt-out of privacy defaults
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
|
-
import { useRuntimeConfig } from "nitropack/runtime";
|
|
2
|
+
import { defineCachedFunction, useRuntimeConfig } from "nitropack/runtime";
|
|
3
|
+
import { $fetch } from "ofetch";
|
|
3
4
|
import { ELEMENT_NODE, parse, renderSync, TEXT_NODE, walkSync } from "ultrahtml";
|
|
4
5
|
import { createCachedJsonFetch } from "./utils/cached-upstream.js";
|
|
5
|
-
import { proxyAssetUrl, rewriteUrl, rewriteUrlsInText, RSRC_RE, scopeCss } from "./utils/instagram-embed.js";
|
|
6
|
+
import { isEmbedShell, proxyAssetUrl, rewriteUrl, rewriteUrlsInText, RSRC_RE, scopeCss } from "./utils/instagram-embed.js";
|
|
6
7
|
import { withSigning } from "./utils/withSigning.js";
|
|
7
8
|
export { proxyAssetUrl, proxyImageUrl, rewriteUrl, rewriteUrlsInText, scopeCss } from "./utils/instagram-embed.js";
|
|
8
9
|
const EMBED_INSTAGRAM_SUFFIX_RE = /\/embed\/instagram$/;
|
|
9
10
|
const SRCSET_SPLIT_RE = /\s+/;
|
|
10
|
-
const cachedEmbedFetch =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const cachedEmbedFetch = defineCachedFunction(
|
|
12
|
+
async (url, headers) => {
|
|
13
|
+
const html = await $fetch(url, { timeout: 1e4, headers });
|
|
14
|
+
if (isEmbedShell(html)) {
|
|
15
|
+
throw createError({
|
|
16
|
+
statusCode: 502,
|
|
17
|
+
statusMessage: "Instagram returned an empty embed shell (post unavailable or upstream rate-limiting)"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return html;
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
// v2 — bump to evict any v1 entries that cached the empty JS shell
|
|
24
|
+
// before the shell-detection / UA fix landed.
|
|
25
|
+
name: "nuxt-scripts-instagram-embed-v2",
|
|
26
|
+
maxAge: 600,
|
|
27
|
+
swr: true,
|
|
28
|
+
staleMaxAge: 600,
|
|
29
|
+
// Vary on headers too — Instagram's response is UA-dependent, so
|
|
30
|
+
// different callers (e.g. unit tests, future UA changes) must not
|
|
31
|
+
// collide on the same key.
|
|
32
|
+
getKey: (url, headers) => {
|
|
33
|
+
const parts = [url];
|
|
34
|
+
for (const [k, v] of Object.entries(headers).sort(([a], [b]) => a.localeCompare(b)))
|
|
35
|
+
parts.push(`${k}=${v}`);
|
|
36
|
+
return parts.join("|");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
14
39
|
);
|
|
15
40
|
const cachedCssFetch = createCachedJsonFetch(
|
|
16
41
|
"nuxt-scripts-instagram-css",
|
|
@@ -56,10 +81,12 @@ export default withSigning(defineEventHandler(async (event) => {
|
|
|
56
81
|
const cleanUrl = parsedUrl.origin + pathname;
|
|
57
82
|
const embedUrl = `${cleanUrl}embed/${captions ? "captioned/" : ""}`;
|
|
58
83
|
const html = await cachedEmbedFetch(embedUrl, {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
"Accept": "text/html",
|
|
85
|
+
// Meta's own crawler UA. Googlebot's UA is also accepted by Instagram
|
|
86
|
+
// but is IP-verified, so it fails from hosts outside Google's ranges
|
|
87
|
+
// (e.g. Cloudflare/Vercel) and Instagram serves the JS shell instead
|
|
88
|
+
// of the SSR'd post.
|
|
89
|
+
"User-Agent": "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"
|
|
63
90
|
}).catch((error) => {
|
|
64
91
|
throw createError({
|
|
65
92
|
statusCode: error.statusCode || 500,
|
|
@@ -13,6 +13,16 @@ import {
|
|
|
13
13
|
const COMPRESSION_RE = /gzip|deflate|br|compress|base64/i;
|
|
14
14
|
const CLIENT_HINT_VERSION_RE = /;v="(\d+)\.[^"]*"/g;
|
|
15
15
|
const SKIP_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["set-cookie", "transfer-encoding", "content-encoding", "content-length"]);
|
|
16
|
+
export const SKIP_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
17
|
+
"connection",
|
|
18
|
+
"keep-alive",
|
|
19
|
+
"proxy-authenticate",
|
|
20
|
+
"proxy-authorization",
|
|
21
|
+
"te",
|
|
22
|
+
"trailer",
|
|
23
|
+
"transfer-encoding",
|
|
24
|
+
"upgrade"
|
|
25
|
+
]);
|
|
16
26
|
function stripQueryFingerprinting(query, privacy) {
|
|
17
27
|
const stripped = stripPayloadFingerprinting(query, privacy);
|
|
18
28
|
const params = new URLSearchParams();
|
|
@@ -88,12 +98,18 @@ export default defineEventHandler(async (event) => {
|
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
100
|
const headers = {};
|
|
101
|
+
const connectionHeaderValue = originalHeaders.connection;
|
|
102
|
+
const connectionNamedHeaders = connectionHeaderValue ? new Set(connectionHeaderValue.split(",").map((h) => h.trim().toLowerCase()).filter(Boolean)) : null;
|
|
91
103
|
for (const [key, value] of Object.entries(originalHeaders)) {
|
|
92
104
|
if (!value)
|
|
93
105
|
continue;
|
|
94
106
|
const lowerKey = key.toLowerCase();
|
|
95
107
|
if (lowerKey === "host")
|
|
96
108
|
continue;
|
|
109
|
+
if (SKIP_REQUEST_HEADERS.has(lowerKey))
|
|
110
|
+
continue;
|
|
111
|
+
if (connectionNamedHeaders?.has(lowerKey))
|
|
112
|
+
continue;
|
|
97
113
|
if (SENSITIVE_HEADERS.includes(lowerKey))
|
|
98
114
|
continue;
|
|
99
115
|
if (lowerKey === "content-length") {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { buildProxyUrl } from "./proxy-url.js";
|
|
2
2
|
export const RSRC_RE = /url\(\/rsrc\.php([^)]+)\)/g;
|
|
3
|
+
const SHELL_BODY_RE = /id=["'](?:splash-screen|has-finished-comet-page)["']/;
|
|
4
|
+
const HAS_POST_CONTENT_RE = /\bclass=(["'])[^"']*\b(?:Embed|EmbeddedMedia|EmbeddedMediaImage)\b[^"']*\1/i;
|
|
5
|
+
export function isEmbedShell(html) {
|
|
6
|
+
return SHELL_BODY_RE.test(html) && !HAS_POST_CONTENT_RE.test(html);
|
|
7
|
+
}
|
|
3
8
|
export const AMP_RE = /&/g;
|
|
4
9
|
export const SCONTENT_RE = /https:\/\/scontent[^"'\s),]+\.cdninstagram\.com[^"'\s),]+/g;
|
|
5
10
|
export const STATIC_CDN_RE = /https:\/\/static\.cdninstagram\.com[^"'\s),]+/g;
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ import type { RedditPixelInput } from './registry/reddit-pixel.js';
|
|
|
35
35
|
import type { RybbitAnalyticsInput } from './registry/rybbit-analytics.js';
|
|
36
36
|
import type { SegmentInput } from './registry/segment.js';
|
|
37
37
|
import type { SnapTrPixelInput } from './registry/snapchat-pixel.js';
|
|
38
|
+
import type { SpeedCurveInput } from './registry/speedcurve.js';
|
|
38
39
|
import type { StripeInput } from './registry/stripe.js';
|
|
39
40
|
import type { TikTokPixelInput } from './registry/tiktok-pixel.js';
|
|
40
41
|
import type { UmamiAnalyticsInput } from './registry/umami-analytics.js';
|
|
@@ -263,6 +264,7 @@ export interface ScriptRegistry {
|
|
|
263
264
|
rybbitAnalytics?: RybbitAnalyticsInput;
|
|
264
265
|
redditPixel?: RedditPixelInput;
|
|
265
266
|
segment?: SegmentInput;
|
|
267
|
+
speedcurve?: SpeedCurveInput;
|
|
266
268
|
stripe?: StripeInput;
|
|
267
269
|
tiktokPixel?: TikTokPixelInput;
|
|
268
270
|
xEmbed?: XEmbedInput;
|
|
@@ -281,7 +283,7 @@ export interface ScriptRegistry {
|
|
|
281
283
|
* Built-in registry script keys — not affected by module augmentation.
|
|
282
284
|
* Use this to type-check records that must enumerate all built-in scripts (logos, meta, etc.).
|
|
283
285
|
*/
|
|
284
|
-
export type BuiltInRegistryScriptKey = 'ahrefsAnalytics' | 'bingUet' | 'blueskyEmbed' | 'calendly' | 'carbonAds' | 'crisp' | 'clarity' | 'cloudflareWebAnalytics' | 'databuddyAnalytics' | 'metaPixel' | 'fathomAnalytics' | 'instagramEmbed' | 'plausibleAnalytics' | 'googleAdsense' | 'googleAnalytics' | 'googleMaps' | 'googleRecaptcha' | 'googleSignIn' | 'lemonSqueezy' | 'googleTagManager' | 'hotjar' | 'intercom' | 'linkedinInsight' | 'paypal' | 'posthog' | 'matomoAnalytics' | 'mixpanelAnalytics' | 'rybbitAnalytics' | 'redditPixel' | 'segment' | 'stripe' | 'tiktokPixel' | 'xEmbed' | 'xPixel' | 'snapchatPixel' | 'youtubePlayer' | 'vercelAnalytics' | 'vimeoPlayer' | 'umamiAnalytics' | 'usercentrics' | 'gravatar' | 'npm';
|
|
286
|
+
export type BuiltInRegistryScriptKey = 'ahrefsAnalytics' | 'bingUet' | 'blueskyEmbed' | 'calendly' | 'carbonAds' | 'crisp' | 'clarity' | 'cloudflareWebAnalytics' | 'databuddyAnalytics' | 'metaPixel' | 'fathomAnalytics' | 'instagramEmbed' | 'plausibleAnalytics' | 'googleAdsense' | 'googleAnalytics' | 'googleMaps' | 'googleRecaptcha' | 'googleSignIn' | 'lemonSqueezy' | 'googleTagManager' | 'hotjar' | 'intercom' | 'linkedinInsight' | 'paypal' | 'posthog' | 'matomoAnalytics' | 'mixpanelAnalytics' | 'rybbitAnalytics' | 'redditPixel' | 'segment' | 'stripe' | 'tiktokPixel' | 'xEmbed' | 'xPixel' | 'snapchatPixel' | 'speedcurve' | 'youtubePlayer' | 'vercelAnalytics' | 'vimeoPlayer' | 'umamiAnalytics' | 'usercentrics' | 'gravatar' | 'npm';
|
|
285
287
|
/**
|
|
286
288
|
* Union of all explicit registry script keys (excludes npm pattern).
|
|
287
289
|
* Includes both built-in and augmented keys.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function afterNextPaint(callback: () => void): void;
|
package/dist/stats.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type TrackedDataType = 'page-views' | 'events' | 'conversions' | 'user-identity' | 'session-replay' | 'heatmaps' | 'clicks' | 'scrolls' | 'retargeting' | 'audiences' | 'form-submissions' | 'video-engagement' | 'transactions' | 'errors' | 'tag-injection' | 'ab-testing';
|
|
1
|
+
type TrackedDataType = 'page-views' | 'events' | 'conversions' | 'user-identity' | 'session-replay' | 'heatmaps' | 'clicks' | 'scrolls' | 'retargeting' | 'audiences' | 'form-submissions' | 'video-engagement' | 'transactions' | 'errors' | 'tag-injection' | 'ab-testing' | 'performance-timings';
|
|
2
2
|
|
|
3
3
|
interface ScriptPrivacy {
|
|
4
4
|
ip: boolean;
|
package/dist/stats.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type TrackedDataType = 'page-views' | 'events' | 'conversions' | 'user-identity' | 'session-replay' | 'heatmaps' | 'clicks' | 'scrolls' | 'retargeting' | 'audiences' | 'form-submissions' | 'video-engagement' | 'transactions' | 'errors' | 'tag-injection' | 'ab-testing';
|
|
1
|
+
type TrackedDataType = 'page-views' | 'events' | 'conversions' | 'user-identity' | 'session-replay' | 'heatmaps' | 'clicks' | 'scrolls' | 'retargeting' | 'audiences' | 'form-submissions' | 'video-engagement' | 'transactions' | 'errors' | 'tag-injection' | 'ab-testing' | 'performance-timings';
|
|
2
2
|
|
|
3
3
|
interface ScriptPrivacy {
|
|
4
4
|
ip: boolean;
|
package/dist/stats.mjs
CHANGED
|
@@ -198,6 +198,11 @@ const scriptMeta = {
|
|
|
198
198
|
gravatar: {
|
|
199
199
|
urls: ["https://secure.gravatar.com/js/gprofiles.js"],
|
|
200
200
|
trackedData: []
|
|
201
|
+
},
|
|
202
|
+
// Performance monitoring
|
|
203
|
+
speedcurve: {
|
|
204
|
+
urls: ["https://cdn.speedcurve.com/js/lux.js"],
|
|
205
|
+
trackedData: ["page-views", "performance-timings", "errors"]
|
|
201
206
|
}
|
|
202
207
|
};
|
|
203
208
|
|
package/dist/types-source.mjs
CHANGED
|
@@ -382,7 +382,7 @@ const types = {
|
|
|
382
382
|
{
|
|
383
383
|
name: "ScriptGoogleMapsHeatmapLayerProps",
|
|
384
384
|
kind: "interface",
|
|
385
|
-
code: "interface ScriptGoogleMapsHeatmapLayerProps {\n /**\n * Configuration options for the heatmap layer visualization.\n * @see https://developers.google.com/maps/documentation/javascript/reference/visualization#HeatmapLayerOptions\n */\n options?: Omit<
|
|
385
|
+
code: "interface ScriptGoogleMapsHeatmapLayerProps {\n /**\n * Configuration options for the heatmap layer visualization.\n * @deprecated Google deprecated the Maps JavaScript API `HeatmapLayer` (May 2025) and removed it in v3.65 (May 2026). Consider [deck.gl HeatmapLayer](https://deck.gl/docs/api-reference/aggregation-layers/heatmap-layer) instead.\n * @see https://developers.google.com/maps/documentation/javascript/reference/visualization#HeatmapLayerOptions\n */\n options?: Omit<HeatmapLayerOptions, 'map'>\n}"
|
|
386
386
|
},
|
|
387
387
|
{
|
|
388
388
|
name: "ScriptGoogleMapsInfoWindowProps",
|
|
@@ -965,11 +965,23 @@ const types = {
|
|
|
965
965
|
code: "export interface SnapPixelApi {\n snaptr: SnapTrFns & {\n push: SnapTrFns\n loaded: boolean\n version: string\n queue: any[]\n }\n _snaptr: SnapPixelApi['snaptr']\n handleRequest?: SnapTrFns\n}"
|
|
966
966
|
}
|
|
967
967
|
],
|
|
968
|
+
speedcurve: [
|
|
969
|
+
{
|
|
970
|
+
name: "SpeedCurveOptions",
|
|
971
|
+
kind: "const",
|
|
972
|
+
code: "export const SpeedCurveOptions = object({\n // -- Composable-only options (consumed by useScriptSpeedCurve, not forwarded to LUX) --\n /**\n * Your SpeedCurve customer ID.\n * @see https://support.speedcurve.com/docs/add-rum-to-your-site\n */\n id: pipe(string(), minLength(1)),\n /**\n * Enable SPA (single-page application) mode.\n * When true, lux.js tracks soft navigations instead of full page loads.\n * @see https://support.speedcurve.com/docs/single-page-applications\n */\n spaMode: optional(boolean()),\n /**\n * Automatically wire Vue Router hooks for SPA tracking when spaMode is true.\n * Set to false to instrument navigations manually.\n * @default true (when spaMode is true)\n */\n autoTrackSpaNavigations: optional(boolean()),\n\n // -- LUX UserConfig passthrough (forwarded onto window.LUX before lux.js loads) --\n // Property names match upstream LUX UserConfig casing exactly. Keep this list in\n // sync with the LUX_USER_CONFIG_KEYS filter in speedcurve.ts.\n /**\n * Page label shown in the SpeedCurve dashboard.\n * Accepts a static string, a function `(to) => string | false` for per-navigation labels,\n * or `false` to disable labeling entirely. A callback returning `false` skips updating\n * the label for that navigation.\n * @default String(to.name ?? to.path)\n */\n label: optional(union([string(), function_(), literal(false)])),\n /**\n * Sampling rate (0–100). Percentage of sessions that send beacons.\n * Upstream spelling is lowercase — matches LUX UserConfig.\n */\n samplerate: optional(pipe(number(), minValue(0), maxValue(100))),\n /**\n * Send the beacon when the page is hidden (pagehide event).\n * @default true\n */\n sendBeaconOnPageHidden: optional(boolean()),\n /**\n * Track JavaScript errors.\n * @default true\n */\n trackErrors: optional(boolean()),\n /**\n * Maximum number of errors to track per page view.\n * @default 5\n */\n maxErrors: optional(number()),\n /**\n * Minimum time (ms) before a beacon can be sent.\n */\n minMeasureTime: optional(number()),\n /**\n * Maximum time (ms) after which the beacon is sent regardless of load state.\n * @default 60000\n */\n maxMeasureTime: optional(number()),\n /**\n * Start a new beacon when the page becomes visible after being hidden.\n */\n newBeaconOnPageShow: optional(boolean()),\n /**\n * Track pages loaded in background tabs.\n * @default false\n */\n trackHiddenPages: optional(boolean()),\n /**\n * Cookie domain for cross-subdomain session tracking.\n */\n cookieDomain: optional(string()),\n})"
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
name: "SpeedCurveApi",
|
|
976
|
+
kind: "interface",
|
|
977
|
+
code: "export interface SpeedCurveApi {\n LUX: LuxGlobal\n}"
|
|
978
|
+
}
|
|
979
|
+
],
|
|
968
980
|
stripe: [
|
|
969
981
|
{
|
|
970
982
|
name: "StripeOptions",
|
|
971
983
|
kind: "const",
|
|
972
|
-
code: "export const StripeOptions = object({\n /**\n * Whether to load Stripe's advanced fraud detection signals.\n * Set to `false` to opt out.\n * @default true\n * @see https://docs.stripe.com/disputes/prevention/advanced-fraud-detection\n */\n advancedFraudSignals: optional(boolean()),\n})"
|
|
984
|
+
code: "export const StripeOptions = object({\n /**\n * Whether to load Stripe's advanced fraud detection signals.\n * Set to `false` to opt out.\n * @default true\n * @see https://docs.stripe.com/disputes/prevention/advanced-fraud-detection\n */\n advancedFraudSignals: optional(boolean()),\n /**\n * The Stripe.js SDK version to load.\n * Named releases get autocomplete; any future codename is also accepted.\n * @default 'basil'\n * @see https://docs.stripe.com/sdks/stripejs-versioning\n */\n version: optional(union([literal('v3'), literal('acacia'), literal('basil'), literal('clover'), literal('dahlia'), string()])),\n})"
|
|
973
985
|
},
|
|
974
986
|
{
|
|
975
987
|
name: "StripeApi",
|
|
@@ -2374,6 +2386,93 @@ const schemaFields = {
|
|
|
2374
2386
|
description: "The user's age."
|
|
2375
2387
|
}
|
|
2376
2388
|
],
|
|
2389
|
+
SpeedCurveOptions: [
|
|
2390
|
+
{
|
|
2391
|
+
name: "id",
|
|
2392
|
+
type: "string",
|
|
2393
|
+
required: true,
|
|
2394
|
+
description: "Your SpeedCurve customer ID."
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
name: "spaMode",
|
|
2398
|
+
type: "boolean",
|
|
2399
|
+
required: false,
|
|
2400
|
+
description: "Enable SPA (single-page application) mode. When true, lux.js tracks soft navigations instead of full page loads."
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
name: "autoTrackSpaNavigations",
|
|
2404
|
+
type: "boolean",
|
|
2405
|
+
required: false,
|
|
2406
|
+
description: "Automatically wire Vue Router hooks for SPA tracking when spaMode is true. Set to false to instrument navigations manually.",
|
|
2407
|
+
defaultValue: "true (when spaMode is true)"
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
name: "label",
|
|
2411
|
+
type: "string | Function | false",
|
|
2412
|
+
required: false,
|
|
2413
|
+
description: "Page label shown in the SpeedCurve dashboard. Accepts a static string, a function `(to) => string | false` for per-navigation labels, or `false` to disable labeling entirely. A callback returning `false` skips updating the label for that navigation.",
|
|
2414
|
+
defaultValue: "String(to.name ?? to.path)"
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
name: "samplerate",
|
|
2418
|
+
type: "number",
|
|
2419
|
+
required: false,
|
|
2420
|
+
description: "Sampling rate (0–100). Percentage of sessions that send beacons. Upstream spelling is lowercase — matches LUX UserConfig."
|
|
2421
|
+
},
|
|
2422
|
+
{
|
|
2423
|
+
name: "sendBeaconOnPageHidden",
|
|
2424
|
+
type: "boolean",
|
|
2425
|
+
required: false,
|
|
2426
|
+
description: "Send the beacon when the page is hidden (pagehide event).",
|
|
2427
|
+
defaultValue: "true"
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
name: "trackErrors",
|
|
2431
|
+
type: "boolean",
|
|
2432
|
+
required: false,
|
|
2433
|
+
description: "Track JavaScript errors.",
|
|
2434
|
+
defaultValue: "true"
|
|
2435
|
+
},
|
|
2436
|
+
{
|
|
2437
|
+
name: "maxErrors",
|
|
2438
|
+
type: "number",
|
|
2439
|
+
required: false,
|
|
2440
|
+
description: "Maximum number of errors to track per page view.",
|
|
2441
|
+
defaultValue: "5"
|
|
2442
|
+
},
|
|
2443
|
+
{
|
|
2444
|
+
name: "minMeasureTime",
|
|
2445
|
+
type: "number",
|
|
2446
|
+
required: false,
|
|
2447
|
+
description: "Minimum time (ms) before a beacon can be sent."
|
|
2448
|
+
},
|
|
2449
|
+
{
|
|
2450
|
+
name: "maxMeasureTime",
|
|
2451
|
+
type: "number",
|
|
2452
|
+
required: false,
|
|
2453
|
+
description: "Maximum time (ms) after which the beacon is sent regardless of load state.",
|
|
2454
|
+
defaultValue: "60000"
|
|
2455
|
+
},
|
|
2456
|
+
{
|
|
2457
|
+
name: "newBeaconOnPageShow",
|
|
2458
|
+
type: "boolean",
|
|
2459
|
+
required: false,
|
|
2460
|
+
description: "Start a new beacon when the page becomes visible after being hidden."
|
|
2461
|
+
},
|
|
2462
|
+
{
|
|
2463
|
+
name: "trackHiddenPages",
|
|
2464
|
+
type: "boolean",
|
|
2465
|
+
required: false,
|
|
2466
|
+
description: "Track pages loaded in background tabs.",
|
|
2467
|
+
defaultValue: "false"
|
|
2468
|
+
},
|
|
2469
|
+
{
|
|
2470
|
+
name: "cookieDomain",
|
|
2471
|
+
type: "string",
|
|
2472
|
+
required: false,
|
|
2473
|
+
description: "Cookie domain for cross-subdomain session tracking."
|
|
2474
|
+
}
|
|
2475
|
+
],
|
|
2377
2476
|
SnapTrPixelOptions: [
|
|
2378
2477
|
{
|
|
2379
2478
|
name: "id",
|
|
@@ -2395,6 +2494,13 @@ const schemaFields = {
|
|
|
2395
2494
|
required: false,
|
|
2396
2495
|
description: "Whether to load Stripe's advanced fraud detection signals. Set to `false` to opt out.",
|
|
2397
2496
|
defaultValue: "true"
|
|
2497
|
+
},
|
|
2498
|
+
{
|
|
2499
|
+
name: "version",
|
|
2500
|
+
type: "'v3' | 'acacia' | 'basil' | 'clover' | 'dahlia' | string",
|
|
2501
|
+
required: false,
|
|
2502
|
+
description: "The Stripe.js SDK version to load. Named releases get autocomplete; any future codename is also accepted.",
|
|
2503
|
+
defaultValue: "'basil'"
|
|
2398
2504
|
}
|
|
2399
2505
|
],
|
|
2400
2506
|
TikTokPixelOptions: [
|
|
@@ -2747,7 +2853,7 @@ const schemaFields = {
|
|
|
2747
2853
|
ScriptGoogleMapsHeatmapLayerProps: [
|
|
2748
2854
|
{
|
|
2749
2855
|
name: "options",
|
|
2750
|
-
type: "Omit<
|
|
2856
|
+
type: "Omit<HeatmapLayerOptions, 'map'>",
|
|
2751
2857
|
required: false,
|
|
2752
2858
|
description: "Configuration options for the heatmap layer visualization."
|
|
2753
2859
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/scripts",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"description": "Load third-party scripts with better performance, privacy and DX in Nuxt Apps.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -71,11 +71,12 @@
|
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"@googlemaps/markerclusterer": "^2.6.2",
|
|
73
73
|
"@paypal/paypal-js": "^8.1.2 || ^9.0.0",
|
|
74
|
+
"@speedcurve/lux": "^4.4.3",
|
|
74
75
|
"@stripe/stripe-js": "^7.0.0 || ^8.0.0 || ^9.0.0",
|
|
75
76
|
"@types/google.maps": "^3.58.1",
|
|
76
77
|
"@types/vimeo__player": "^2.18.3",
|
|
77
78
|
"@types/youtube": "^0.1.0",
|
|
78
|
-
"@unhead/vue": "^2.0.3",
|
|
79
|
+
"@unhead/vue": "^2.0.3 || ^3.0.0",
|
|
79
80
|
"posthog-js": "^1.0.0"
|
|
80
81
|
},
|
|
81
82
|
"peerDependenciesMeta": {
|
|
@@ -85,6 +86,9 @@
|
|
|
85
86
|
"@paypal/paypal-js": {
|
|
86
87
|
"optional": true
|
|
87
88
|
},
|
|
89
|
+
"@speedcurve/lux": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
88
92
|
"@stripe/stripe-js": {
|
|
89
93
|
"optional": true
|
|
90
94
|
},
|
|
@@ -111,7 +115,7 @@
|
|
|
111
115
|
"magic-string": "^0.30.21",
|
|
112
116
|
"ofetch": "^1.5.1",
|
|
113
117
|
"ohash": "^2.0.11",
|
|
114
|
-
"oxc-parser": "^0.
|
|
118
|
+
"oxc-parser": "^0.134.0",
|
|
115
119
|
"oxc-walker": "^1.0.0",
|
|
116
120
|
"pathe": "^2.0.3",
|
|
117
121
|
"pkg-types": "^2.3.1",
|
|
@@ -121,11 +125,12 @@
|
|
|
121
125
|
"ultrahtml": "^1.6.0",
|
|
122
126
|
"unplugin": "^3.0.0",
|
|
123
127
|
"unstorage": "^1.17.5",
|
|
124
|
-
"valibot": "^1.4.
|
|
128
|
+
"valibot": "^1.4.1"
|
|
125
129
|
},
|
|
126
130
|
"devDependencies": {
|
|
127
131
|
"@nuxt/kit": "^4.4.6",
|
|
128
132
|
"@nuxt/module-builder": "^1.0.2",
|
|
133
|
+
"@speedcurve/lux": "^4.4.3",
|
|
129
134
|
"rollup": "^4.60.4",
|
|
130
135
|
"unbuild": "^3.6.1",
|
|
131
136
|
"unimport": "^6.3.0"
|