PageSourceSearch

https://flowworks.io/scripts.js

js flowworks.io collected 2026-10-02 00:37:46 UTC 4,704 bytes, 111 lines download raw bytes

1// 어드민 대리 로그인 토큰인지 (서버 JWTData.impersonatedByAdminId).
2// utils/impersonation.ts 의 isImpersonatedToken 과 같은 판정 — 이 파일은 번들 밖 정적 스크립트라
3// import 할 수 없어 불가피하게 복제한다. 한쪽을 고치면 다른 쪽도 고칠 것 (impersonation.test.ts 가 둘 다 검증).
4// 이 토큰을 서비스워커에 넘기면 서비스워커가 background sync 로 그 회원 계정에 푸시 구독을
5// 등록해, 어드민 브라우저가 회원의 푸시 기기로 남는다. 판별 실패 시에는 기존 동작을 유지한다
6// (서버도 같은 claim 을 보고 등록을 거부하므로 여기서 못 걸러도 등록되지는 않는다).
7function isImpersonatedAuthToken(token) {
8  try {
9    var payload = token.split('.')[1];
10    if (!payload) return false;
11    var normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
12    return Boolean(JSON.parse(atob(normalized)).impersonatedByAdminId);
13  } catch (error) {
14    return false;
15  }
16}
17
18// Function to send auth token to service worker
19function sendAuthTokenToServiceWorker(serviceWorker) {
20  try {
21    // Define known production domains
22    let productionDomains = ['app.flowworks.io', 'flowworks.io', 'api.flowworks.io', 'cdn.flowworks.io'];
23
24    // Define known development domains
25    let developmentDomains = ['dev.flowworks.io', 'dev-api.flowworks.io', 'dev-cdn.flowworks.io'];
26
27    let hostname = window.location.hostname;
28    let tokenName;
29
30    // Explicit environment detection
31    if (productionDomains.includes(hostname)) {
32      tokenName = 'flowworks_accesstoken';
33    } else if (developmentDomains.includes(hostname) || hostname.includes('dev-')) {
34      tokenName = 'dev_flowworks_accesstoken';
35    } else if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.includes('mydomain.com')) {
36      tokenName = 'local_flowworks_accesstoken';
37    } else {
38      // Fallback for unknown domains - default to development for safety
39      console.warn('Unknown hostname detected:', hostname, '- defaulting to development token');
40      tokenName = 'dev_flowworks_accesstoken';
41    }
42
43    // Get auth token from localStorage
44    let token = localStorage.getItem(tokenName);
45
46    if (token && isImpersonatedAuthToken(token)) {
47      return;
48    }
49
50    if (token && serviceWorker) {
51      // Send token to service worker
52      serviceWorker.postMessage({
53        type: 'UPDATE_AUTH_TOKEN',
54        token: token,
55      });
56    }
57  } catch (error) {
58    console.error('Failed to send auth token to service worker:', error);
59  }
60}
61
62if ('serviceWorker' in navigator) {
63  console.log('Will the service worker register?');
64  navigator.serviceWorker
65    .register('/sw.js')
66    .then(function (reg) {
67      console.log('Yes, it did.');
68
69      // Send auth token to service worker when it's ready
70      if (reg.active) {
71        sendAuthTokenToServiceWorker(reg.active);
72      }
73
74      // Handle service worker updates
75      reg.addEventListener('updatefound', function () {
76        let newWorker = reg.installing;
77        newWorker.addEventListener('statechange', function () {
78          if (newWorker.state === 'activated') {
79            sendAuthTokenToServiceWorker(newWorker);
80          }
81        });
82      });
83    })
84    .catch(function (err) {
85      console.log("No it didn't. This happened:", err);
86    });
87
88  // 일부 한국 인앱 브라우저(네이버 앱, 카카오 웹뷰 등) / 광고차단 확장이 addEventListener를
89  // 후킹하면서 listener target에 대해 .tagName을 가정한다. window/navigator는 tagName이 없어
90  // 그쪽 후킹이 TypeError를 던지는데, 그게 글로벌 에러로 새서 우리 알림 시스템까지 흘러옴.
91  // try/catch로 그 노이즈를 차단(우리 측 기능 동작에는 영향 없음).
92  try {
93    // Listen for navigation messages from service worker (fallback for browsers without client.navigate support)
94    navigator.serviceWorker.addEventListener('message', function (event) {
95      if (event.data && event.data.type === 'NAVIGATE_TO' && event.data.url) {
96        // Navigate to the specified URL
97        window.location.href = event.data.url;
98      }
99    });
100  } catch (_e) { /* external addEventListener hook noise */ }
101
102  try {
103    // Update token when storage changes
104    window.addEventListener('storage', function (event) {
105      let tokenNames = ['flowworks_accesstoken', 'dev_flowworks_accesstoken', 'local_flowworks_accesstoken'];
106      if (tokenNames.includes(event.key) && navigator.serviceWorker.controller) {
107        sendAuthTokenToServiceWorker(navigator.serviceWorker.controller);
108      }
109    });
110  } catch (_e) { /* external addEventListener hook noise */ }
111}

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.