@nuxt/scripts 1.0.0-beta.7 → 1.0.0-rc.10
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/bin/cli.mjs +2 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.mjs +50 -0
- package/dist/devtools-client/200.html +1 -0
- package/dist/devtools-client/404.html +1 -0
- package/dist/devtools-client/_fonts/4ppnHhMi-pBsWSPo7mY0avYxlDoAg1N3PTzCwXLZ5rA-d9oibkGnTd1JL3tc_xnaVgBLYmOB8kjrK2cvZaqwj9s.woff2 +0 -0
- package/dist/devtools-client/_fonts/4qBuU9MRVUlPZNPSF7Xom_sK8RBEnfYu-9VXFrdq8A8-8TDwLE1HAj1sQn7XxVWtM_7sIaPM-DTdO3Pf8U2DF1U.woff2 +0 -0
- package/dist/devtools-client/_fonts/6dYsbWUd_BpKJ7mdDihgOcya1gHXLpJBuMYXux3WMjE-q3fYNS8YbW5n7ZeXI2vSNgkRWW5VDPKAl51SNTjG2qk.woff2 +0 -0
- package/dist/devtools-client/_fonts/Lr-hqqZZsYmCt0ITUlr1CUrWim9fsKvoDFZliMxgNHY-iTa_Yt_PzhOY9TX7ZXdSlEPim6iRt92xhECwaxWxd5w.woff2 +0 -0
- package/dist/devtools-client/_fonts/OknHvWI6KtYn1JQBzX7eSpNDBQ8520F9TvSUJYkVf6A-xeZn9253svK_8Q2LD0XEruY_MnEsuCRO5LenPoggC0Y.woff2 +0 -0
- package/dist/devtools-client/_fonts/PV2hrQG6wq5BlIPDjdL1IcOflycaghyt5MHzlBqZtlo-lb_WexLz3VZqfTN0oi554iBH5tT2j2UFEV-XErCAS3E.woff2 +0 -0
- package/dist/devtools-client/_fonts/UA7OtwYHwGN_HjcVGTdmiQxUit7FlqkCwxVUWSeXVnQ-B4OXCFOL_tWrYODpQTc07aMaj0c2cewTOmBRWR9tD-A.woff2 +0 -0
- package/dist/devtools-client/_fonts/VE4cDVCv5MxbFM7ZLoLCGbIpNd71zhp7MDI9lmN5Y7I-xZyDYCUVrd6LV8eVGF3Um3UZjBFuUtDGtvdyTBBRYBo.woff2 +0 -0
- package/dist/devtools-client/_fonts/fVoGbnMbBFd5L9BBp9fUPavUSkZ_EmsQNSyadkT-108-U4T0khaeLQSIhtt9eVvaCEKJjtWJ4ioRJOf8hvqkWY0.woff2 +0 -0
- package/dist/devtools-client/_fonts/lQAxeCEs1R0Lw-H9XRU1RlOARQN8J6npRsPjyEDMe5s-_DUSLEkO3tKTuun_gSnDLoQPVEnpOnyqZMOw0ByZ6PA.woff2 +0 -0
- package/dist/devtools-client/_fonts/lntlqNHKLV2n82yTwMde70QqOjcfLE2XJ5oKZ3vRPWc-z6TxpIZQdWXztWLr9_OFWqt_WJJoeGtuK_-XQMZGQwE.woff2 +0 -0
- package/dist/devtools-client/_fonts/qxAYvKsXWeYv731eb-h5TRurcdIP_W44mpNdX-HABAk-zUDeMEFlNtNbrwvT9JxLEBg0TphGy70O6RfIoIX_ZwU.woff2 +0 -0
- package/dist/devtools-client/_nuxt/B8PEiB0p.js +1 -0
- package/dist/devtools-client/_nuxt/BgPDxVUn.js +1 -0
- package/dist/devtools-client/_nuxt/BmlapxLP.js +1 -0
- package/dist/devtools-client/_nuxt/CM2vefXI.js +188 -0
- package/dist/devtools-client/_nuxt/DAF5Qk9P.js +1 -0
- package/dist/devtools-client/_nuxt/Dx6HhVmj.js +1 -0
- package/dist/devtools-client/_nuxt/S8LiR9M1.js +1 -0
- package/dist/devtools-client/_nuxt/builds/latest.json +1 -0
- package/dist/devtools-client/_nuxt/builds/meta/5458a3f2-af35-479c-8852-bf6f92fed611.json +1 -0
- package/dist/devtools-client/_nuxt/entry.BKkVrcJj.css +1 -0
- package/dist/devtools-client/_nuxt/error-404.d44aGwWI.css +1 -0
- package/dist/devtools-client/_nuxt/error-500.NthMfIEt.css +1 -0
- package/dist/devtools-client/_nuxt/first-party.C8Ha4JLM.css +1 -0
- package/dist/devtools-client/_nuxt/index.DZD1lwyI.css +1 -0
- package/dist/devtools-client/_nuxt/registry.B9lnjF_b.css +1 -0
- package/dist/devtools-client/_nuxt/vBkR1GJq.js +1 -0
- package/dist/devtools-client/_nuxt/wDzz0qaB.js +1 -0
- package/dist/devtools-client/docs/index.html +1 -0
- package/dist/devtools-client/first-party/index.html +1 -0
- package/dist/devtools-client/index.html +1 -0
- package/dist/devtools-client/registry/index.html +1 -0
- package/dist/module.d.mts +89 -80
- package/dist/module.d.ts +185 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +1056 -756
- package/dist/registry.d.mts +92 -4
- package/dist/registry.d.ts +94 -0
- package/dist/registry.mjs +668 -326
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +77 -165
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +148 -227
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +77 -165
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.d.vue.ts +6 -55
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +12 -83
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue.d.ts +6 -55
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.d.vue.ts +5 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue +24 -38
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue.d.ts +5 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.d.vue.ts +43 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.vue +60 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.vue.d.ts +43 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.d.vue.ts +4 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +22 -26
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue.d.ts +4 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.d.vue.ts +11 -8
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +57 -57
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue.d.ts +11 -8
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.d.vue.ts +24 -42
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +71 -74
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue.d.ts +24 -42
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +19 -20
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +85 -38
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +19 -20
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.d.vue.ts +98 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue +263 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue.d.ts +98 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.d.vue.ts +10 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue +9 -41
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue.d.ts +10 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.d.vue.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue +23 -38
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue.d.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.d.vue.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue +23 -38
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue.d.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.d.vue.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue +24 -38
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue.d.ts +7 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.d.vue.ts +200 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +170 -0
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue.d.ts +200 -0
- package/dist/runtime/components/GoogleMaps/bindGoogleMapsEvents.d.ts +13 -0
- package/dist/runtime/components/GoogleMaps/bindGoogleMapsEvents.js +8 -0
- package/dist/runtime/components/GoogleMaps/injectionKeys.d.ts +10 -0
- package/dist/runtime/components/GoogleMaps/injectionKeys.js +2 -0
- package/dist/runtime/components/GoogleMaps/types.d.ts +42 -0
- package/dist/runtime/components/GoogleMaps/types.js +1 -0
- package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.d.ts +98 -0
- package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.js +126 -0
- package/dist/runtime/components/ScriptBlueskyEmbed.d.vue.ts +83 -0
- package/dist/runtime/components/ScriptBlueskyEmbed.vue +91 -0
- package/dist/runtime/components/ScriptBlueskyEmbed.vue.d.ts +83 -0
- package/dist/runtime/components/ScriptCarbonAds.d.vue.ts +4 -7
- package/dist/runtime/components/ScriptCarbonAds.vue +1 -0
- package/dist/runtime/components/ScriptCarbonAds.vue.d.ts +4 -7
- package/dist/runtime/components/ScriptCrisp.d.vue.ts +7 -11
- package/dist/runtime/components/ScriptCrisp.vue +2 -1
- package/dist/runtime/components/ScriptCrisp.vue.d.ts +7 -11
- package/dist/runtime/components/ScriptGoogleAdsense.d.vue.ts +4 -7
- package/dist/runtime/components/ScriptGoogleAdsense.vue +2 -1
- package/dist/runtime/components/ScriptGoogleAdsense.vue.d.ts +4 -7
- package/dist/runtime/components/ScriptGravatar.d.vue.ts +22 -0
- package/dist/runtime/components/ScriptGravatar.vue +46 -0
- package/dist/runtime/components/ScriptGravatar.vue.d.ts +22 -0
- package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +12 -15
- package/dist/runtime/components/ScriptInstagramEmbed.vue +11 -3
- package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +12 -15
- package/dist/runtime/components/ScriptIntercom.d.vue.ts +7 -11
- package/dist/runtime/components/ScriptIntercom.vue +5 -3
- package/dist/runtime/components/ScriptIntercom.vue.d.ts +7 -11
- package/dist/runtime/components/ScriptLemonSqueezy.d.vue.ts +2 -3
- package/dist/runtime/components/ScriptLemonSqueezy.vue +1 -0
- package/dist/runtime/components/ScriptLemonSqueezy.vue.d.ts +2 -3
- package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +43 -37
- package/dist/runtime/components/ScriptPayPalButtons.vue +49 -79
- package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +43 -37
- package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +37 -28
- package/dist/runtime/components/ScriptPayPalMessages.vue +47 -50
- package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +37 -28
- package/dist/runtime/components/ScriptStripePricingTable.d.vue.ts +5 -9
- package/dist/runtime/components/ScriptStripePricingTable.vue +3 -2
- package/dist/runtime/components/ScriptStripePricingTable.vue.d.ts +5 -9
- package/dist/runtime/components/ScriptVimeoPlayer.d.vue.ts +17 -11
- package/dist/runtime/components/ScriptVimeoPlayer.vue +14 -10
- package/dist/runtime/components/ScriptVimeoPlayer.vue.d.ts +17 -11
- package/dist/runtime/components/ScriptXEmbed.d.vue.ts +10 -14
- package/dist/runtime/components/ScriptXEmbed.vue +21 -12
- package/dist/runtime/components/ScriptXEmbed.vue.d.ts +10 -14
- package/dist/runtime/components/ScriptYouTubePlayer.d.vue.ts +10 -15
- package/dist/runtime/components/ScriptYouTubePlayer.vue +12 -5
- package/dist/runtime/components/ScriptYouTubePlayer.vue.d.ts +10 -15
- package/dist/runtime/composables/useScript.js +159 -8
- package/dist/runtime/composables/useScriptEventPage.js +2 -2
- package/dist/runtime/composables/useScriptProxyToken.d.ts +12 -0
- package/dist/runtime/composables/useScriptProxyToken.js +4 -0
- package/dist/runtime/composables/useScriptProxyUrl.d.ts +12 -0
- package/dist/runtime/composables/useScriptProxyUrl.js +27 -0
- package/dist/runtime/composables/useScriptTriggerConsent.d.ts +10 -0
- package/dist/runtime/composables/useScriptTriggerConsent.js +33 -20
- package/dist/runtime/composables/useScriptTriggerElement.js +1 -1
- package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +1 -1
- package/dist/runtime/devtools-standalone-bridge.client.d.ts +8 -0
- package/dist/runtime/devtools-standalone-bridge.client.js +50 -0
- package/dist/runtime/plugins/proxy-token.server.d.ts +10 -0
- package/dist/runtime/plugins/proxy-token.server.js +17 -0
- package/dist/runtime/registry/bing-uet.d.ts +198 -0
- package/dist/runtime/registry/bing-uet.js +43 -0
- package/dist/runtime/registry/bluesky-embed.d.ts +112 -0
- package/dist/runtime/registry/bluesky-embed.js +68 -0
- package/dist/runtime/registry/clarity.d.ts +16 -17
- package/dist/runtime/registry/clarity.js +33 -31
- package/dist/runtime/registry/cloudflare-web-analytics.d.ts +2 -13
- package/dist/runtime/registry/cloudflare-web-analytics.js +2 -14
- package/dist/runtime/registry/crisp.d.ts +10 -40
- package/dist/runtime/registry/crisp.js +2 -33
- package/dist/runtime/registry/databuddy-analytics.d.ts +2 -35
- package/dist/runtime/registry/databuddy-analytics.js +20 -45
- package/dist/runtime/registry/fathom-analytics.d.ts +7 -26
- package/dist/runtime/registry/fathom-analytics.js +3 -25
- package/dist/runtime/registry/google-adsense.d.ts +3 -11
- package/dist/runtime/registry/google-adsense.js +2 -11
- package/dist/runtime/registry/google-analytics.d.ts +9 -7
- package/dist/runtime/registry/google-analytics.js +15 -9
- package/dist/runtime/registry/google-maps.d.ts +3 -9
- package/dist/runtime/registry/google-maps.js +2 -8
- package/dist/runtime/registry/google-recaptcha.d.ts +2 -6
- package/dist/runtime/registry/google-recaptcha.js +4 -12
- package/dist/runtime/registry/google-sign-in.d.ts +2 -13
- package/dist/runtime/registry/google-sign-in.js +2 -22
- package/dist/runtime/registry/google-tag-manager.d.ts +8 -29
- package/dist/runtime/registry/google-tag-manager.js +14 -28
- package/dist/runtime/registry/gravatar.d.ts +26 -0
- package/dist/runtime/registry/gravatar.js +33 -0
- package/dist/runtime/registry/hotjar.d.ts +4 -6
- package/dist/runtime/registry/hotjar.js +2 -5
- package/dist/runtime/registry/instagram-embed.d.ts +3 -18
- package/dist/runtime/registry/instagram-embed.js +4 -19
- package/dist/runtime/registry/intercom.d.ts +5 -13
- package/dist/runtime/registry/intercom.js +2 -12
- package/dist/runtime/registry/matomo-analytics.d.ts +12 -15
- package/dist/runtime/registry/matomo-analytics.js +31 -13
- package/dist/runtime/registry/meta-pixel.d.ts +12 -8
- package/dist/runtime/registry/meta-pixel.js +12 -5
- package/dist/runtime/registry/mixpanel-analytics.d.ts +32 -0
- package/dist/runtime/registry/mixpanel-analytics.js +58 -0
- package/dist/runtime/registry/npm.d.ts +3 -7
- package/dist/runtime/registry/npm.js +2 -9
- package/dist/runtime/registry/paypal.d.ts +4 -25
- package/dist/runtime/registry/paypal.js +3 -66
- package/dist/runtime/registry/plausible-analytics.js +19 -14
- package/dist/runtime/registry/posthog.d.ts +18 -14
- package/dist/runtime/registry/posthog.js +18 -16
- package/dist/runtime/registry/reddit-pixel.d.ts +5 -6
- package/dist/runtime/registry/reddit-pixel.js +2 -4
- package/dist/runtime/registry/rybbit-analytics.d.ts +2 -14
- package/dist/runtime/registry/rybbit-analytics.js +10 -20
- package/dist/runtime/registry/schemas.d.ts +1047 -0
- package/dist/runtime/registry/schemas.js +1004 -0
- package/dist/runtime/registry/segment.d.ts +2 -5
- package/dist/runtime/registry/segment.js +2 -5
- package/dist/runtime/registry/snapchat-pixel.d.ts +5 -34
- package/dist/runtime/registry/snapchat-pixel.js +2 -20
- package/dist/runtime/registry/stripe.d.ts +3 -4
- package/dist/runtime/registry/stripe.js +2 -4
- package/dist/runtime/registry/tiktok-pixel.d.ts +20 -9
- package/dist/runtime/registry/tiktok-pixel.js +24 -7
- package/dist/runtime/registry/umami-analytics.d.ts +2 -31
- package/dist/runtime/registry/umami-analytics.js +2 -36
- package/dist/runtime/registry/vercel-analytics.d.ts +29 -0
- package/dist/runtime/registry/vercel-analytics.js +84 -0
- package/dist/runtime/registry/vimeo-player.d.ts +2 -2
- package/dist/runtime/registry/vimeo-player.js +1 -1
- package/dist/runtime/registry/x-embed.d.ts +3 -21
- package/dist/runtime/registry/x-embed.js +2 -21
- package/dist/runtime/registry/x-pixel.d.ts +4 -7
- package/dist/runtime/registry/x-pixel.js +2 -5
- package/dist/runtime/registry/youtube-player.d.ts +7 -7
- package/dist/runtime/registry/youtube-player.js +1 -1
- package/dist/runtime/server/bluesky-embed-image.d.ts +2 -0
- package/dist/runtime/server/bluesky-embed-image.js +7 -0
- package/dist/runtime/server/bluesky-embed.d.ts +2 -0
- package/dist/runtime/server/bluesky-embed.js +78 -0
- package/dist/runtime/server/google-maps-geocode-proxy.d.ts +2 -0
- package/dist/runtime/server/google-maps-geocode-proxy.js +38 -0
- package/dist/runtime/server/google-static-maps-proxy.d.ts +1 -1
- package/dist/runtime/server/google-static-maps-proxy.js +18 -23
- package/dist/runtime/server/gravatar-proxy.d.ts +2 -0
- package/dist/runtime/server/gravatar-proxy.js +46 -0
- package/dist/runtime/server/instagram-embed-asset.d.ts +1 -1
- package/dist/runtime/server/instagram-embed-asset.js +8 -41
- package/dist/runtime/server/instagram-embed-image.d.ts +1 -1
- package/dist/runtime/server/instagram-embed-image.js +6 -53
- package/dist/runtime/server/instagram-embed.d.ts +1 -0
- package/dist/runtime/server/instagram-embed.js +82 -40
- package/dist/runtime/server/proxy-handler.js +102 -85
- package/dist/runtime/server/utils/cached-upstream.d.ts +55 -0
- package/dist/runtime/server/utils/cached-upstream.js +65 -0
- package/dist/runtime/server/utils/embed-rewriters.d.ts +19 -0
- package/dist/runtime/server/utils/embed-rewriters.js +41 -0
- package/dist/runtime/server/utils/image-proxy.d.ts +14 -0
- package/dist/runtime/server/utils/image-proxy.js +73 -0
- package/dist/runtime/server/utils/instagram-embed.d.ts +16 -0
- package/dist/runtime/server/utils/instagram-embed.js +153 -0
- package/dist/runtime/server/utils/privacy.d.ts +1 -10
- package/dist/runtime/server/utils/privacy.js +60 -40
- package/dist/runtime/server/utils/proxy-url.d.ts +9 -0
- package/dist/runtime/server/utils/proxy-url.js +21 -0
- package/dist/runtime/server/utils/sign-constants.d.ts +16 -0
- package/dist/runtime/server/utils/sign-constants.js +5 -0
- package/dist/runtime/server/utils/sign.d.ts +101 -0
- package/dist/runtime/server/utils/sign.js +91 -0
- package/dist/runtime/server/utils/withSigning.d.ts +23 -0
- package/dist/runtime/server/utils/withSigning.js +19 -0
- package/dist/runtime/server/x-embed-image.d.ts +1 -1
- package/dist/runtime/server/x-embed-image.js +5 -49
- package/dist/runtime/server/x-embed.js +26 -6
- package/dist/runtime/types.d.ts +311 -55
- package/dist/runtime/types.js +1 -2
- package/dist/runtime/utils/pure.d.ts +1 -1
- package/dist/runtime/utils.d.ts +6 -4
- package/dist/runtime/utils.js +31 -14
- package/dist/stats.d.mts +202 -0
- package/dist/stats.d.ts +202 -0
- package/dist/stats.mjs +3835 -0
- package/dist/types-source.d.mts +17 -0
- package/dist/types-source.d.ts +17 -0
- package/dist/types-source.mjs +3787 -0
- package/dist/types.d.mts +4 -2
- package/package.json +41 -63
- package/README.md +0 -86
- package/dist/client/200.html +0 -1
- package/dist/client/404.html +0 -1
- package/dist/client/_nuxt/BJa0m50V.js +0 -1
- package/dist/client/_nuxt/BPQ3VLAy.js +0 -1
- package/dist/client/_nuxt/Ci5iXYuB.js +0 -1
- package/dist/client/_nuxt/DaI2y8Uz.js +0 -162
- package/dist/client/_nuxt/builds/latest.json +0 -1
- package/dist/client/_nuxt/builds/meta/9b4fb16a-3c62-48b0-8295-126cb077b5d3.json +0 -1
- package/dist/client/_nuxt/entry.D45OuV0w.css +0 -1
- package/dist/client/_nuxt/error-404.B57D-jUQ.css +0 -1
- package/dist/client/_nuxt/error-500.DTHUW7BI.css +0 -1
- package/dist/client/_nuxt/vPLZfVXe.js +0 -1
- package/dist/client/index.html +0 -1
- package/dist/runtime/components/ScriptPayPalMarks.d.vue.ts +0 -52
- package/dist/runtime/components/ScriptPayPalMarks.vue +0 -69
- package/dist/runtime/components/ScriptPayPalMarks.vue.d.ts +0 -52
- package/dist/runtime/validation/mock.d.ts +0 -42
- package/dist/runtime/validation/mock.js +0 -21
- package/dist/runtime/validation/valibot.d.ts +0 -1
- package/dist/runtime/validation/valibot.js +0 -1
- /package/dist/{client → devtools-client}/_nuxt/CVO1_9PV.js +0 -0
- /package/dist/{client → devtools-client}/_nuxt/Cp-IABpG.js +0 -0
- /package/dist/{client → devtools-client}/_nuxt/D0r3Knsf.js +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { defineEventHandler, getHeaders,
|
|
2
|
-
import { useRuntimeConfig } from "
|
|
3
|
-
import { useNitroApp } from "nitropack/runtime";
|
|
1
|
+
import { createError, defineEventHandler, getHeaders, getQuery, getRequestIP, getRequestWebStream, readBody, setResponseHeader } from "h3";
|
|
2
|
+
import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
|
|
4
3
|
import {
|
|
5
|
-
SENSITIVE_HEADERS,
|
|
6
4
|
anonymizeIP,
|
|
5
|
+
mergePrivacy,
|
|
7
6
|
normalizeLanguage,
|
|
8
7
|
normalizeUserAgent,
|
|
9
|
-
stripPayloadFingerprinting,
|
|
10
8
|
resolvePrivacy,
|
|
11
|
-
|
|
9
|
+
SENSITIVE_HEADERS,
|
|
10
|
+
stripPayloadFingerprinting
|
|
12
11
|
} from "./utils/privacy.js";
|
|
12
|
+
const COMPRESSION_RE = /gzip|deflate|br|compress|base64/i;
|
|
13
|
+
const CLIENT_HINT_VERSION_RE = /;v="(\d+)\.[^"]*"/g;
|
|
14
|
+
const SKIP_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["set-cookie", "transfer-encoding", "content-encoding", "content-length"]);
|
|
13
15
|
function stripQueryFingerprinting(query, privacy) {
|
|
14
16
|
const stripped = stripPayloadFingerprinting(query, privacy);
|
|
15
17
|
const params = new URLSearchParams();
|
|
@@ -18,11 +20,10 @@ function stripQueryFingerprinting(query, privacy) {
|
|
|
18
20
|
params.set(key, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
|
-
return params.toString();
|
|
23
|
+
return { queryString: params.toString(), stripped };
|
|
22
24
|
}
|
|
23
25
|
export default defineEventHandler(async (event) => {
|
|
24
26
|
const config = useRuntimeConfig();
|
|
25
|
-
const nitro = useNitroApp();
|
|
26
27
|
const proxyConfig = config["nuxt-scripts-proxy"];
|
|
27
28
|
if (!proxyConfig) {
|
|
28
29
|
throw createError({
|
|
@@ -30,72 +31,79 @@ export default defineEventHandler(async (event) => {
|
|
|
30
31
|
statusMessage: "First-party proxy not configured"
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
const {
|
|
34
|
+
const { proxyPrefix, domainPrivacy, privacy: globalPrivacy, debug = import.meta.dev } = proxyConfig;
|
|
34
35
|
const path = event.path;
|
|
35
36
|
const log = debug ? (message, ...args) => {
|
|
36
37
|
console.debug(message, ...args);
|
|
37
38
|
} : () => {
|
|
38
39
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
const afterPrefix = path.slice(proxyPrefix.length + 1);
|
|
41
|
+
const slashIdx = afterPrefix.indexOf("/");
|
|
42
|
+
const domain = slashIdx > 0 ? afterPrefix.slice(0, slashIdx) : afterPrefix;
|
|
43
|
+
const remainingPath = slashIdx > 0 ? afterPrefix.slice(slashIdx) : "/";
|
|
44
|
+
if (!domain) {
|
|
45
|
+
log("[proxy] No domain in path:", path);
|
|
46
|
+
throw createError({
|
|
47
|
+
statusCode: 404,
|
|
48
|
+
statusMessage: "No proxy domain found",
|
|
49
|
+
message: `No domain in proxy path: ${path}`
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
let perScriptInput;
|
|
53
|
+
for (const [configDomain, privacyInput] of Object.entries(domainPrivacy)) {
|
|
54
|
+
if (domain === configDomain || domain.endsWith(`.${configDomain}`)) {
|
|
55
|
+
perScriptInput = privacyInput;
|
|
50
56
|
break;
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
|
-
if (
|
|
54
|
-
log("[proxy]
|
|
59
|
+
if (perScriptInput === void 0) {
|
|
60
|
+
log("[proxy] Rejected: domain not in allowlist:", domain);
|
|
55
61
|
throw createError({
|
|
56
|
-
statusCode:
|
|
57
|
-
statusMessage: "
|
|
58
|
-
message: `
|
|
62
|
+
statusCode: 403,
|
|
63
|
+
statusMessage: "Domain not allowed",
|
|
64
|
+
message: `Proxy domain not in allowlist: ${domain}`
|
|
59
65
|
});
|
|
60
66
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
log("[proxy] WARNING: No privacy config for route", matchedRoutePattern, "\u2014 defaulting to full anonymization");
|
|
64
|
-
}
|
|
67
|
+
const targetBase = `https://${domain}`;
|
|
68
|
+
log("[proxy] Matched:", domain, "->", targetBase);
|
|
65
69
|
const perScriptResolved = resolvePrivacy(perScriptInput ?? true);
|
|
66
70
|
const privacy = globalPrivacy !== void 0 ? mergePrivacy(perScriptResolved, globalPrivacy) : perScriptResolved;
|
|
67
71
|
const anyPrivacy = privacy.ip || privacy.userAgent || privacy.language || privacy.screen || privacy.timezone || privacy.hardware;
|
|
68
72
|
const originalHeaders = getHeaders(event);
|
|
73
|
+
const originalQuery = getQuery(event);
|
|
69
74
|
const contentType = originalHeaders["content-type"] || "";
|
|
70
|
-
const compressionParam =
|
|
75
|
+
const compressionParam = originalQuery.compression || "";
|
|
71
76
|
const isBinaryBody = Boolean(
|
|
72
|
-
originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam &&
|
|
77
|
+
originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam && COMPRESSION_RE.test(compressionParam)
|
|
73
78
|
);
|
|
74
|
-
let
|
|
75
|
-
|
|
76
|
-
targetPath = "/" + targetPath;
|
|
77
|
-
}
|
|
78
|
-
let targetUrl = targetBase + targetPath;
|
|
79
|
+
let targetUrl = targetBase + remainingPath;
|
|
80
|
+
let strippedQueryRecord;
|
|
79
81
|
if (anyPrivacy) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
if (Object.keys(originalQuery).length > 0) {
|
|
83
|
+
const { queryString, stripped } = stripQueryFingerprinting(originalQuery, privacy);
|
|
84
|
+
strippedQueryRecord = stripped;
|
|
83
85
|
const basePath = targetUrl.split("?")[0] || targetUrl;
|
|
84
|
-
targetUrl =
|
|
86
|
+
targetUrl = queryString ? `${basePath}?${queryString}` : basePath;
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
const headers = {};
|
|
88
90
|
for (const [key, value] of Object.entries(originalHeaders)) {
|
|
89
|
-
if (!value)
|
|
91
|
+
if (!value)
|
|
92
|
+
continue;
|
|
90
93
|
const lowerKey = key.toLowerCase();
|
|
91
|
-
if (
|
|
94
|
+
if (lowerKey === "host")
|
|
95
|
+
continue;
|
|
96
|
+
if (SENSITIVE_HEADERS.includes(lowerKey))
|
|
97
|
+
continue;
|
|
92
98
|
if (lowerKey === "content-length") {
|
|
93
|
-
if (anyPrivacy && !isBinaryBody)
|
|
99
|
+
if (anyPrivacy && !isBinaryBody)
|
|
100
|
+
continue;
|
|
94
101
|
headers[lowerKey] = value;
|
|
95
102
|
continue;
|
|
96
103
|
}
|
|
97
104
|
if (lowerKey === "x-forwarded-for" || lowerKey === "x-real-ip" || lowerKey === "forwarded" || lowerKey === "cf-connecting-ip" || lowerKey === "true-client-ip" || lowerKey === "x-client-ip" || lowerKey === "x-cluster-client-ip") {
|
|
98
|
-
if (privacy.ip)
|
|
105
|
+
if (privacy.ip)
|
|
106
|
+
continue;
|
|
99
107
|
headers[lowerKey] = value;
|
|
100
108
|
continue;
|
|
101
109
|
}
|
|
@@ -108,11 +116,12 @@ export default defineEventHandler(async (event) => {
|
|
|
108
116
|
continue;
|
|
109
117
|
}
|
|
110
118
|
if (lowerKey === "sec-ch-ua" || lowerKey === "sec-ch-ua-full-version-list") {
|
|
111
|
-
headers[lowerKey] = privacy.hardware ? value.replace(
|
|
119
|
+
headers[lowerKey] = privacy.hardware ? value.replace(CLIENT_HINT_VERSION_RE, ';v="$1"') : value;
|
|
112
120
|
continue;
|
|
113
121
|
}
|
|
114
122
|
if (lowerKey === "sec-ch-ua-platform-version" || lowerKey === "sec-ch-ua-arch" || lowerKey === "sec-ch-ua-model" || lowerKey === "sec-ch-ua-bitness") {
|
|
115
|
-
if (privacy.hardware)
|
|
123
|
+
if (privacy.hardware)
|
|
124
|
+
continue;
|
|
116
125
|
headers[lowerKey] = value;
|
|
117
126
|
continue;
|
|
118
127
|
}
|
|
@@ -134,7 +143,6 @@ export default defineEventHandler(async (event) => {
|
|
|
134
143
|
let rawBody;
|
|
135
144
|
let passthroughBody = false;
|
|
136
145
|
const method = event.method?.toUpperCase();
|
|
137
|
-
const originalQuery = getQuery(event);
|
|
138
146
|
const isWriteMethod = method === "POST" || method === "PUT" || method === "PATCH";
|
|
139
147
|
if (isWriteMethod) {
|
|
140
148
|
if (isBinaryBody || !anyPrivacy) {
|
|
@@ -149,36 +157,50 @@ export default defineEventHandler(async (event) => {
|
|
|
149
157
|
} else if (typeof rawBody === "object") {
|
|
150
158
|
body = stripPayloadFingerprinting(rawBody, privacy);
|
|
151
159
|
} else if (typeof rawBody === "string") {
|
|
152
|
-
if (
|
|
153
|
-
let parsed = null;
|
|
154
|
-
try {
|
|
155
|
-
parsed = JSON.parse(rawBody);
|
|
156
|
-
} catch {
|
|
157
|
-
}
|
|
158
|
-
if (Array.isArray(parsed)) {
|
|
159
|
-
body = parsed.map(
|
|
160
|
-
(item) => item && typeof item === "object" && !Array.isArray(item) ? stripPayloadFingerprinting(item, privacy) : item
|
|
161
|
-
);
|
|
162
|
-
} else if (parsed && typeof parsed === "object") {
|
|
163
|
-
body = stripPayloadFingerprinting(parsed, privacy);
|
|
164
|
-
} else {
|
|
165
|
-
body = rawBody;
|
|
166
|
-
}
|
|
167
|
-
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
160
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
168
161
|
const params = new URLSearchParams(rawBody);
|
|
169
162
|
const obj = {};
|
|
170
|
-
params.
|
|
171
|
-
|
|
172
|
-
|
|
163
|
+
for (const [key, value] of params.entries()) {
|
|
164
|
+
if (key in obj) {
|
|
165
|
+
const existing = obj[key];
|
|
166
|
+
obj[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
167
|
+
} else {
|
|
168
|
+
obj[key] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
173
171
|
const stripped = stripPayloadFingerprinting(obj, privacy);
|
|
174
|
-
const
|
|
172
|
+
const out = new URLSearchParams();
|
|
175
173
|
for (const [k, v] of Object.entries(stripped)) {
|
|
176
|
-
if (v === void 0 || v === null)
|
|
177
|
-
|
|
174
|
+
if (v === void 0 || v === null)
|
|
175
|
+
continue;
|
|
176
|
+
if (Array.isArray(v)) {
|
|
177
|
+
for (const item of v)
|
|
178
|
+
out.append(k, typeof item === "string" ? item : JSON.stringify(item));
|
|
179
|
+
} else {
|
|
180
|
+
out.append(k, typeof v === "string" ? v : JSON.stringify(v));
|
|
181
|
+
}
|
|
178
182
|
}
|
|
179
|
-
body =
|
|
183
|
+
body = out.toString();
|
|
180
184
|
} else {
|
|
181
|
-
|
|
185
|
+
const maybeJson = contentType.includes("json") || (rawBody.startsWith("{") || rawBody.startsWith("["));
|
|
186
|
+
if (maybeJson) {
|
|
187
|
+
let parsed = null;
|
|
188
|
+
try {
|
|
189
|
+
parsed = JSON.parse(rawBody);
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
if (Array.isArray(parsed)) {
|
|
193
|
+
body = parsed.map(
|
|
194
|
+
(item) => item && typeof item === "object" && !Array.isArray(item) ? stripPayloadFingerprinting(item, privacy) : item
|
|
195
|
+
);
|
|
196
|
+
} else if (parsed && typeof parsed === "object") {
|
|
197
|
+
body = stripPayloadFingerprinting(parsed, privacy);
|
|
198
|
+
} else {
|
|
199
|
+
body = rawBody;
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
body = rawBody;
|
|
203
|
+
}
|
|
182
204
|
}
|
|
183
205
|
} else {
|
|
184
206
|
body = rawBody;
|
|
@@ -186,6 +208,7 @@ export default defineEventHandler(async (event) => {
|
|
|
186
208
|
}
|
|
187
209
|
}
|
|
188
210
|
}
|
|
211
|
+
const nitro = useNitroApp();
|
|
189
212
|
await nitro.hooks.callHook("nuxt-scripts:proxy", {
|
|
190
213
|
timestamp: Date.now(),
|
|
191
214
|
path: event.path,
|
|
@@ -200,7 +223,7 @@ export default defineEventHandler(async (event) => {
|
|
|
200
223
|
},
|
|
201
224
|
stripped: {
|
|
202
225
|
headers,
|
|
203
|
-
query:
|
|
226
|
+
query: strippedQueryRecord ?? originalQuery,
|
|
204
227
|
body: passthroughBody ? "<passthrough>" : body ?? null
|
|
205
228
|
}
|
|
206
229
|
});
|
|
@@ -226,24 +249,18 @@ export default defineEventHandler(async (event) => {
|
|
|
226
249
|
duplex: passthroughBody ? "half" : void 0
|
|
227
250
|
});
|
|
228
251
|
} catch (err) {
|
|
229
|
-
|
|
230
|
-
log("[proxy] Fetch error:", err instanceof Error ? err.message : err);
|
|
231
|
-
if (path.includes("/collect") || path.includes("/tr") || path.includes("/events")) {
|
|
232
|
-
event.node.res.statusCode = 204;
|
|
233
|
-
return "";
|
|
234
|
-
}
|
|
235
|
-
const isTimeout = err instanceof Error && (err.message.includes("aborted") || err.message.includes("timeout"));
|
|
252
|
+
log("[proxy] Upstream error:", err);
|
|
236
253
|
throw createError({
|
|
237
|
-
statusCode:
|
|
238
|
-
statusMessage:
|
|
239
|
-
message:
|
|
254
|
+
statusCode: 502,
|
|
255
|
+
statusMessage: "Bad Gateway",
|
|
256
|
+
message: `Proxy upstream request failed: ${targetUrl}`
|
|
240
257
|
});
|
|
258
|
+
} finally {
|
|
259
|
+
clearTimeout(timeoutId);
|
|
241
260
|
}
|
|
242
|
-
clearTimeout(timeoutId);
|
|
243
261
|
log("[proxy] Response:", response.status, response.statusText);
|
|
244
|
-
const skipHeaders = ["set-cookie", "transfer-encoding", "content-encoding", "content-length"];
|
|
245
262
|
response.headers.forEach((value, key) => {
|
|
246
|
-
if (!
|
|
263
|
+
if (!SKIP_RESPONSE_HEADERS.has(key.toLowerCase())) {
|
|
247
264
|
setResponseHeader(event, key, value);
|
|
248
265
|
}
|
|
249
266
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
/**
|
|
3
|
+
* Server-side caches for upstream proxy fetches.
|
|
4
|
+
*
|
|
5
|
+
* ## Why
|
|
6
|
+
*
|
|
7
|
+
* Proxy URLs arriving from the client carry per-request auth artefacts (`sig`,
|
|
8
|
+
* `_pt`, `_ts`) that change across renders. CDNs key on full URL so each
|
|
9
|
+
* rotation produces a unique edge cache entry and upstream origins take the hit
|
|
10
|
+
* on every render. Caching the *upstream response* here — keyed on the inner
|
|
11
|
+
* resource URL (or normalized param set) — dedupes those fetches across every
|
|
12
|
+
* request that resolves to the same upstream, regardless of how the caller
|
|
13
|
+
* authenticated.
|
|
14
|
+
*
|
|
15
|
+
* Safe because `withSigning` runs before any cache path: unsigned requests 403
|
|
16
|
+
* before they can do a cache lookup. Cache stores hold only responses produced
|
|
17
|
+
* from legitimately-authenticated requests.
|
|
18
|
+
*
|
|
19
|
+
* ## Binary payloads
|
|
20
|
+
*
|
|
21
|
+
* Image/blob responses are stored as base64 strings so they round-trip cleanly
|
|
22
|
+
* through every unstorage driver (memory, filesystem, redis, cloudflare kv).
|
|
23
|
+
* The 33% size overhead is tolerable; the alternative is relying on each driver
|
|
24
|
+
* to preserve Buffer/ArrayBuffer which is not universal.
|
|
25
|
+
*/
|
|
26
|
+
export interface CachedBinaryResponse {
|
|
27
|
+
base64: string;
|
|
28
|
+
contentType: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface CachedBinaryFetchOptions {
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
timeout?: number;
|
|
33
|
+
redirect?: 'follow' | 'manual';
|
|
34
|
+
ignoreResponseError?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface CachedBinaryResult extends CachedBinaryResponse {
|
|
37
|
+
body: Buffer;
|
|
38
|
+
status: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Cache upstream binary/image fetches. Returns a helper that restores the
|
|
42
|
+
* response body as a Buffer so the handler can pipe it straight to the client.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createCachedBinaryFetch(name: string, maxAge: number): (url: string, opts?: CachedBinaryFetchOptions) => Promise<CachedBinaryResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Cache upstream JSON/text fetches. `getKey` is caller-controlled so handlers
|
|
47
|
+
* can normalize on whichever inner params identify the resource (tweet ID,
|
|
48
|
+
* post URL, query hash).
|
|
49
|
+
*/
|
|
50
|
+
export declare function createCachedJsonFetch<T>(name: string, maxAge: number, getKey: (url: string, opts?: {
|
|
51
|
+
headers?: Record<string, string>;
|
|
52
|
+
}) => string): (url: string, opts?: {
|
|
53
|
+
headers?: Record<string, string>;
|
|
54
|
+
timeout?: number;
|
|
55
|
+
}) => Promise<T>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { defineCachedFunction } from "nitropack/runtime";
|
|
3
|
+
import { $fetch } from "ofetch";
|
|
4
|
+
export function createCachedBinaryFetch(name, maxAge) {
|
|
5
|
+
const cached = defineCachedFunction(
|
|
6
|
+
async (url, opts) => {
|
|
7
|
+
const response = await $fetch.raw(url, {
|
|
8
|
+
responseType: "arrayBuffer",
|
|
9
|
+
timeout: opts?.timeout ?? 1e4,
|
|
10
|
+
redirect: opts?.redirect ?? "follow",
|
|
11
|
+
ignoreResponseError: opts?.ignoreResponseError ?? false,
|
|
12
|
+
headers: opts?.headers
|
|
13
|
+
});
|
|
14
|
+
const data = response._data;
|
|
15
|
+
return {
|
|
16
|
+
base64: data ? Buffer.from(data).toString("base64") : "",
|
|
17
|
+
contentType: response.headers.get("content-type"),
|
|
18
|
+
status: response.status
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name,
|
|
23
|
+
maxAge,
|
|
24
|
+
swr: true,
|
|
25
|
+
staleMaxAge: maxAge,
|
|
26
|
+
getKey: (url, opts) => {
|
|
27
|
+
if (!opts)
|
|
28
|
+
return url;
|
|
29
|
+
const parts = [url];
|
|
30
|
+
if (opts.headers) {
|
|
31
|
+
const entries = Object.entries(opts.headers).sort(([a], [b]) => a.localeCompare(b));
|
|
32
|
+
for (const [k, v] of entries)
|
|
33
|
+
parts.push(`${k}=${v}`);
|
|
34
|
+
}
|
|
35
|
+
if (opts.redirect)
|
|
36
|
+
parts.push(`redirect=${opts.redirect}`);
|
|
37
|
+
return parts.join("|");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
return async (url, opts) => {
|
|
42
|
+
const result = await cached(url, opts);
|
|
43
|
+
return {
|
|
44
|
+
...result,
|
|
45
|
+
body: result.base64 ? Buffer.from(result.base64, "base64") : Buffer.alloc(0)
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function createCachedJsonFetch(name, maxAge, getKey) {
|
|
50
|
+
return defineCachedFunction(
|
|
51
|
+
async (url, opts) => {
|
|
52
|
+
return await $fetch(url, {
|
|
53
|
+
timeout: opts?.timeout ?? 1e4,
|
|
54
|
+
headers: opts?.headers
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name,
|
|
59
|
+
maxAge,
|
|
60
|
+
swr: true,
|
|
61
|
+
staleMaxAge: maxAge,
|
|
62
|
+
getKey
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutate a tweet (and any quoted tweet) in place so every raw CDN image URL
|
|
3
|
+
* is rewritten to route through the site's `/embed/x-image` proxy. When a
|
|
4
|
+
* `secret` is provided, URLs are HMAC-signed and pass `withSigning` without a
|
|
5
|
+
* page token.
|
|
6
|
+
*
|
|
7
|
+
* Clone the input first if it came from a shared cache — this function does
|
|
8
|
+
* not copy.
|
|
9
|
+
*/
|
|
10
|
+
export declare function rewriteTweetImages(tweet: any, imagePath: string, secret?: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Mutate a Bluesky post in place so every CDN image URL routes through the
|
|
13
|
+
* site's `/embed/bluesky-image` proxy. Covers author avatar, embedded images
|
|
14
|
+
* (thumb + fullsize), and external embed thumbnails.
|
|
15
|
+
*
|
|
16
|
+
* Clone the input first if it came from a shared cache — this function does
|
|
17
|
+
* not copy.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rewriteBlueskyPostImages(post: any, imagePath: string, secret?: string): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { buildProxyUrl } from "./proxy-url.js";
|
|
2
|
+
export function rewriteTweetImages(tweet, imagePath, secret) {
|
|
3
|
+
if (!tweet)
|
|
4
|
+
return;
|
|
5
|
+
if (tweet.user?.profile_image_url_https)
|
|
6
|
+
tweet.user.profile_image_url_https = buildProxyUrl(imagePath, { url: tweet.user.profile_image_url_https }, secret);
|
|
7
|
+
if (tweet.photos) {
|
|
8
|
+
for (const photo of tweet.photos) {
|
|
9
|
+
if (photo.url)
|
|
10
|
+
photo.url = buildProxyUrl(imagePath, { url: photo.url }, secret);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (tweet.entities?.media) {
|
|
14
|
+
for (const media of tweet.entities.media) {
|
|
15
|
+
if (media.media_url_https)
|
|
16
|
+
media.media_url_https = buildProxyUrl(imagePath, { url: media.media_url_https }, secret);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (tweet.video?.poster)
|
|
20
|
+
tweet.video.poster = buildProxyUrl(imagePath, { url: tweet.video.poster }, secret);
|
|
21
|
+
if (tweet.quoted_tweet)
|
|
22
|
+
rewriteTweetImages(tweet.quoted_tweet, imagePath, secret);
|
|
23
|
+
}
|
|
24
|
+
export function rewriteBlueskyPostImages(post, imagePath, secret) {
|
|
25
|
+
if (!post)
|
|
26
|
+
return;
|
|
27
|
+
const proxy = (url) => url ? buildProxyUrl(imagePath, { url }, secret) : url;
|
|
28
|
+
if (post.author?.avatar)
|
|
29
|
+
post.author.avatar = proxy(post.author.avatar);
|
|
30
|
+
const embed = post.embed;
|
|
31
|
+
if (embed?.images) {
|
|
32
|
+
for (const image of embed.images) {
|
|
33
|
+
if (image.thumb)
|
|
34
|
+
image.thumb = proxy(image.thumb);
|
|
35
|
+
if (image.fullsize)
|
|
36
|
+
image.fullsize = proxy(image.fullsize);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (embed?.external?.thumb)
|
|
40
|
+
embed.external.thumb = proxy(embed.external.thumb);
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ImageProxyConfig {
|
|
2
|
+
allowedDomains: string[] | ((hostname: string) => boolean);
|
|
3
|
+
accept?: string;
|
|
4
|
+
userAgent?: string;
|
|
5
|
+
cacheMaxAge?: number;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
/** Follow redirects (default: true). Set to false to reject redirects (SSRF protection). */
|
|
8
|
+
followRedirects?: boolean;
|
|
9
|
+
/** Decode & in URL query parameter */
|
|
10
|
+
decodeAmpersands?: boolean;
|
|
11
|
+
/** Unique name for the nitro cache group (defaults to derived from allowedDomains). */
|
|
12
|
+
cacheName?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function createImageProxyHandler(config: ImageProxyConfig): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Buffer<ArrayBufferLike>>>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
|
+
import { createCachedBinaryFetch } from "./cached-upstream.js";
|
|
3
|
+
import { withSigning } from "./withSigning.js";
|
|
4
|
+
const AMP_RE = /&/g;
|
|
5
|
+
export function createImageProxyHandler(config) {
|
|
6
|
+
const {
|
|
7
|
+
accept = "image/webp,image/jpeg,image/png,image/*,*/*;q=0.8",
|
|
8
|
+
userAgent,
|
|
9
|
+
cacheMaxAge = 3600,
|
|
10
|
+
contentType = "image/jpeg",
|
|
11
|
+
followRedirects = true,
|
|
12
|
+
decodeAmpersands = false,
|
|
13
|
+
cacheName = Array.isArray(config.allowedDomains) ? `nuxt-scripts-img:${config.allowedDomains[0] || "default"}` : "nuxt-scripts-img:custom"
|
|
14
|
+
} = config;
|
|
15
|
+
const cachedFetch = createCachedBinaryFetch(cacheName, cacheMaxAge);
|
|
16
|
+
return withSigning(defineEventHandler(async (event) => {
|
|
17
|
+
const query = getQuery(event);
|
|
18
|
+
let url = query.url;
|
|
19
|
+
if (decodeAmpersands && url)
|
|
20
|
+
url = url.replace(AMP_RE, "&");
|
|
21
|
+
if (!url) {
|
|
22
|
+
throw createError({
|
|
23
|
+
statusCode: 400,
|
|
24
|
+
statusMessage: "Image URL is required"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
let parsedUrl;
|
|
28
|
+
try {
|
|
29
|
+
parsedUrl = new URL(url);
|
|
30
|
+
} catch {
|
|
31
|
+
throw createError({
|
|
32
|
+
statusCode: 400,
|
|
33
|
+
statusMessage: "Invalid image URL"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
37
|
+
throw createError({
|
|
38
|
+
statusCode: 400,
|
|
39
|
+
statusMessage: "Invalid URL scheme"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const domainAllowed = typeof config.allowedDomains === "function" ? config.allowedDomains(parsedUrl.hostname) : config.allowedDomains.includes(parsedUrl.hostname);
|
|
43
|
+
if (!domainAllowed) {
|
|
44
|
+
throw createError({
|
|
45
|
+
statusCode: 403,
|
|
46
|
+
statusMessage: "Domain not allowed"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const headers = { Accept: accept };
|
|
50
|
+
if (userAgent)
|
|
51
|
+
headers["User-Agent"] = userAgent;
|
|
52
|
+
const result = await cachedFetch(url, {
|
|
53
|
+
timeout: 5e3,
|
|
54
|
+
redirect: followRedirects ? "follow" : "manual",
|
|
55
|
+
ignoreResponseError: !followRedirects,
|
|
56
|
+
headers
|
|
57
|
+
}).catch((error) => {
|
|
58
|
+
throw createError({
|
|
59
|
+
statusCode: error.statusCode || 500,
|
|
60
|
+
statusMessage: error.statusMessage || "Failed to fetch image"
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
if (!followRedirects && result.status >= 300 && result.status < 400) {
|
|
64
|
+
throw createError({
|
|
65
|
+
statusCode: 403,
|
|
66
|
+
statusMessage: "Redirects not allowed"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
setHeader(event, "Content-Type", result.contentType || contentType);
|
|
70
|
+
setHeader(event, "Cache-Control", `public, max-age=${cacheMaxAge}, s-maxage=${cacheMaxAge}`);
|
|
71
|
+
return result.body;
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const RSRC_RE: RegExp;
|
|
2
|
+
export declare const AMP_RE: RegExp;
|
|
3
|
+
export declare const SCONTENT_RE: RegExp;
|
|
4
|
+
export declare const STATIC_CDN_RE: RegExp;
|
|
5
|
+
export declare const LOOKASIDE_RE: RegExp;
|
|
6
|
+
export declare const INSTAGRAM_IMAGE_HOSTS: string[];
|
|
7
|
+
export declare const INSTAGRAM_ASSET_HOST = "static.cdninstagram.com";
|
|
8
|
+
export declare function proxyImageUrl(url: string, prefix?: string, secret?: string): string;
|
|
9
|
+
export declare function proxyAssetUrl(url: string, prefix?: string, secret?: string): string;
|
|
10
|
+
export declare function rewriteUrl(url: string, prefix?: string, secret?: string): string;
|
|
11
|
+
export declare function rewriteUrlsInText(text: string, prefix?: string, secret?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Scope CSS rules under a parent selector and strip global/page-level rules.
|
|
14
|
+
* Removes :root, html, body selectors and @charset/@import at-rules.
|
|
15
|
+
*/
|
|
16
|
+
export declare function scopeCss(css: string, scopeSelector: string): string;
|