PageSourceSearch

https://streamaifrontend.netlify.app/js/ext-bridge.js

js streamaifrontend.netlify.app collected 2026-10-03 11:27:36 UTC 9,918 bytes, 338 lines download raw bytes

1/** Talk to the Cuts Point Chrome extension for YouTube cookie handoff. */
2;(function () {
3  const cfg = window.VIRALMOMENT || {}
4
5  function handoffOrigin() {
6    return (cfg.extensionHandoffOrigin || "https://streamaifrontend.netlify.app").replace(/\/$/, "")
7  }
8
9  /** Origins where the published extension can talk to the page directly. */
10  function isExtensionTrustedSite() {
11    const host = location.hostname
12    return (
13      host === "streamaifrontend.netlify.app" ||
14      host === "localhost" ||
15      host === "127.0.0.1"
16    )
17  }
18
19  function fail(code, detail) {
20    const base = { ok: false, code, reason: detail }
21    return window.VMExtUi?.formatResult ? window.VMExtUi.formatResult(base) : base
22  }
23
24  function finalize(result) {
25    if (!result || result.ok) return result
26    return window.VMExtUi?.formatResult ? window.VMExtUi.formatResult(result) : result
27  }
28
29  function extensionIds() {
30    const ids = Array.isArray(cfg.chromeExtensionIds) ? cfg.chromeExtensionIds.slice() : []
31    try {
32      const saved = localStorage.getItem("cutspoint_ext_id")
33      if (saved && !ids.includes(saved)) ids.unshift(saved)
34    } catch {
35      /* ignore */
36    }
37    return ids
38  }
39
40  function sendViaContentBridge(message) {
41    return new Promise((resolve) => {
42      const bridgeId = `${Date.now()}-${Math.random().toString(36).slice(2)}`
43      let settled = false
44
45      const done = (result) => {
46        if (settled) return
47        settled = true
48        window.removeEventListener("message", onResult)
49        clearTimeout(timer)
50        resolve(result)
51      }
52
53      const onResult = (event) => {
54        if (event.source !== window) return
55        const data = event.data
56        if (!data || data.type !== "CUTSPOINT_EXT_BRIDGE_RESULT" || data.bridgeId !== bridgeId) return
57        if (data.error) {
58          done(fail("extension_missing", data.error))
59          return
60        }
61        done(data.response ? finalize(data.response) : fail("extension_missing"))
62      }
63
64      window.addEventListener("message", onResult)
65      const timer = setTimeout(() => {
66        done(fail("extension_missing"))
67      }, 15000)
68
69      try {
70        window.postMessage({ type: "CUTSPOINT_EXT_BRIDGE", bridgeId, message }, "*")
71      } catch {
72        done(fail("extension_missing"))
73      }
74    })
75  }
76
77  function sendViaExternalRuntime(message) {
78    return new Promise((resolve) => {
79      if (!window.chrome?.runtime?.sendMessage) {
80        resolve(null)
81        return
82      }
83      const ids = extensionIds()
84      if (!ids.length) {
85        resolve(fail("extension_missing"))
86        return
87      }
88
89      let remaining = ids.length
90      let settled = false
91
92      ids.forEach((id) => {
93        try {
94          window.chrome.runtime.sendMessage(id, message, (response) => {
95            const err = window.chrome.runtime.lastError
96            remaining -= 1
97            if (settled) return
98            if (!err && response) {
99              settled = true
100              try {
101                localStorage.setItem("cutspoint_ext_id", id)
102              } catch {
103                /* ignore */
104              }
105              resolve(response)
106              return
107            }
108            if (remaining <= 0) {
109              resolve(null)
110            }
111          })
112        } catch {
113          remaining -= 1
114          if (remaining <= 0 && !settled) {
115            resolve(null)
116          }
117        }
118      })
119    })
120  }
121
122  async function sendToExtension(message) {
123    // cutspoint.com is not in the published extension's externally_connectable list,
124    // and Netlify blocks iframes (X-Frame-Options: DENY). Cookie flows use a popup
125    // to the trusted Netlify origin instead — do not attempt iframe RPC here.
126    if (!isExtensionTrustedSite()) {
127      return fail("extension_missing")
128    }
129    const external = await sendViaExternalRuntime(message)
130    if (external) return external
131    return sendViaContentBridge(message)
132  }
133
134  async function ping() {
135    if (!isExtensionTrustedSite()) {
136      // Can't probe from cutspoint.com without framing; popup handoff verifies later.
137      return { ok: true, deferred: true }
138    }
139    const res = await sendToExtension({ type: "PING_EXTENSION" })
140    if (res?.ok) return res
141    return finalize(res || fail("extension_missing"))
142  }
143
144  async function attachCookies(jobId, accessToken) {
145    return sendToExtension({
146      type: "ATTACH_YOUTUBE_COOKIES",
147      jobId,
148      accessToken
149    })
150  }
151
152  async function getBridgeUrl(jobId) {
153    return sendToExtension({ type: "GET_COOKIE_BRIDGE_URL", jobId: jobId || "" })
154  }
155
156  function listenForCookieResult(jobId, resolve) {
157    const onMessage = (event) => {
158      const data = event.data
159      if (!data || data.type !== "CUTSPOINT_COOKIES_RESULT") return
160      if (jobId && data.jobId && data.jobId !== jobId) return
161      window.removeEventListener("message", onMessage)
162      clearTimeout(timer)
163      resolve(
164        data.ok
165          ? {
166              ok: true,
167              reason: data.message || "ok",
168              cookiesB64: data.cookiesB64 || null
169            }
170          : finalize({ ok: false, reason: data.message })
171      )
172    }
173    window.addEventListener("message", onMessage)
174    const timer = setTimeout(() => {
175      window.removeEventListener("message", onMessage)
176      resolve(fail("timeout"))
177    }, 120000)
178    return timer
179  }
180
181  function openCookieBridgePopup(jobId, accessToken, authUrl) {
182    return new Promise((resolve) => {
183      const hash = new URLSearchParams({
184        access_token: accessToken || "",
185        token_type: "bearer",
186        type: "website"
187      })
188      const url = `${authUrl}#${hash.toString()}`
189      const popup = window.open(url, "cutspoint_cookie_bridge", "width=440,height=560")
190
191      listenForCookieResult(jobId, resolve)
192
193      if (!popup) {
194        resolve(fail("popup_blocked"))
195      }
196    })
197  }
198
199  /** Full cookie flow on Netlify (extension-trusted) — used from cutspoint.com. */
200  function openNetlifyCookieHandoff(jobId, accessToken) {
201    return new Promise((resolve) => {
202      const url = new URL(`${handoffOrigin()}/ext-cookie-handoff.html`)
203      url.searchParams.set("mode", "cookies")
204      url.searchParams.set("origin", location.origin)
205      if (jobId) url.searchParams.set("jobId", jobId)
206      url.hash = new URLSearchParams({
207        access_token: accessToken || "",
208        token_type: "bearer",
209        type: "website"
210      }).toString()
211
212      const popup = window.open(url.toString(), "cutspoint_handoff", "width=480,height=620")
213      listenForCookieResult(jobId, resolve)
214
215      if (!popup) {
216        resolve(fail("popup_blocked"))
217      }
218    })
219  }
220
221  async function getCookiesB64IfReady() {
222    if (!isExtensionTrustedSite()) {
223      return { ok: false, cookiesB64: null }
224    }
225    return sendToExtension({ type: "GET_YOUTUBE_COOKIES_B64" })
226  }
227
228  async function obtainCookiesForScan() {
229    const token = (await window.VMAuth.getAccessToken()) || ""
230
231    if (!isExtensionTrustedSite()) {
232      // Popup to Netlify (trusted by extension) — no iframe.
233      return finalize(await openNetlifyCookieHandoff("", token))
234    }
235
236    const ready = await getCookiesB64IfReady()
237    if (ready?.ok && ready.cookiesB64) {
238      return { ok: true, cookiesB64: ready.cookiesB64 }
239    }
240
241    const bridge = await getBridgeUrl("")
242    const authUrl = bridge?.authUrl
243    if (!authUrl) {
244      return finalize({
245        ok: false,
246        code: "extension_missing",
247        reason: bridge?.reason
248      })
249    }
250
251    return finalize(await openCookieBridgePopup("", token, authUrl))
252  }
253
254  async function ensureCookiesForJob(jobId, opts) {
255    const force = Boolean(opts && opts.force)
256    if (!force) {
257      const status = await window.VMApi.getCookiesStatus(jobId)
258      if (status?.has_cookies) return { ok: true, alreadyHad: true }
259    }
260
261    const token = await window.VMAuth.getAccessToken()
262    if (!token) {
263      return fail("sign_in")
264    }
265
266    if (!isExtensionTrustedSite()) {
267      const result = finalize(await openNetlifyCookieHandoff(jobId, token))
268      if (result.ok && result.cookiesB64) {
269        try {
270          await window.VMApi.attachCookies(jobId, result.cookiesB64)
271        } catch {
272          /* attach may already have succeeded inside the bridge */
273        }
274      }
275      return result
276    }
277
278    // Silent path first (Netlify / localhost) — refresh without a popup when possible.
279    const ready = await getCookiesB64IfReady()
280    if (ready?.ok && ready.cookiesB64) {
281      try {
282        await window.VMApi.attachCookies(jobId, ready.cookiesB64)
283        return { ok: true, cookiesB64: ready.cookiesB64 }
284      } catch {
285        /* fall through to extension attach / popup */
286      }
287    }
288
289    const attached = await attachCookies(jobId, token)
290    if (attached?.ok) {
291      return { ok: true, cookiesB64: attached.cookiesB64 || ready?.cookiesB64 || null }
292    }
293
294    let authUrl = attached?.authUrl
295    if (!authUrl) {
296      const bridge = await getBridgeUrl(jobId)
297      authUrl = bridge?.authUrl
298    }
299
300    if (!authUrl) {
301      return finalize({
302        ok: false,
303        code: "extension_missing",
304        reason: attached?.reason
305      })
306    }
307
308    const result = finalize(await openCookieBridgePopup(jobId, token, authUrl))
309    if (result.ok && result.cookiesB64) {
310      try {
311        await window.VMApi.attachCookies(jobId, result.cookiesB64)
312      } catch {
313        /* attach may already have succeeded inside the bridge */
314      }
315    }
316    return result
317  }
318
319  window.addEventListener("cutspoint-extension-ready", (event) => {
320    const id = event?.detail?.id
321    if (!id) return
322    try {
323      localStorage.setItem("cutspoint_ext_id", id)
324    } catch {
325      /* ignore */
326    }
327  })
328
329  window.VMExt = {
330    ping,
331    attachCookies,
332    getBridgeUrl,
333    openCookieBridgePopup,
334    getCookiesB64IfReady,
335    obtainCookiesForScan,
336    ensureCookiesForJob
337  }
338})()

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.