@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.
Files changed (300) hide show
  1. package/bin/cli.mjs +2 -0
  2. package/dist/cli.d.mts +2 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.mjs +50 -0
  5. package/dist/devtools-client/200.html +1 -0
  6. package/dist/devtools-client/404.html +1 -0
  7. package/dist/devtools-client/_fonts/4ppnHhMi-pBsWSPo7mY0avYxlDoAg1N3PTzCwXLZ5rA-d9oibkGnTd1JL3tc_xnaVgBLYmOB8kjrK2cvZaqwj9s.woff2 +0 -0
  8. package/dist/devtools-client/_fonts/4qBuU9MRVUlPZNPSF7Xom_sK8RBEnfYu-9VXFrdq8A8-8TDwLE1HAj1sQn7XxVWtM_7sIaPM-DTdO3Pf8U2DF1U.woff2 +0 -0
  9. package/dist/devtools-client/_fonts/6dYsbWUd_BpKJ7mdDihgOcya1gHXLpJBuMYXux3WMjE-q3fYNS8YbW5n7ZeXI2vSNgkRWW5VDPKAl51SNTjG2qk.woff2 +0 -0
  10. package/dist/devtools-client/_fonts/Lr-hqqZZsYmCt0ITUlr1CUrWim9fsKvoDFZliMxgNHY-iTa_Yt_PzhOY9TX7ZXdSlEPim6iRt92xhECwaxWxd5w.woff2 +0 -0
  11. package/dist/devtools-client/_fonts/OknHvWI6KtYn1JQBzX7eSpNDBQ8520F9TvSUJYkVf6A-xeZn9253svK_8Q2LD0XEruY_MnEsuCRO5LenPoggC0Y.woff2 +0 -0
  12. package/dist/devtools-client/_fonts/PV2hrQG6wq5BlIPDjdL1IcOflycaghyt5MHzlBqZtlo-lb_WexLz3VZqfTN0oi554iBH5tT2j2UFEV-XErCAS3E.woff2 +0 -0
  13. package/dist/devtools-client/_fonts/UA7OtwYHwGN_HjcVGTdmiQxUit7FlqkCwxVUWSeXVnQ-B4OXCFOL_tWrYODpQTc07aMaj0c2cewTOmBRWR9tD-A.woff2 +0 -0
  14. package/dist/devtools-client/_fonts/VE4cDVCv5MxbFM7ZLoLCGbIpNd71zhp7MDI9lmN5Y7I-xZyDYCUVrd6LV8eVGF3Um3UZjBFuUtDGtvdyTBBRYBo.woff2 +0 -0
  15. package/dist/devtools-client/_fonts/fVoGbnMbBFd5L9BBp9fUPavUSkZ_EmsQNSyadkT-108-U4T0khaeLQSIhtt9eVvaCEKJjtWJ4ioRJOf8hvqkWY0.woff2 +0 -0
  16. package/dist/devtools-client/_fonts/lQAxeCEs1R0Lw-H9XRU1RlOARQN8J6npRsPjyEDMe5s-_DUSLEkO3tKTuun_gSnDLoQPVEnpOnyqZMOw0ByZ6PA.woff2 +0 -0
  17. package/dist/devtools-client/_fonts/lntlqNHKLV2n82yTwMde70QqOjcfLE2XJ5oKZ3vRPWc-z6TxpIZQdWXztWLr9_OFWqt_WJJoeGtuK_-XQMZGQwE.woff2 +0 -0
  18. package/dist/devtools-client/_fonts/qxAYvKsXWeYv731eb-h5TRurcdIP_W44mpNdX-HABAk-zUDeMEFlNtNbrwvT9JxLEBg0TphGy70O6RfIoIX_ZwU.woff2 +0 -0
  19. package/dist/devtools-client/_nuxt/B8PEiB0p.js +1 -0
  20. package/dist/devtools-client/_nuxt/BgPDxVUn.js +1 -0
  21. package/dist/devtools-client/_nuxt/BmlapxLP.js +1 -0
  22. package/dist/devtools-client/_nuxt/CM2vefXI.js +188 -0
  23. package/dist/devtools-client/_nuxt/DAF5Qk9P.js +1 -0
  24. package/dist/devtools-client/_nuxt/Dx6HhVmj.js +1 -0
  25. package/dist/devtools-client/_nuxt/S8LiR9M1.js +1 -0
  26. package/dist/devtools-client/_nuxt/builds/latest.json +1 -0
  27. package/dist/devtools-client/_nuxt/builds/meta/5458a3f2-af35-479c-8852-bf6f92fed611.json +1 -0
  28. package/dist/devtools-client/_nuxt/entry.BKkVrcJj.css +1 -0
  29. package/dist/devtools-client/_nuxt/error-404.d44aGwWI.css +1 -0
  30. package/dist/devtools-client/_nuxt/error-500.NthMfIEt.css +1 -0
  31. package/dist/devtools-client/_nuxt/first-party.C8Ha4JLM.css +1 -0
  32. package/dist/devtools-client/_nuxt/index.DZD1lwyI.css +1 -0
  33. package/dist/devtools-client/_nuxt/registry.B9lnjF_b.css +1 -0
  34. package/dist/devtools-client/_nuxt/vBkR1GJq.js +1 -0
  35. package/dist/devtools-client/_nuxt/wDzz0qaB.js +1 -0
  36. package/dist/devtools-client/docs/index.html +1 -0
  37. package/dist/devtools-client/first-party/index.html +1 -0
  38. package/dist/devtools-client/index.html +1 -0
  39. package/dist/devtools-client/registry/index.html +1 -0
  40. package/dist/module.d.mts +89 -80
  41. package/dist/module.d.ts +185 -0
  42. package/dist/module.json +1 -1
  43. package/dist/module.mjs +1056 -756
  44. package/dist/registry.d.mts +92 -4
  45. package/dist/registry.d.ts +94 -0
  46. package/dist/registry.mjs +668 -326
  47. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +77 -165
  48. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +148 -227
  49. package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +77 -165
  50. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.d.vue.ts +6 -55
  51. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +12 -83
  52. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue.d.ts +6 -55
  53. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.d.vue.ts +5 -1
  54. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue +24 -38
  55. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue.d.ts +5 -1
  56. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.d.vue.ts +43 -0
  57. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.vue +60 -0
  58. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsGeoJson.vue.d.ts +43 -0
  59. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.d.vue.ts +4 -0
  60. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +22 -26
  61. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue.d.ts +4 -0
  62. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.d.vue.ts +11 -8
  63. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +57 -57
  64. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue.d.ts +11 -8
  65. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.d.vue.ts +24 -42
  66. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +71 -74
  67. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue.d.ts +24 -42
  68. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +19 -20
  69. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +85 -38
  70. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +19 -20
  71. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.d.vue.ts +98 -0
  72. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue +263 -0
  73. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue.d.ts +98 -0
  74. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.d.vue.ts +10 -3
  75. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue +9 -41
  76. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue.d.ts +10 -3
  77. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.d.vue.ts +7 -3
  78. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue +23 -38
  79. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue.d.ts +7 -3
  80. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.d.vue.ts +7 -3
  81. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue +23 -38
  82. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue.d.ts +7 -3
  83. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.d.vue.ts +7 -3
  84. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue +24 -38
  85. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue.d.ts +7 -3
  86. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.d.vue.ts +200 -0
  87. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +170 -0
  88. package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue.d.ts +200 -0
  89. package/dist/runtime/components/GoogleMaps/bindGoogleMapsEvents.d.ts +13 -0
  90. package/dist/runtime/components/GoogleMaps/bindGoogleMapsEvents.js +8 -0
  91. package/dist/runtime/components/GoogleMaps/injectionKeys.d.ts +10 -0
  92. package/dist/runtime/components/GoogleMaps/injectionKeys.js +2 -0
  93. package/dist/runtime/components/GoogleMaps/types.d.ts +42 -0
  94. package/dist/runtime/components/GoogleMaps/types.js +1 -0
  95. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.d.ts +98 -0
  96. package/dist/runtime/components/GoogleMaps/useGoogleMapsResource.js +126 -0
  97. package/dist/runtime/components/ScriptBlueskyEmbed.d.vue.ts +83 -0
  98. package/dist/runtime/components/ScriptBlueskyEmbed.vue +91 -0
  99. package/dist/runtime/components/ScriptBlueskyEmbed.vue.d.ts +83 -0
  100. package/dist/runtime/components/ScriptCarbonAds.d.vue.ts +4 -7
  101. package/dist/runtime/components/ScriptCarbonAds.vue +1 -0
  102. package/dist/runtime/components/ScriptCarbonAds.vue.d.ts +4 -7
  103. package/dist/runtime/components/ScriptCrisp.d.vue.ts +7 -11
  104. package/dist/runtime/components/ScriptCrisp.vue +2 -1
  105. package/dist/runtime/components/ScriptCrisp.vue.d.ts +7 -11
  106. package/dist/runtime/components/ScriptGoogleAdsense.d.vue.ts +4 -7
  107. package/dist/runtime/components/ScriptGoogleAdsense.vue +2 -1
  108. package/dist/runtime/components/ScriptGoogleAdsense.vue.d.ts +4 -7
  109. package/dist/runtime/components/ScriptGravatar.d.vue.ts +22 -0
  110. package/dist/runtime/components/ScriptGravatar.vue +46 -0
  111. package/dist/runtime/components/ScriptGravatar.vue.d.ts +22 -0
  112. package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +12 -15
  113. package/dist/runtime/components/ScriptInstagramEmbed.vue +11 -3
  114. package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +12 -15
  115. package/dist/runtime/components/ScriptIntercom.d.vue.ts +7 -11
  116. package/dist/runtime/components/ScriptIntercom.vue +5 -3
  117. package/dist/runtime/components/ScriptIntercom.vue.d.ts +7 -11
  118. package/dist/runtime/components/ScriptLemonSqueezy.d.vue.ts +2 -3
  119. package/dist/runtime/components/ScriptLemonSqueezy.vue +1 -0
  120. package/dist/runtime/components/ScriptLemonSqueezy.vue.d.ts +2 -3
  121. package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +43 -37
  122. package/dist/runtime/components/ScriptPayPalButtons.vue +49 -79
  123. package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +43 -37
  124. package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +37 -28
  125. package/dist/runtime/components/ScriptPayPalMessages.vue +47 -50
  126. package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +37 -28
  127. package/dist/runtime/components/ScriptStripePricingTable.d.vue.ts +5 -9
  128. package/dist/runtime/components/ScriptStripePricingTable.vue +3 -2
  129. package/dist/runtime/components/ScriptStripePricingTable.vue.d.ts +5 -9
  130. package/dist/runtime/components/ScriptVimeoPlayer.d.vue.ts +17 -11
  131. package/dist/runtime/components/ScriptVimeoPlayer.vue +14 -10
  132. package/dist/runtime/components/ScriptVimeoPlayer.vue.d.ts +17 -11
  133. package/dist/runtime/components/ScriptXEmbed.d.vue.ts +10 -14
  134. package/dist/runtime/components/ScriptXEmbed.vue +21 -12
  135. package/dist/runtime/components/ScriptXEmbed.vue.d.ts +10 -14
  136. package/dist/runtime/components/ScriptYouTubePlayer.d.vue.ts +10 -15
  137. package/dist/runtime/components/ScriptYouTubePlayer.vue +12 -5
  138. package/dist/runtime/components/ScriptYouTubePlayer.vue.d.ts +10 -15
  139. package/dist/runtime/composables/useScript.js +159 -8
  140. package/dist/runtime/composables/useScriptEventPage.js +2 -2
  141. package/dist/runtime/composables/useScriptProxyToken.d.ts +12 -0
  142. package/dist/runtime/composables/useScriptProxyToken.js +4 -0
  143. package/dist/runtime/composables/useScriptProxyUrl.d.ts +12 -0
  144. package/dist/runtime/composables/useScriptProxyUrl.js +27 -0
  145. package/dist/runtime/composables/useScriptTriggerConsent.d.ts +10 -0
  146. package/dist/runtime/composables/useScriptTriggerConsent.js +33 -20
  147. package/dist/runtime/composables/useScriptTriggerElement.js +1 -1
  148. package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +1 -1
  149. package/dist/runtime/devtools-standalone-bridge.client.d.ts +8 -0
  150. package/dist/runtime/devtools-standalone-bridge.client.js +50 -0
  151. package/dist/runtime/plugins/proxy-token.server.d.ts +10 -0
  152. package/dist/runtime/plugins/proxy-token.server.js +17 -0
  153. package/dist/runtime/registry/bing-uet.d.ts +198 -0
  154. package/dist/runtime/registry/bing-uet.js +43 -0
  155. package/dist/runtime/registry/bluesky-embed.d.ts +112 -0
  156. package/dist/runtime/registry/bluesky-embed.js +68 -0
  157. package/dist/runtime/registry/clarity.d.ts +16 -17
  158. package/dist/runtime/registry/clarity.js +33 -31
  159. package/dist/runtime/registry/cloudflare-web-analytics.d.ts +2 -13
  160. package/dist/runtime/registry/cloudflare-web-analytics.js +2 -14
  161. package/dist/runtime/registry/crisp.d.ts +10 -40
  162. package/dist/runtime/registry/crisp.js +2 -33
  163. package/dist/runtime/registry/databuddy-analytics.d.ts +2 -35
  164. package/dist/runtime/registry/databuddy-analytics.js +20 -45
  165. package/dist/runtime/registry/fathom-analytics.d.ts +7 -26
  166. package/dist/runtime/registry/fathom-analytics.js +3 -25
  167. package/dist/runtime/registry/google-adsense.d.ts +3 -11
  168. package/dist/runtime/registry/google-adsense.js +2 -11
  169. package/dist/runtime/registry/google-analytics.d.ts +9 -7
  170. package/dist/runtime/registry/google-analytics.js +15 -9
  171. package/dist/runtime/registry/google-maps.d.ts +3 -9
  172. package/dist/runtime/registry/google-maps.js +2 -8
  173. package/dist/runtime/registry/google-recaptcha.d.ts +2 -6
  174. package/dist/runtime/registry/google-recaptcha.js +4 -12
  175. package/dist/runtime/registry/google-sign-in.d.ts +2 -13
  176. package/dist/runtime/registry/google-sign-in.js +2 -22
  177. package/dist/runtime/registry/google-tag-manager.d.ts +8 -29
  178. package/dist/runtime/registry/google-tag-manager.js +14 -28
  179. package/dist/runtime/registry/gravatar.d.ts +26 -0
  180. package/dist/runtime/registry/gravatar.js +33 -0
  181. package/dist/runtime/registry/hotjar.d.ts +4 -6
  182. package/dist/runtime/registry/hotjar.js +2 -5
  183. package/dist/runtime/registry/instagram-embed.d.ts +3 -18
  184. package/dist/runtime/registry/instagram-embed.js +4 -19
  185. package/dist/runtime/registry/intercom.d.ts +5 -13
  186. package/dist/runtime/registry/intercom.js +2 -12
  187. package/dist/runtime/registry/matomo-analytics.d.ts +12 -15
  188. package/dist/runtime/registry/matomo-analytics.js +31 -13
  189. package/dist/runtime/registry/meta-pixel.d.ts +12 -8
  190. package/dist/runtime/registry/meta-pixel.js +12 -5
  191. package/dist/runtime/registry/mixpanel-analytics.d.ts +32 -0
  192. package/dist/runtime/registry/mixpanel-analytics.js +58 -0
  193. package/dist/runtime/registry/npm.d.ts +3 -7
  194. package/dist/runtime/registry/npm.js +2 -9
  195. package/dist/runtime/registry/paypal.d.ts +4 -25
  196. package/dist/runtime/registry/paypal.js +3 -66
  197. package/dist/runtime/registry/plausible-analytics.js +19 -14
  198. package/dist/runtime/registry/posthog.d.ts +18 -14
  199. package/dist/runtime/registry/posthog.js +18 -16
  200. package/dist/runtime/registry/reddit-pixel.d.ts +5 -6
  201. package/dist/runtime/registry/reddit-pixel.js +2 -4
  202. package/dist/runtime/registry/rybbit-analytics.d.ts +2 -14
  203. package/dist/runtime/registry/rybbit-analytics.js +10 -20
  204. package/dist/runtime/registry/schemas.d.ts +1047 -0
  205. package/dist/runtime/registry/schemas.js +1004 -0
  206. package/dist/runtime/registry/segment.d.ts +2 -5
  207. package/dist/runtime/registry/segment.js +2 -5
  208. package/dist/runtime/registry/snapchat-pixel.d.ts +5 -34
  209. package/dist/runtime/registry/snapchat-pixel.js +2 -20
  210. package/dist/runtime/registry/stripe.d.ts +3 -4
  211. package/dist/runtime/registry/stripe.js +2 -4
  212. package/dist/runtime/registry/tiktok-pixel.d.ts +20 -9
  213. package/dist/runtime/registry/tiktok-pixel.js +24 -7
  214. package/dist/runtime/registry/umami-analytics.d.ts +2 -31
  215. package/dist/runtime/registry/umami-analytics.js +2 -36
  216. package/dist/runtime/registry/vercel-analytics.d.ts +29 -0
  217. package/dist/runtime/registry/vercel-analytics.js +84 -0
  218. package/dist/runtime/registry/vimeo-player.d.ts +2 -2
  219. package/dist/runtime/registry/vimeo-player.js +1 -1
  220. package/dist/runtime/registry/x-embed.d.ts +3 -21
  221. package/dist/runtime/registry/x-embed.js +2 -21
  222. package/dist/runtime/registry/x-pixel.d.ts +4 -7
  223. package/dist/runtime/registry/x-pixel.js +2 -5
  224. package/dist/runtime/registry/youtube-player.d.ts +7 -7
  225. package/dist/runtime/registry/youtube-player.js +1 -1
  226. package/dist/runtime/server/bluesky-embed-image.d.ts +2 -0
  227. package/dist/runtime/server/bluesky-embed-image.js +7 -0
  228. package/dist/runtime/server/bluesky-embed.d.ts +2 -0
  229. package/dist/runtime/server/bluesky-embed.js +78 -0
  230. package/dist/runtime/server/google-maps-geocode-proxy.d.ts +2 -0
  231. package/dist/runtime/server/google-maps-geocode-proxy.js +38 -0
  232. package/dist/runtime/server/google-static-maps-proxy.d.ts +1 -1
  233. package/dist/runtime/server/google-static-maps-proxy.js +18 -23
  234. package/dist/runtime/server/gravatar-proxy.d.ts +2 -0
  235. package/dist/runtime/server/gravatar-proxy.js +46 -0
  236. package/dist/runtime/server/instagram-embed-asset.d.ts +1 -1
  237. package/dist/runtime/server/instagram-embed-asset.js +8 -41
  238. package/dist/runtime/server/instagram-embed-image.d.ts +1 -1
  239. package/dist/runtime/server/instagram-embed-image.js +6 -53
  240. package/dist/runtime/server/instagram-embed.d.ts +1 -0
  241. package/dist/runtime/server/instagram-embed.js +82 -40
  242. package/dist/runtime/server/proxy-handler.js +102 -85
  243. package/dist/runtime/server/utils/cached-upstream.d.ts +55 -0
  244. package/dist/runtime/server/utils/cached-upstream.js +65 -0
  245. package/dist/runtime/server/utils/embed-rewriters.d.ts +19 -0
  246. package/dist/runtime/server/utils/embed-rewriters.js +41 -0
  247. package/dist/runtime/server/utils/image-proxy.d.ts +14 -0
  248. package/dist/runtime/server/utils/image-proxy.js +73 -0
  249. package/dist/runtime/server/utils/instagram-embed.d.ts +16 -0
  250. package/dist/runtime/server/utils/instagram-embed.js +153 -0
  251. package/dist/runtime/server/utils/privacy.d.ts +1 -10
  252. package/dist/runtime/server/utils/privacy.js +60 -40
  253. package/dist/runtime/server/utils/proxy-url.d.ts +9 -0
  254. package/dist/runtime/server/utils/proxy-url.js +21 -0
  255. package/dist/runtime/server/utils/sign-constants.d.ts +16 -0
  256. package/dist/runtime/server/utils/sign-constants.js +5 -0
  257. package/dist/runtime/server/utils/sign.d.ts +101 -0
  258. package/dist/runtime/server/utils/sign.js +91 -0
  259. package/dist/runtime/server/utils/withSigning.d.ts +23 -0
  260. package/dist/runtime/server/utils/withSigning.js +19 -0
  261. package/dist/runtime/server/x-embed-image.d.ts +1 -1
  262. package/dist/runtime/server/x-embed-image.js +5 -49
  263. package/dist/runtime/server/x-embed.js +26 -6
  264. package/dist/runtime/types.d.ts +311 -55
  265. package/dist/runtime/types.js +1 -2
  266. package/dist/runtime/utils/pure.d.ts +1 -1
  267. package/dist/runtime/utils.d.ts +6 -4
  268. package/dist/runtime/utils.js +31 -14
  269. package/dist/stats.d.mts +202 -0
  270. package/dist/stats.d.ts +202 -0
  271. package/dist/stats.mjs +3835 -0
  272. package/dist/types-source.d.mts +17 -0
  273. package/dist/types-source.d.ts +17 -0
  274. package/dist/types-source.mjs +3787 -0
  275. package/dist/types.d.mts +4 -2
  276. package/package.json +41 -63
  277. package/README.md +0 -86
  278. package/dist/client/200.html +0 -1
  279. package/dist/client/404.html +0 -1
  280. package/dist/client/_nuxt/BJa0m50V.js +0 -1
  281. package/dist/client/_nuxt/BPQ3VLAy.js +0 -1
  282. package/dist/client/_nuxt/Ci5iXYuB.js +0 -1
  283. package/dist/client/_nuxt/DaI2y8Uz.js +0 -162
  284. package/dist/client/_nuxt/builds/latest.json +0 -1
  285. package/dist/client/_nuxt/builds/meta/9b4fb16a-3c62-48b0-8295-126cb077b5d3.json +0 -1
  286. package/dist/client/_nuxt/entry.D45OuV0w.css +0 -1
  287. package/dist/client/_nuxt/error-404.B57D-jUQ.css +0 -1
  288. package/dist/client/_nuxt/error-500.DTHUW7BI.css +0 -1
  289. package/dist/client/_nuxt/vPLZfVXe.js +0 -1
  290. package/dist/client/index.html +0 -1
  291. package/dist/runtime/components/ScriptPayPalMarks.d.vue.ts +0 -52
  292. package/dist/runtime/components/ScriptPayPalMarks.vue +0 -69
  293. package/dist/runtime/components/ScriptPayPalMarks.vue.d.ts +0 -52
  294. package/dist/runtime/validation/mock.d.ts +0 -42
  295. package/dist/runtime/validation/mock.js +0 -21
  296. package/dist/runtime/validation/valibot.d.ts +0 -1
  297. package/dist/runtime/validation/valibot.js +0 -1
  298. /package/dist/{client → devtools-client}/_nuxt/CVO1_9PV.js +0 -0
  299. /package/dist/{client → devtools-client}/_nuxt/Cp-IABpG.js +0 -0
  300. /package/dist/{client → devtools-client}/_nuxt/D0r3Knsf.js +0 -0
@@ -1,15 +1,17 @@
1
- import { defineEventHandler, getHeaders, getRequestIP, readBody, getRequestWebStream, getQuery, setResponseHeader, createError } from "h3";
2
- import { useRuntimeConfig } from "#imports";
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
- mergePrivacy
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 { routes, privacy: globalPrivacy, routePrivacy, debug = import.meta.dev } = proxyConfig;
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
- let targetBase;
40
- let matchedPrefix;
41
- let matchedRoutePattern;
42
- const sortedRoutes = Object.entries(routes).sort((a, b) => b[0].length - a[0].length);
43
- for (const [routePattern, target] of sortedRoutes) {
44
- const prefix = routePattern.replace(/\/\*\*$/, "");
45
- if (path.startsWith(prefix)) {
46
- targetBase = target.replace(/\/\*\*$/, "");
47
- matchedPrefix = prefix;
48
- matchedRoutePattern = routePattern;
49
- log("[proxy] Matched:", prefix, "->", targetBase);
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 (!targetBase || !matchedPrefix || !matchedRoutePattern) {
54
- log("[proxy] No match for path:", path);
59
+ if (perScriptInput === void 0) {
60
+ log("[proxy] Rejected: domain not in allowlist:", domain);
55
61
  throw createError({
56
- statusCode: 404,
57
- statusMessage: "No proxy route matched",
58
- message: `No proxy target found for path: ${path}`
62
+ statusCode: 403,
63
+ statusMessage: "Domain not allowed",
64
+ message: `Proxy domain not in allowlist: ${domain}`
59
65
  });
60
66
  }
61
- const perScriptInput = routePrivacy[matchedRoutePattern];
62
- if (debug && perScriptInput === void 0) {
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 = new URL(event.path, "http://localhost").searchParams.get("compression");
75
+ const compressionParam = originalQuery.compression || "";
71
76
  const isBinaryBody = Boolean(
72
- originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam && /gzip|deflate|br|compress|base64/i.test(compressionParam)
77
+ originalHeaders["content-encoding"] || contentType.includes("octet-stream") || compressionParam && COMPRESSION_RE.test(compressionParam)
73
78
  );
74
- let targetPath = path.slice(matchedPrefix.length);
75
- if (targetPath && !targetPath.startsWith("/")) {
76
- targetPath = "/" + targetPath;
77
- }
78
- let targetUrl = targetBase + targetPath;
79
+ let targetUrl = targetBase + remainingPath;
80
+ let strippedQueryRecord;
79
81
  if (anyPrivacy) {
80
- const query = getQuery(event);
81
- if (Object.keys(query).length > 0) {
82
- const strippedQuery = stripQueryFingerprinting(query, privacy);
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 = strippedQuery ? `${basePath}?${strippedQuery}` : basePath;
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) continue;
91
+ if (!value)
92
+ continue;
90
93
  const lowerKey = key.toLowerCase();
91
- if (SENSITIVE_HEADERS.includes(lowerKey)) continue;
94
+ if (lowerKey === "host")
95
+ continue;
96
+ if (SENSITIVE_HEADERS.includes(lowerKey))
97
+ continue;
92
98
  if (lowerKey === "content-length") {
93
- if (anyPrivacy && !isBinaryBody) continue;
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) continue;
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(/;v="(\d+)\.[^"]*"/g, ';v="$1"') : value;
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) continue;
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 (rawBody.startsWith("{") || rawBody.startsWith("[")) {
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.forEach((value, key) => {
171
- obj[key] = value;
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 stringified = {};
172
+ const out = new URLSearchParams();
175
173
  for (const [k, v] of Object.entries(stripped)) {
176
- if (v === void 0 || v === null) continue;
177
- stringified[k] = typeof v === "string" ? v : JSON.stringify(v);
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 = new URLSearchParams(stringified).toString();
183
+ body = out.toString();
180
184
  } else {
181
- body = rawBody;
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: anyPrivacy ? stripPayloadFingerprinting(originalQuery, privacy) : originalQuery,
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
- clearTimeout(timeoutId);
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: isTimeout ? 504 : 502,
238
- statusMessage: isTimeout ? "Upstream timeout" : "Bad Gateway",
239
- message: "Failed to reach upstream"
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 (!skipHeaders.includes(key.toLowerCase())) {
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 &amp; 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 = /&amp;/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;