@nuxt/scripts 1.0.0-rc.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/devtools-client/200.html +1 -1
- package/dist/devtools-client/404.html +1 -1
- package/dist/devtools-client/_nuxt/{BBS9G2Kb.js → Br5kvbNb.js} +1 -1
- package/dist/devtools-client/_nuxt/C25MBdR1.js +1 -0
- package/dist/devtools-client/_nuxt/{DCBsJT4N.js → Cg_OIb5q.js} +1 -1
- package/dist/devtools-client/_nuxt/{B4uHpJPz.js → D2o5loaz.js} +1 -1
- package/dist/devtools-client/_nuxt/De7Wf2b9.js +188 -0
- package/dist/devtools-client/_nuxt/{Cxq4HLPL.js → DnVCfhVR.js} +1 -1
- package/dist/devtools-client/_nuxt/builds/latest.json +1 -1
- package/dist/devtools-client/_nuxt/builds/meta/9d868e70-bc5a-425c-8c84-8defe5186920.json +1 -0
- package/dist/devtools-client/_nuxt/{entry.BwpOBArY.css → entry.BSxy0W1q.css} +1 -1
- package/dist/devtools-client/_nuxt/index.DZD1lwyI.css +1 -0
- package/dist/devtools-client/_nuxt/{DvZScWzI.js → pN4-T8ZD.js} +1 -1
- 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.d.mts +15 -0
- package/dist/module.d.ts +15 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +35 -8
- package/dist/registry.mjs +3 -3
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +6 -2
- package/dist/runtime/components/ScriptBlueskyEmbed.d.vue.ts +0 -1
- package/dist/runtime/components/ScriptBlueskyEmbed.vue +12 -10
- package/dist/runtime/components/ScriptBlueskyEmbed.vue.d.ts +0 -1
- package/dist/runtime/components/ScriptInstagramEmbed.vue +3 -1
- package/dist/runtime/components/ScriptXEmbed.d.vue.ts +0 -1
- package/dist/runtime/components/ScriptXEmbed.vue +11 -9
- package/dist/runtime/components/ScriptXEmbed.vue.d.ts +0 -1
- package/dist/runtime/composables/useScript.js +17 -6
- 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/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 +189 -11
- package/dist/runtime/registry/bing-uet.js +16 -2
- package/dist/runtime/registry/bluesky-embed.d.ts +0 -4
- package/dist/runtime/registry/bluesky-embed.js +0 -4
- package/dist/runtime/registry/clarity.d.ts +6 -2
- package/dist/runtime/registry/clarity.js +12 -1
- package/dist/runtime/registry/google-analytics.d.ts +6 -2
- package/dist/runtime/registry/google-analytics.js +12 -1
- package/dist/runtime/registry/google-tag-manager.d.ts +6 -2
- package/dist/runtime/registry/google-tag-manager.js +10 -1
- package/dist/runtime/registry/gravatar.js +10 -13
- package/dist/runtime/registry/matomo-analytics.d.ts +9 -3
- package/dist/runtime/registry/matomo-analytics.js +28 -1
- package/dist/runtime/registry/meta-pixel.d.ts +8 -2
- package/dist/runtime/registry/meta-pixel.js +10 -1
- package/dist/runtime/registry/mixpanel-analytics.d.ts +12 -2
- package/dist/runtime/registry/mixpanel-analytics.js +16 -4
- package/dist/runtime/registry/posthog.d.ts +8 -2
- package/dist/runtime/registry/posthog.js +15 -4
- package/dist/runtime/registry/schemas.d.ts +65 -0
- package/dist/runtime/registry/schemas.js +75 -8
- package/dist/runtime/registry/tiktok-pixel.d.ts +16 -2
- package/dist/runtime/registry/tiktok-pixel.js +22 -1
- package/dist/runtime/registry/x-embed.d.ts +0 -4
- package/dist/runtime/registry/x-embed.js +0 -4
- package/dist/runtime/server/bluesky-embed-image.d.ts +1 -1
- package/dist/runtime/server/bluesky-embed.d.ts +1 -15
- package/dist/runtime/server/bluesky-embed.js +22 -4
- package/dist/runtime/server/google-maps-geocode-proxy.js +8 -5
- package/dist/runtime/server/google-static-maps-proxy.d.ts +1 -1
- package/dist/runtime/server/google-static-maps-proxy.js +13 -8
- package/dist/runtime/server/gravatar-proxy.d.ts +1 -1
- package/dist/runtime/server/gravatar-proxy.js +6 -7
- package/dist/runtime/server/instagram-embed-asset.d.ts +1 -1
- package/dist/runtime/server/instagram-embed-image.d.ts +1 -1
- package/dist/runtime/server/instagram-embed.js +22 -10
- 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 +3 -1
- package/dist/runtime/server/utils/image-proxy.js +8 -6
- package/dist/runtime/server/utils/instagram-embed.d.ts +4 -4
- package/dist/runtime/server/utils/instagram-embed.js +10 -9
- 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 +2 -10
- package/dist/runtime/server/utils/sign.js +8 -5
- package/dist/runtime/server/utils/withSigning.js +3 -2
- package/dist/runtime/server/x-embed-image.d.ts +1 -1
- package/dist/runtime/server/x-embed.js +20 -2
- package/dist/runtime/types.d.ts +24 -1
- package/dist/types-source.mjs +160 -12
- package/package.json +2 -2
- package/dist/devtools-client/_nuxt/CQR4zIAm.js +0 -1
- package/dist/devtools-client/_nuxt/DTxy5P8N.js +0 -188
- package/dist/devtools-client/_nuxt/builds/meta/484f72b9-a019-4127-8ab9-c10e92624094.json +0 -1
- package/dist/devtools-client/_nuxt/index.CA-OpSj0.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.script-status[data-v-5cf865ba]{align-items:center;border-radius:9999px;display:inline-flex;font-size:.6875rem;font-weight:600;gap:.375rem;letter-spacing:.01em;line-height:1.4;padding:.125rem .5rem}.script-status-dot[data-v-5cf865ba]{border-radius:50%;flex-shrink:0;height:6px;width:6px}.status-loaded[data-v-5cf865ba]{background:#6bc6701f;color:#006818;color:oklch(45% .15 145)}.status-loaded .script-status-dot[data-v-5cf865ba]{background:#11ad32;box-shadow:0 0 6px #11ad3280}.dark .status-loaded[data-v-5cf865ba]{background:#10782326;color:#75d079}.status-loading[data-v-5cf865ba]{background:#70b3f71a;color:#0065b0;color:oklch(50% .15 250)}.status-loading .script-status-dot[data-v-5cf865ba]{animation:pulse-dot-5cf865ba 1.5s ease-in-out infinite;background:#0083e0;background:oklch(60% .18 250)}.dark .status-loading[data-v-5cf865ba]{background:#23588a26;color:#70b3f7}.status-awaiting[data-v-5cf865ba]{background:#d9b9821a;color:#946900;color:oklch(55% .12 80)}.status-awaiting .script-status-dot[data-v-5cf865ba]{background:#cd9200;background:oklch(70% .15 80)}.dark .status-awaiting[data-v-5cf865ba]{background:#67522d26;color:#cfa761}.status-error[data-v-5cf865ba]{background:#ce70691a;color:#a83634}.status-error .script-status-dot[data-v-5cf865ba]{background:#de3b3d}.dark .status-error[data-v-5cf865ba]{background:#843c3826;color:#e6857e}.status-validation[data-v-5cf865ba]{background:#a890d41a;color:#6e519d}.status-validation .script-status-dot[data-v-5cf865ba]{background:#8f68cb}.dark .status-validation[data-v-5cf865ba]{background:#4e3d6c26;color:#b7a0e4}.status-unknown[data-v-5cf865ba]{background:var(--color-surface-sunken);color:var(--color-text-muted)}.status-unknown .script-status-dot[data-v-5cf865ba]{background:var(--color-neutral-400)}@keyframes pulse-dot-5cf865ba{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.85)}}.script-metric[data-v-b147450b]{align-items:center;background:var(--color-surface-sunken);border:1px solid var(--color-border-subtle);border-radius:9999px;color:var(--color-text-muted);display:inline-flex;font-family:var(--font-mono);font-size:.6875rem;font-weight:500;gap:.25rem;letter-spacing:-.01em;padding:.125rem .5rem}.script-metric[data-v-c6837c50]{align-items:center;background:#6bc67014;border:1px solid oklch(65% .15 145/.12);border-radius:9999px;color:#2f7434;display:inline-flex;font-family:var(--font-mono);font-size:.6875rem;font-weight:500;gap:.25rem;letter-spacing:-.01em;padding:.125rem .5rem}.dark .script-metric[data-v-c6837c50]{background:#2c63301f;border-color:#49814c26;color:#85cc87}.ui-tooltip-panel[data-v-16948115]{background:var(--color-surface-elevated);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:0 4px 12px #0000001a;color:var(--color-text);font-size:.75rem;font-weight:400;line-height:1.4;padding:.5rem .75rem;pointer-events:none;white-space:normal}.dark .ui-tooltip-panel[data-v-16948115]{box-shadow:0 4px 12px #0000004d}.waterfall-container[data-v-d16c88db]{display:flex;flex-direction:column;gap:.5rem;padding:.75rem}.waterfall-stats[data-v-d16c88db]{align-items:center;display:flex;font-size:.6875rem;gap:.5rem}.waterfall-stat[data-v-d16c88db]{align-items:baseline;display:inline-flex;font-variant-numeric:tabular-nums;gap:.25rem}.waterfall-stat-value[data-v-d16c88db]{color:var(--color-text);font-weight:700}.waterfall-stat-label[data-v-d16c88db]{color:var(--color-text-subtle)}.waterfall-sep[data-v-d16c88db]{background:var(--color-text-subtle);border-radius:50%;height:3px;opacity:.3;width:3px}.waterfall-proxied-badge[data-v-d16c88db]{align-items:center;color:#107823;display:inline-flex;gap:.25rem}.dark .waterfall-proxied-badge[data-v-d16c88db]{color:#85cc87}.domain-pill[data-v-d16c88db]{align-items:center;background:var(--color-surface-sunken);border:1px solid var(--color-border-subtle);border-radius:9999px;color:var(--color-text-subtle);display:inline-flex;font-family:var(--font-mono);font-size:.625rem;gap:.125rem;padding:.0625rem .375rem}.domain-pill-proxied[data-v-d16c88db]{background:#6bc67014;border-color:#4aa6511f;color:#2f7434}.dark .domain-pill-proxied[data-v-d16c88db]{background:#2f74341a;color:#8fc990}.waterfall-table[data-v-d16c88db]{background:var(--color-surface-elevated);border:1px solid var(--color-border-subtle);border-radius:var(--radius-md);overflow:hidden}.waterfall-legend[data-v-d16c88db]{align-items:center;background:var(--color-surface-sunken);border-bottom:1px solid var(--color-border-subtle);display:flex;gap:.75rem;padding:.25rem .5rem}.waterfall-legend-item[data-v-d16c88db]{align-items:center;color:var(--color-text-subtle);display:flex;font-size:.5625rem;font-weight:600;gap:.25rem;letter-spacing:.04em;text-transform:uppercase}.waterfall-legend-dot[data-v-d16c88db]{border-radius:2px;height:5px;width:5px}.waterfall-row[data-v-d16c88db]{align-items:center;cursor:default;display:flex;font-size:.6875rem;gap:.375rem;padding:.1875rem .5rem;transition:background .1s}.waterfall-row[data-v-d16c88db]:hover{background:var(--color-surface-sunken)}.waterfall-row-proxied[data-v-d16c88db]{background:#6bc67008}.waterfall-row-proxied[data-v-d16c88db]:hover{background:#6bc6700f}.waterfall-status[data-v-d16c88db]{border-radius:3px;flex-shrink:0;font-family:var(--font-mono);font-size:.625rem;font-weight:600;line-height:1;padding:.125rem 0;text-align:center;width:1.5rem}.waterfall-status-200[data-v-d16c88db]{background:#6bc6701a;color:#107823}.dark .waterfall-status-200[data-v-d16c88db]{background:#2f74341f;color:#85cc87}.waterfall-status-304[data-v-d16c88db]{background:#d9b9821a;color:#946900;color:oklch(55% .12 80)}.dark .waterfall-status-304[data-v-d16c88db]{background:#75603b1f;color:#cfa761}.waterfall-row-icon[data-v-d16c88db]{color:var(--color-text-subtle);flex-shrink:0;font-size:.625rem;opacity:.4}.waterfall-row-icon-proxied[data-v-d16c88db]{color:#278733;opacity:1}.dark .waterfall-row-icon-proxied[data-v-d16c88db]{color:#85cc87}.waterfall-url[data-v-d16c88db]{color:var(--color-text-muted);flex-shrink:0;font-family:var(--font-mono);font-size:.625rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:15rem}.waterfall-bar-track[data-v-d16c88db]{background:var(--color-surface-sunken);border-radius:3px;flex:1;height:.875rem;overflow:hidden;position:relative}.waterfall-bar[data-v-d16c88db]{border-radius:3px;display:flex;height:100%;overflow:hidden;position:absolute}.waterfall-duration[data-v-d16c88db]{color:var(--color-text-subtle);flex-shrink:0;font-family:var(--font-mono);font-size:.625rem;font-variant-numeric:tabular-nums;text-align:right;width:2.5rem}.devtools-snippet[data-v-265ccc31]{margin:.5rem .75rem}.devtools-snippet-header[data-v-265ccc31]{align-items:center;display:flex;justify-content:space-between;margin-bottom:.375rem}.devtools-snippet-label[data-v-265ccc31]{color:var(--color-text-muted);font-family:var(--font-mono);font-size:.6875rem;font-weight:500;letter-spacing:-.01em}.devtools-snippet-block[data-v-265ccc31]{border-radius:var(--radius-sm);font-size:.6875rem;line-height:1.6;max-height:300px;overflow-y:auto;padding:.5rem .625rem!important}.filter-bar[data-v-1d33b8c9]{align-items:center;display:flex;gap:.25rem;margin-bottom:.75rem;padding:0 .25rem}.filter-chip[data-v-1d33b8c9]{align-items:center;background:transparent;border:1px solid var(--color-border-subtle);border-radius:9999px;color:var(--color-text-subtle);cursor:pointer;display:inline-flex;font-size:.6875rem;font-weight:500;gap:.375rem;padding:.25rem .625rem;transition:all .15s}.filter-chip[data-v-1d33b8c9]:hover{border-color:var(--color-border);color:var(--color-text-muted)}.filter-chip-active[data-v-1d33b8c9]{background:var(--color-surface-sunken);border-color:var(--color-border);color:var(--color-text)}.filter-chip-count[data-v-1d33b8c9]{background:var(--color-surface-sunken);border-radius:9999px;color:var(--color-text-subtle);font-size:.625rem;font-variant-numeric:tabular-nums;min-width:1.25rem;padding:0 .25rem;text-align:center}.filter-chip-active .filter-chip-count[data-v-1d33b8c9]{background:var(--color-surface-elevated)}.sub-tab[data-v-1d33b8c9]{align-items:center;border-bottom:2px solid transparent;color:var(--color-text-subtle);cursor:pointer;display:flex;font-size:.75rem;font-weight:500;gap:.375rem;margin-bottom:-1px;padding:.5rem .75rem;transition:color .15s,border-color .15s}.sub-tab[data-v-1d33b8c9]:hover{color:var(--color-text-muted)}.sub-tab-active[data-v-1d33b8c9]{border-bottom-color:var(--seo-green);color:var(--color-text)}.event-timeline[data-v-1d33b8c9]{display:flex;flex-direction:column;gap:.125rem}.event-row[data-v-1d33b8c9]{align-items:center;border-radius:var(--radius-sm);display:flex;font-size:.6875rem;gap:.625rem;padding:.25rem .375rem;transition:background .1s}.event-row[data-v-1d33b8c9]:hover{background:var(--color-surface-sunken)}.event-time[data-v-1d33b8c9]{color:var(--color-text-subtle);font-family:var(--font-mono);font-size:.625rem;font-variant-numeric:tabular-nums;min-width:5.5rem;white-space:nowrap}.event-badge[data-v-1d33b8c9]{border-radius:9999px;display:inline-flex;font-size:.625rem;font-weight:600;letter-spacing:.01em;padding:.0625rem .375rem;white-space:nowrap}.event-fn[data-v-1d33b8c9]{background:var(--color-surface-sunken);border:1px solid var(--color-border-subtle);border-radius:var(--radius-sm);color:var(--color-text-muted);font-family:var(--font-mono);font-size:.6875rem;max-width:100%;overflow:hidden;padding:.0625rem .5rem;text-overflow:ellipsis;white-space:nowrap}.status-badge-loaded[data-v-1d33b8c9]{background:#6bc6701f;color:#006818;color:oklch(45% .15 145)}.dark .status-badge-loaded[data-v-1d33b8c9]{background:#10782326;color:#75d079}.status-badge-loading[data-v-1d33b8c9]{background:#d9b9821f;color:#946900;color:oklch(55% .12 80)}.dark .status-badge-loading[data-v-1d33b8c9]{background:#67522d26;color:#cfa761}.status-badge-awaiting[data-v-1d33b8c9]{background:var(--color-surface-sunken);color:var(--color-text-muted)}.status-badge-error[data-v-1d33b8c9]{background:#ce70691a;color:#a83634}.dark .status-badge-error[data-v-1d33b8c9]{background:#843c3826;color:#e6857e}.status-badge-validation[data-v-1d33b8c9]{background:#a890d41a;color:#6e519d}.dark .status-badge-validation[data-v-1d33b8c9]{background:#4e3d6c26;color:#b7a0e4}.status-badge-default[data-v-1d33b8c9]{background:var(--color-surface-sunken);color:var(--color-text-subtle)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{f as s,o,c as n,a as l,_ as r,g as a}from"./
|
|
1
|
+
import{f as s,o,c as n,a as l,_ as r,g as a}from"./De7Wf2b9.js";const _={class:"h-full max-h-full overflow-hidden"},u=["src","title"],i=s({__name:"DevtoolsDocs",props:{url:{}},setup(e){return(c,t)=>(o(),n("div",_,[l("iframe",{src:e.url,title:`Documentation - ${e.url}`,class:"w-full h-full border-none",style:{"min-height":"calc(100vh - 100px)"}},null,8,u)]))}}),f=Object.assign(i,{__name:"DevtoolsDocs"}),m={};function d(e,c){const t=f;return o(),a(t,{url:"https://scripts.nuxt.com"})}const p=r(m,[["render",d]]);export{p as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.BSxy0W1q.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/De7Wf2b9.js"><script type="module" src="/__nuxt-scripts/_nuxt/De7Wf2b9.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"9d868e70-bc5a-425c-8c84-8defe5186920",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1776270313716,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.BSxy0W1q.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/De7Wf2b9.js"><script type="module" src="/__nuxt-scripts/_nuxt/De7Wf2b9.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"9d868e70-bc5a-425c-8c84-8defe5186920",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1776270313717,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.BSxy0W1q.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/De7Wf2b9.js"><script type="module" src="/__nuxt-scripts/_nuxt/De7Wf2b9.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"9d868e70-bc5a-425c-8c84-8defe5186920",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1776270313718,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-scripts/_nuxt/entry.BSxy0W1q.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-scripts/_nuxt/De7Wf2b9.js"><script type="module" src="/__nuxt-scripts/_nuxt/De7Wf2b9.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-scripts",buildId:"9d868e70-bc5a-425c-8c84-8defe5186920",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1776270313718,false]</script></body></html>
|
package/dist/module.d.mts
CHANGED
|
@@ -120,6 +120,21 @@ interface ModuleOptions {
|
|
|
120
120
|
* @default true
|
|
121
121
|
*/
|
|
122
122
|
autoGenerateSecret?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* How long (in seconds) a page token issued during SSR remains valid on the
|
|
125
|
+
* client. Client-driven proxy requests (dynamic fetches, runtime image
|
|
126
|
+
* helpers) attach this token so `withSigning` accepts them without each URL
|
|
127
|
+
* being HMAC-signed up front.
|
|
128
|
+
*
|
|
129
|
+
* The default of 1 hour is safe for SSR; for SSG or prerendered routes,
|
|
130
|
+
* deployed HTML carries the build-time token, so bump this (e.g. `2592000`
|
|
131
|
+
* for 30 days) to keep client-side proxy calls working after the build.
|
|
132
|
+
* Longer TTLs widen the replay window if a token is scraped, so prefer the
|
|
133
|
+
* shortest value that covers your cache horizon.
|
|
134
|
+
*
|
|
135
|
+
* @default 3600
|
|
136
|
+
*/
|
|
137
|
+
pageTokenMaxAge?: number;
|
|
123
138
|
};
|
|
124
139
|
/**
|
|
125
140
|
* Google Static Maps proxy configuration.
|
package/dist/module.d.ts
CHANGED
|
@@ -120,6 +120,21 @@ interface ModuleOptions {
|
|
|
120
120
|
* @default true
|
|
121
121
|
*/
|
|
122
122
|
autoGenerateSecret?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* How long (in seconds) a page token issued during SSR remains valid on the
|
|
125
|
+
* client. Client-driven proxy requests (dynamic fetches, runtime image
|
|
126
|
+
* helpers) attach this token so `withSigning` accepts them without each URL
|
|
127
|
+
* being HMAC-signed up front.
|
|
128
|
+
*
|
|
129
|
+
* The default of 1 hour is safe for SSR; for SSG or prerendered routes,
|
|
130
|
+
* deployed HTML carries the build-time token, so bump this (e.g. `2592000`
|
|
131
|
+
* for 30 days) to keep client-side proxy calls working after the build.
|
|
132
|
+
* Longer TTLs widen the replay window if a token is scraped, so prefer the
|
|
133
|
+
* shortest value that covers your cache horizon.
|
|
134
|
+
*
|
|
135
|
+
* @default 3600
|
|
136
|
+
*/
|
|
137
|
+
pageTokenMaxAge?: number;
|
|
123
138
|
};
|
|
124
139
|
/**
|
|
125
140
|
* Google Static Maps proxy configuration.
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
2
|
import { existsSync, readFileSync, appendFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
3
|
-
import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, createResolver, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, addPluginTemplate, addServerHandler, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin } from '@nuxt/kit';
|
|
3
|
+
import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, createResolver, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, addPluginTemplate, addServerHandler, addImports, addComponentsDir, addTemplate, hasNuxtModule, addBuildPlugin, addPlugin } from '@nuxt/kit';
|
|
4
4
|
import { defu } from 'defu';
|
|
5
5
|
import { join, resolve } from 'pathe';
|
|
6
6
|
import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
|
|
@@ -288,7 +288,7 @@ function migrateDeprecatedRegistryKeys(registry, warn) {
|
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
|
-
function normalizeRegistryConfig(registry, warn) {
|
|
291
|
+
function normalizeRegistryConfig(registry, warn, componentOnlyKeys) {
|
|
292
292
|
for (const key of Object.keys(registry)) {
|
|
293
293
|
const entry = registry[key];
|
|
294
294
|
if (!entry) {
|
|
@@ -296,6 +296,10 @@ function normalizeRegistryConfig(registry, warn) {
|
|
|
296
296
|
continue;
|
|
297
297
|
}
|
|
298
298
|
if (entry === true) {
|
|
299
|
+
if (componentOnlyKeys?.has(key)) {
|
|
300
|
+
registry[key] = [{}];
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
299
303
|
warn?.(`[nuxt-scripts] registry.${key}: \`true\` shorthand is deprecated. Use \`{ trigger: 'onNuxtReady' }\` instead.`);
|
|
300
304
|
registry[key] = [{}, { trigger: "onNuxtReady" }];
|
|
301
305
|
continue;
|
|
@@ -1496,8 +1500,9 @@ const module$1 = defineNuxtModule({
|
|
|
1496
1500
|
}
|
|
1497
1501
|
const scripts = await registry(resolvePath);
|
|
1498
1502
|
if (config.registry) {
|
|
1503
|
+
const componentOnlyKeys = new Set(scripts.filter((s) => !s.import).map((s) => s.registryKey));
|
|
1499
1504
|
migrateDeprecatedRegistryKeys(config.registry, (msg) => logger.warn(msg));
|
|
1500
|
-
normalizeRegistryConfig(config.registry, (msg) => logger.warn(msg));
|
|
1505
|
+
normalizeRegistryConfig(config.registry, (msg) => logger.warn(msg), componentOnlyKeys);
|
|
1501
1506
|
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
1502
1507
|
const registryWithDefaults = {};
|
|
1503
1508
|
for (const [key, entry] of Object.entries(config.registry)) {
|
|
@@ -1550,6 +1555,8 @@ const module$1 = defineNuxtModule({
|
|
|
1550
1555
|
const composables = [
|
|
1551
1556
|
"useScript",
|
|
1552
1557
|
"useScriptEventPage",
|
|
1558
|
+
"useScriptProxyToken",
|
|
1559
|
+
"useScriptProxyUrl",
|
|
1553
1560
|
"useScriptTriggerConsent",
|
|
1554
1561
|
"useScriptTriggerElement",
|
|
1555
1562
|
"useScriptTriggerIdleTimeout",
|
|
@@ -1592,10 +1599,23 @@ const module$1 = defineNuxtModule({
|
|
|
1592
1599
|
const script = scripts.find((s) => s.registryKey === key);
|
|
1593
1600
|
if (!script?.schema)
|
|
1594
1601
|
continue;
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1602
|
+
const isComponentOnly = !script.import;
|
|
1603
|
+
if (isComponentOnly) {
|
|
1604
|
+
if (scriptOptions && "trigger" in scriptOptions && scriptOptions.trigger !== false) {
|
|
1605
|
+
const pascal = key.charAt(0).toUpperCase() + key.slice(1);
|
|
1606
|
+
logger.warn(
|
|
1607
|
+
`[nuxt-scripts] registry.${key}: \`trigger\` has no effect on component-only scripts. Render <Script${pascal}> in your template to load the embed.`
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
continue;
|
|
1611
|
+
}
|
|
1612
|
+
const willAutoLoad = scriptOptions && "trigger" in scriptOptions && scriptOptions.trigger !== false;
|
|
1613
|
+
if (willAutoLoad) {
|
|
1614
|
+
const requiredFields = extractRequiredFields(script.schema);
|
|
1615
|
+
const missing = requiredFields.filter((f) => !input[f]);
|
|
1616
|
+
if (missing.length) {
|
|
1617
|
+
logger.warn(`[nuxt-scripts] registry.${key}: missing required field${missing.length > 1 ? "s" : ""} ${missing.map((f) => `'${f}'`).join(", ")}. The script infrastructure is registered but will not function without ${missing.length > 1 ? "them" : "it"}.`);
|
|
1618
|
+
}
|
|
1599
1619
|
}
|
|
1600
1620
|
const envDefaultKeys = new Set(Object.keys(script.envDefaults || {}));
|
|
1601
1621
|
const userProvidedFields = Object.keys(input).filter((f) => !envDefaultKeys.has(f));
|
|
@@ -1830,7 +1850,14 @@ Options: configure platform rewrites, switch to server-rendered mode, or disable
|
|
|
1830
1850
|
else if (proxySecretResolved?.source === "memory-generated")
|
|
1831
1851
|
logger.warn(`[security] Generated an in-memory ${PROXY_SECRET_ENV_KEY} (could not write .env). Signed URLs will break across restarts.`);
|
|
1832
1852
|
if (proxySecretResolved?.secret) {
|
|
1833
|
-
nuxt.options.runtimeConfig["nuxt-scripts"]
|
|
1853
|
+
const scriptsRuntime = nuxt.options.runtimeConfig["nuxt-scripts"];
|
|
1854
|
+
scriptsRuntime.proxySecret = proxySecretResolved.secret;
|
|
1855
|
+
if (config.security?.pageTokenMaxAge !== void 0)
|
|
1856
|
+
scriptsRuntime.pageTokenMaxAge = config.security.pageTokenMaxAge;
|
|
1857
|
+
addPlugin({
|
|
1858
|
+
src: await resolvePath("./runtime/plugins/proxy-token.server"),
|
|
1859
|
+
mode: "server"
|
|
1860
|
+
});
|
|
1834
1861
|
} else if (!nuxt.options.dev) {
|
|
1835
1862
|
logger.warn(
|
|
1836
1863
|
`[security] ${PROXY_SECRET_ENV_KEY} is not set. Proxy endpoints will pass requests through without signature verification.
|
package/dist/registry.mjs
CHANGED
|
@@ -346,7 +346,7 @@ async function registry(resolve) {
|
|
|
346
346
|
return "https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";
|
|
347
347
|
}
|
|
348
348
|
},
|
|
349
|
-
partytown: { forwards: ["mixpanel", "mixpanel.init", "mixpanel.track", "mixpanel.identify", "mixpanel.people.set", "mixpanel.reset", "mixpanel.register"] }
|
|
349
|
+
partytown: { forwards: ["mixpanel", "mixpanel.init", "mixpanel.track", "mixpanel.identify", "mixpanel.people.set", "mixpanel.reset", "mixpanel.register", "mixpanel.opt_in_tracking", "mixpanel.opt_out_tracking"] }
|
|
350
350
|
}),
|
|
351
351
|
// ad
|
|
352
352
|
def("bingUet", {
|
|
@@ -401,7 +401,7 @@ async function registry(resolve) {
|
|
|
401
401
|
domains: ["analytics.tiktok.com", "mon.tiktok.com", "mcs.tiktok.com"],
|
|
402
402
|
privacy: PRIVACY_FULL
|
|
403
403
|
},
|
|
404
|
-
partytown: { forwards: ["ttq.track", "ttq.page", "ttq.identify"] }
|
|
404
|
+
partytown: { forwards: ["ttq.track", "ttq.page", "ttq.identify", "ttq.grantConsent", "ttq.revokeConsent", "ttq.holdConsent"] }
|
|
405
405
|
}),
|
|
406
406
|
def("snapchatPixel", {
|
|
407
407
|
schema: SnapTrPixelOptions,
|
|
@@ -503,7 +503,7 @@ async function registry(resolve) {
|
|
|
503
503
|
domains: ["www.clarity.ms", "scripts.clarity.ms", "d.clarity.ms", "e.clarity.ms", "k.clarity.ms", "c.clarity.ms", "a.clarity.ms", "b.clarity.ms"],
|
|
504
504
|
privacy: PRIVACY_HEATMAP
|
|
505
505
|
},
|
|
506
|
-
partytown: { forwards: [] }
|
|
506
|
+
partytown: { forwards: ["clarity"] }
|
|
507
507
|
}),
|
|
508
508
|
// payments
|
|
509
509
|
def("stripe", {
|
|
@@ -4,6 +4,7 @@ import { defu } from "defu";
|
|
|
4
4
|
import { useHead, useRuntimeConfig } from "nuxt/app";
|
|
5
5
|
import { withQuery } from "ufo";
|
|
6
6
|
import { computed, onMounted, ref } from "vue";
|
|
7
|
+
import { useScriptProxyUrl } from "../../composables/useScriptProxyUrl";
|
|
7
8
|
</script>
|
|
8
9
|
|
|
9
10
|
<script setup>
|
|
@@ -34,6 +35,7 @@ const runtimeConfig = useRuntimeConfig();
|
|
|
34
35
|
const proxyConfig = runtimeConfig.public["nuxt-scripts"]?.googleStaticMapsProxy;
|
|
35
36
|
const apiKey = props.apiKey || scriptRuntimeConfig("googleMaps")?.apiKey;
|
|
36
37
|
const useProxy = !props.apiKey && proxyConfig?.enabled;
|
|
38
|
+
const proxyUrl = useScriptProxyUrl();
|
|
37
39
|
if (import.meta.dev) {
|
|
38
40
|
if (!apiKey && !useProxy)
|
|
39
41
|
console.warn("[nuxt-scripts] ScriptGoogleMapsStaticMap requires a Google Maps API key with Static Maps API access. Set NUXT_PUBLIC_SCRIPTS_GOOGLE_MAPS_API_KEY in your .env, or enable the proxy via `scripts.registry.googleMaps`.");
|
|
@@ -122,8 +124,10 @@ const src = computed(() => {
|
|
|
122
124
|
if (query[key] === void 0)
|
|
123
125
|
delete query[key];
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
if (useProxy) {
|
|
128
|
+
return proxyUrl("/_scripts/proxy/google-static-maps", query);
|
|
129
|
+
}
|
|
130
|
+
return withQuery("https://maps.googleapis.com/maps/api/staticmap", query);
|
|
127
131
|
});
|
|
128
132
|
const imgAttributes = computed(() => {
|
|
129
133
|
return defu(props.imgAttrs, {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useAsyncData } from "nuxt/app";
|
|
3
3
|
import { computed } from "vue";
|
|
4
|
-
import {
|
|
4
|
+
import { useScriptProxyUrl } from "../composables/useScriptProxyUrl";
|
|
5
|
+
import { extractBlueskyPostId, facetsToHtml, formatBlueskyDate, formatCount } from "../registry/bluesky-embed";
|
|
5
6
|
import { requireRegistryEndpoint, scriptsPrefix } from "../utils";
|
|
6
7
|
const props = defineProps({
|
|
7
8
|
postUrl: { type: String, required: true },
|
|
@@ -15,11 +16,12 @@ const resolvedApiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed
|
|
|
15
16
|
const resolvedImageProxyEndpoint = computed(() => props.imageProxyEndpoint || `${prefix}/embed/bluesky-image`);
|
|
16
17
|
if (!props.apiEndpoint)
|
|
17
18
|
requireRegistryEndpoint("ScriptBlueskyEmbed", "blueskyEmbed");
|
|
19
|
+
const proxyUrl = useScriptProxyUrl();
|
|
18
20
|
const postId = computed(() => extractBlueskyPostId(props.postUrl));
|
|
19
21
|
const cacheKey = computed(() => `bluesky-embed-${postId.value?.actor}-${postId.value?.rkey}`);
|
|
20
22
|
const { data: post, status, error } = useAsyncData(
|
|
21
23
|
cacheKey,
|
|
22
|
-
() => $fetch(
|
|
24
|
+
() => $fetch(proxyUrl(resolvedApiEndpoint.value, { url: props.postUrl }))
|
|
23
25
|
);
|
|
24
26
|
const slotProps = computed(() => {
|
|
25
27
|
if (!post.value)
|
|
@@ -31,8 +33,7 @@ const slotProps = computed(() => {
|
|
|
31
33
|
// Author info
|
|
32
34
|
displayName: p.author.displayName,
|
|
33
35
|
handle: p.author.handle,
|
|
34
|
-
avatar:
|
|
35
|
-
avatarOriginal: p.author.avatar,
|
|
36
|
+
avatar: p.author.avatar,
|
|
36
37
|
isVerified: p.author.verification?.verifiedStatus === "valid",
|
|
37
38
|
// Post content
|
|
38
39
|
text: p.record.text,
|
|
@@ -49,10 +50,10 @@ const slotProps = computed(() => {
|
|
|
49
50
|
repliesFormatted: formatCount(p.replyCount),
|
|
50
51
|
quotes: p.quoteCount,
|
|
51
52
|
quotesFormatted: formatCount(p.quoteCount),
|
|
52
|
-
// Media
|
|
53
|
+
// Media (already proxied)
|
|
53
54
|
images: p.embed?.images?.map((img) => ({
|
|
54
|
-
thumb:
|
|
55
|
-
fullsize:
|
|
55
|
+
thumb: img.thumb,
|
|
56
|
+
fullsize: img.fullsize,
|
|
56
57
|
alt: img.alt,
|
|
57
58
|
aspectRatio: img.aspectRatio
|
|
58
59
|
})),
|
|
@@ -60,13 +61,14 @@ const slotProps = computed(() => {
|
|
|
60
61
|
uri: p.embed.external.uri,
|
|
61
62
|
title: p.embed.external.title,
|
|
62
63
|
description: p.embed.external.description,
|
|
63
|
-
thumb: p.embed.external.thumb
|
|
64
|
+
thumb: p.embed.external.thumb
|
|
64
65
|
} : void 0,
|
|
65
66
|
// Links
|
|
66
67
|
postUrl: props.postUrl,
|
|
67
68
|
authorUrl: `https://bsky.app/profile/${p.author.handle}`,
|
|
68
|
-
// Helpers
|
|
69
|
-
|
|
69
|
+
// Helpers — proxy an arbitrary URL through the image endpoint at runtime.
|
|
70
|
+
// Uses the page token emitted during SSR so client-generated URLs validate.
|
|
71
|
+
proxyImage: (url) => proxyUrl(resolvedImageProxyEndpoint.value, { url })
|
|
70
72
|
};
|
|
71
73
|
});
|
|
72
74
|
defineExpose({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useAsyncData } from "nuxt/app";
|
|
3
3
|
import { computed } from "vue";
|
|
4
|
+
import { useScriptProxyUrl } from "../composables/useScriptProxyUrl";
|
|
4
5
|
import { extractInstagramShortcode } from "../registry/instagram-embed";
|
|
5
6
|
import { requireRegistryEndpoint, scriptsPrefix } from "../utils";
|
|
6
7
|
const props = defineProps({
|
|
@@ -14,10 +15,11 @@ const prefix = scriptsPrefix();
|
|
|
14
15
|
const apiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed/instagram`);
|
|
15
16
|
if (!props.apiEndpoint)
|
|
16
17
|
requireRegistryEndpoint("ScriptInstagramEmbed", "instagramEmbed");
|
|
18
|
+
const proxyUrl = useScriptProxyUrl();
|
|
17
19
|
const shortcode = computed(() => extractInstagramShortcode(props.postUrl));
|
|
18
20
|
const { data: html, status, error } = useAsyncData(
|
|
19
21
|
`instagram-embed-${props.postUrl}`,
|
|
20
|
-
() => $fetch(
|
|
22
|
+
() => $fetch(proxyUrl(apiEndpoint.value, { url: props.postUrl, captions: props.captions })),
|
|
21
23
|
{ watch: [() => props.postUrl, () => props.captions] }
|
|
22
24
|
);
|
|
23
25
|
defineExpose({
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useAsyncData } from "nuxt/app";
|
|
3
3
|
import { computed } from "vue";
|
|
4
|
-
import {
|
|
4
|
+
import { useScriptProxyUrl } from "../composables/useScriptProxyUrl";
|
|
5
|
+
import { formatCount, formatTweetDate } from "../registry/x-embed";
|
|
5
6
|
import { requireRegistryEndpoint, scriptsPrefix } from "../utils";
|
|
6
7
|
const props = defineProps({
|
|
7
8
|
tweetId: { type: String, required: true },
|
|
@@ -15,10 +16,11 @@ const apiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed/x`);
|
|
|
15
16
|
const resolvedImageProxyEndpoint = computed(() => props.imageProxyEndpoint || `${prefix}/embed/x-image`);
|
|
16
17
|
if (!props.apiEndpoint)
|
|
17
18
|
requireRegistryEndpoint("ScriptXEmbed", "xEmbed");
|
|
19
|
+
const proxyUrl = useScriptProxyUrl();
|
|
18
20
|
const cacheKey = computed(() => `x-embed-${props.tweetId}`);
|
|
19
21
|
const { data: tweet, status, error } = useAsyncData(
|
|
20
22
|
cacheKey,
|
|
21
|
-
() => $fetch(
|
|
23
|
+
() => $fetch(proxyUrl(apiEndpoint.value, { id: props.tweetId }))
|
|
22
24
|
);
|
|
23
25
|
const slotProps = computed(() => {
|
|
24
26
|
if (!tweet.value)
|
|
@@ -30,8 +32,7 @@ const slotProps = computed(() => {
|
|
|
30
32
|
// User info
|
|
31
33
|
userName: t.user.name,
|
|
32
34
|
userHandle: t.user.screen_name,
|
|
33
|
-
userAvatar:
|
|
34
|
-
userAvatarOriginal: t.user.profile_image_url_https,
|
|
35
|
+
userAvatar: t.user.profile_image_url_https,
|
|
35
36
|
isVerified: t.user.verified || t.user.is_blue_verified,
|
|
36
37
|
// Tweet content
|
|
37
38
|
text: t.text,
|
|
@@ -42,14 +43,14 @@ const slotProps = computed(() => {
|
|
|
42
43
|
likesFormatted: formatCount(t.favorite_count),
|
|
43
44
|
replies: t.conversation_count,
|
|
44
45
|
repliesFormatted: formatCount(t.conversation_count),
|
|
45
|
-
// Media
|
|
46
|
+
// Media (already proxied)
|
|
46
47
|
photos: t.photos?.map((p) => ({
|
|
47
48
|
...p,
|
|
48
|
-
proxiedUrl:
|
|
49
|
+
proxiedUrl: p.url
|
|
49
50
|
})),
|
|
50
51
|
video: t.video ? {
|
|
51
52
|
...t.video,
|
|
52
|
-
posterProxied:
|
|
53
|
+
posterProxied: t.video.poster
|
|
53
54
|
} : null,
|
|
54
55
|
// Links
|
|
55
56
|
tweetUrl: `https://x.com/${t.user.screen_name}/status/${t.id_str}`,
|
|
@@ -59,8 +60,9 @@ const slotProps = computed(() => {
|
|
|
59
60
|
// Reply context
|
|
60
61
|
isReply: !!t.parent,
|
|
61
62
|
replyToUser: t.parent?.user.screen_name,
|
|
62
|
-
// Helpers
|
|
63
|
-
|
|
63
|
+
// Helpers — proxy an arbitrary URL through the image endpoint at runtime.
|
|
64
|
+
// Uses the page token emitted during SSR so client-generated URLs validate.
|
|
65
|
+
proxyImage: (url) => proxyUrl(resolvedImageProxyEndpoint.value, { url })
|
|
64
66
|
};
|
|
65
67
|
});
|
|
66
68
|
defineExpose({
|
|
@@ -26,11 +26,22 @@ function toNetworkRequest(entry, proxyPrefix) {
|
|
|
26
26
|
isProxied
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
function createDomainMatcher(domains, proxyPrefix) {
|
|
29
|
+
function createDomainMatcher(domains, proxyPrefix, scriptSrc) {
|
|
30
30
|
const localHostname = window.location.hostname;
|
|
31
|
+
const scriptUrl = (() => {
|
|
32
|
+
if (!scriptSrc)
|
|
33
|
+
return "";
|
|
34
|
+
try {
|
|
35
|
+
return new URL(scriptSrc, window.location.origin).href;
|
|
36
|
+
} catch {
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
31
40
|
return function matchesScript(entry) {
|
|
32
41
|
try {
|
|
33
42
|
const entryUrl = new URL(entry.name, window.location.origin);
|
|
43
|
+
if (scriptUrl && entryUrl.href === scriptUrl)
|
|
44
|
+
return true;
|
|
34
45
|
if (entryUrl.hostname !== localHostname && domains.has(entryUrl.hostname))
|
|
35
46
|
return true;
|
|
36
47
|
const proxyPath = `${proxyPrefix}/`;
|
|
@@ -46,12 +57,12 @@ function createDomainMatcher(domains, proxyPrefix) {
|
|
|
46
57
|
return false;
|
|
47
58
|
};
|
|
48
59
|
}
|
|
49
|
-
function observeNetworkRequests(payload, domains, onUpdate) {
|
|
60
|
+
function observeNetworkRequests(payload, domains, onUpdate, scriptSrc) {
|
|
50
61
|
if (typeof PerformanceObserver === "undefined")
|
|
51
62
|
return () => {
|
|
52
63
|
};
|
|
53
64
|
const proxyPrefix = resolveProxyPrefix();
|
|
54
|
-
const matchesScript = createDomainMatcher(domains, proxyPrefix);
|
|
65
|
+
const matchesScript = createDomainMatcher(domains, proxyPrefix, scriptSrc);
|
|
55
66
|
const seen = /* @__PURE__ */ new Set();
|
|
56
67
|
function entryKey(entry) {
|
|
57
68
|
return `${entry.name}@${entry.startTime}`;
|
|
@@ -148,7 +159,7 @@ export function useScript(input, options) {
|
|
|
148
159
|
],
|
|
149
160
|
networkRequests: []
|
|
150
161
|
};
|
|
151
|
-
disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
|
|
162
|
+
disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, src);
|
|
152
163
|
syncScripts();
|
|
153
164
|
}
|
|
154
165
|
return stub;
|
|
@@ -274,7 +285,7 @@ export function useScript(input, options) {
|
|
|
274
285
|
...scriptHostname ? [scriptHostname] : [],
|
|
275
286
|
...options.devtools?.domains || []
|
|
276
287
|
]);
|
|
277
|
-
let disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
|
|
288
|
+
let disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, input.src);
|
|
278
289
|
const _origRemove = instance.remove;
|
|
279
290
|
const _origReload = instance.reload;
|
|
280
291
|
instance.remove = () => {
|
|
@@ -284,7 +295,7 @@ export function useScript(input, options) {
|
|
|
284
295
|
instance.reload = async () => {
|
|
285
296
|
disconnectObserver();
|
|
286
297
|
const result = await _origReload();
|
|
287
|
-
disconnectObserver = observeNetworkRequests(payload, domains, syncScripts);
|
|
298
|
+
disconnectObserver = observeNetworkRequests(payload, domains, syncScripts, input.src);
|
|
288
299
|
return result;
|
|
289
300
|
};
|
|
290
301
|
syncScripts();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ScriptProxyToken {
|
|
2
|
+
token: string;
|
|
3
|
+
ts: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Shared `useState` holding the proxy page token emitted during SSR.
|
|
7
|
+
*
|
|
8
|
+
* Populated by the `nuxt-scripts:proxy-token` server plugin when
|
|
9
|
+
* `runtimeConfig['nuxt-scripts'].proxySecret` is set, and hydrated to the
|
|
10
|
+
* client via the Nuxt payload. Stays null when signing is disabled.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useScriptProxyToken(): import("vue").Ref<ScriptProxyToken | null, ScriptProxyToken | null>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build proxy URLs that the server's `withSigning` middleware accepts.
|
|
3
|
+
*
|
|
4
|
+
* Attaches the page token emitted during SSR (`_pt` + `_ts`) when one is
|
|
5
|
+
* available, so client-driven proxy calls (e.g. reactive fetches, dynamic
|
|
6
|
+
* image helpers exposed in slot props) authenticate without needing a
|
|
7
|
+
* server round-trip to sign each URL.
|
|
8
|
+
*
|
|
9
|
+
* When no token is present (signing disabled or no secret), emits plain
|
|
10
|
+
* `?url=...` URLs, matching the pre-signing behavior.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useScriptProxyUrl(): (path: string, query?: Record<string, unknown>) => string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PAGE_TOKEN_PARAM, PAGE_TOKEN_TS_PARAM } from "../server/utils/sign-constants.js";
|
|
2
|
+
import { useScriptProxyToken } from "./useScriptProxyToken.js";
|
|
3
|
+
export function useScriptProxyUrl() {
|
|
4
|
+
const token = useScriptProxyToken();
|
|
5
|
+
return (path, query = {}) => {
|
|
6
|
+
const parts = [];
|
|
7
|
+
for (const [key, value] of Object.entries(query)) {
|
|
8
|
+
if (value === void 0 || value === null)
|
|
9
|
+
continue;
|
|
10
|
+
const encodedKey = encodeURIComponent(key);
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const item of value) {
|
|
13
|
+
if (item === void 0 || item === null)
|
|
14
|
+
continue;
|
|
15
|
+
parts.push(`${encodedKey}=${encodeURIComponent(String(item))}`);
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
parts.push(`${encodedKey}=${encodeURIComponent(String(value))}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (token.value) {
|
|
22
|
+
parts.push(`${PAGE_TOKEN_PARAM}=${encodeURIComponent(token.value.token)}`);
|
|
23
|
+
parts.push(`${PAGE_TOKEN_TS_PARAM}=${token.value.ts}`);
|
|
24
|
+
}
|
|
25
|
+
return parts.length ? `${path}?${parts.join("&")}` : path;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emit a per-request proxy page token into the SSR payload.
|
|
3
|
+
*
|
|
4
|
+
* The token authorizes client-side proxy calls (`/embed/x-image?url=...`,
|
|
5
|
+
* `/embed/bluesky?url=...`, etc.) without needing each URL to be signed
|
|
6
|
+
* ahead of time. It stays null when no proxy secret is configured, in
|
|
7
|
+
* which case `withSigning` passes requests through unchecked.
|
|
8
|
+
*/
|
|
9
|
+
declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
|
|
10
|
+
export default _default;
|