PageSourceSearch

https://www.taxi-money.net/serviceWorker.js?v=1.15

js taxi-money.net collected 2026-09-30 11:00:02 UTC 17,604 bytes, 568 lines download raw bytes

1var DOMAIN_FALLBACK_CACHE = 'domain-fallback-v3';
2var DOMAIN_FALLBACK_SPLASH = '/domain-fallback/splash.html';
3var DOMAIN_FALLBACK_UNAVAILABLE = '/domain-fallback/unavailable.html';
4var DOMAIN_FALLBACK_LOGO = '/media/assets/app/src/img/logo.png';
5var DOMAIN_FALLBACK_ASSETS = [
6	DOMAIN_FALLBACK_SPLASH,
7	DOMAIN_FALLBACK_UNAVAILABLE,
8	DOMAIN_FALLBACK_LOGO,
9];
10var DOMAIN_FALLBACK_SPLASH_DELAY_MS = 8000;
11var DOMAIN_FALLBACK_FETCH_HARD_TIMEOUT_MS = 60000;
12var DOMAIN_FALLBACK_PROBE_TIMEOUT_MS = 5000;
13var DOMAIN_FALLBACK_TECH_TIMEOUT_MS = 8000;
14var DOMAIN_FALLBACK_TECH_NEXT_DOMAIN_URL = 'https://tech.taxi1.ws/system/api/next-domain';
15var DOMAIN_FALLBACK_NAVIGATE_FAILURE_THRESHOLD = 2;
16var DOMAIN_FALLBACK_NAVIGATE_FAILURE_WINDOW_MS = 5 * 60 * 1000;
17var DOMAIN_FALLBACK_IDB_NAME = 'txm-domain-fallback';
18var DOMAIN_FALLBACK_IDB_STORE = 'state';
19var DOMAIN_FALLBACK_IDB_KEY = 'fallback';
20var DOMAIN_FALLBACK_IDB_KEY_NAVIGATE_FAILURES = 'navigate-failures';
21
22self.addEventListener('install', function (event) {
23	event.waitUntil(
24		caches.open(DOMAIN_FALLBACK_CACHE).then(function (cache) {
25			return cache.addAll(DOMAIN_FALLBACK_ASSETS);
26		}).then(function () {
27			return self.skipWaiting();
28		})
29	);
30});
31
32self.addEventListener('activate', function (event) {
33	event.waitUntil(
34		caches.keys().then(function (keys) {
35			return Promise.all(keys.filter(function (key) {
36				return key.indexOf('domain-fallback-') === 0 && key !== DOMAIN_FALLBACK_CACHE;
37			}).map(function (key) {
38				return caches.delete(key);
39			}));
40		}).then(function () {
41			return self.clients.claim();
42		})
43	);
44});
45
46self.addEventListener('message', function (event) {
47	if (!event.data || event.data.type !== 'CLEAR_FALLBACK') {
48		return;
49	}
50
51	event.waitUntil(clearFallbackState());
52});
53
54self.addEventListener('push', function (event) {
55	if (!(self.Notification && self.Notification.permission === 'granted')) {
56		return;
57	}
58
59	const sendNotification = payload => {
60		if (payload.data.hasOwnProperty('token') && payload.data.token) {
61			fetch('/push-notifications/delivered', {
62				method: 'POST',
63				headers: {
64					'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
65				},
66				body: 'token=' + payload.data.token
67			})
68		}
69
70		return self.registration.showNotification(payload.title, {
71			body: payload.body,
72			icon: payload.icon,
73			actions: payload.actions ? payload.actions : [],
74			data: payload.data
75		});
76	};
77
78	if (event.data) {
79		const payload = JSON.parse(event.data.text());
80		event.waitUntil(sendNotification(payload));
81	}
82});
83
84self.addEventListener('notificationclick', function(event) {
85	const clickedNotification = event.notification;
86	clickedNotification.close();
87
88	const clients = self.clients;
89	const notification = event.notification;
90
91	if (notification.data.hasOwnProperty('token') && notification.data.token) {
92		fetch('/push-notifications/clicked', {
93			method: 'POST',
94			headers: {
95				'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
96			},
97			body: 'token=' + notification.data.token
98		})
99	}
100
101	if (notification.data.hasOwnProperty('url') && notification.data.url) {
102		return clients.openWindow(notification.data.url);
103	} else {
104		return clients.openWindow('/');
105	}
106});
107
108self.addEventListener('fetch', function (event) {
109	var url = new URL(event.request.url);
110
111	if (event.request.mode === 'navigate') {
112		if (event.request.method !== 'GET' || isAdminPath(url.pathname)) {
113			return;
114		}
115
116		event.respondWith(handleNavigateRequest(event));
117		return;
118	}
119
120	if (url.origin === self.location.origin && isFallbackAsset(url.pathname)) {
121		event.respondWith(getCachedPage(url.pathname));
122	}
123});
124
125function isAdminPath(pathname) {
126	return pathname === '/admin' || pathname.indexOf('/admin/') === 0;
127}
128
129function isFallbackAsset(pathname) {
130	return DOMAIN_FALLBACK_ASSETS.indexOf(pathname) !== -1;
131}
132
133function handleNavigateRequest(event) {
134	var request = event.request;
135	var pending = startNavigateFetch(request);
136	var splashTimer = null;
137	var splashDelay = new Promise(function (resolve) {
138		splashTimer = setTimeout(function () {
139			resolve({splash: true});
140		}, DOMAIN_FALLBACK_SPLASH_DELAY_MS);
141	});
142	var settled = pending.promise.then(function (response) {
143		return {response: response};
144	}, function (error) {
145		return {error: error || new Error('fetch failed')};
146	});
147
148	return Promise.race([settled, splashDelay]).then(function (outcome) {
149		clearTimeout(splashTimer);
150
151		if (outcome.response) {
152			return clearNavigateFailures().then(function () {
153				return outcome.response;
154			});
155		}
156
157		if (outcome.error) {
158			return respondNavigateFailure(request);
159		}
160
161		if (typeof ReadableStream === 'undefined' || typeof TextEncoder === 'undefined') {
162			pending.abort();
163
164			return respondNavigateFailure(request);
165		}
166
167		return respondSplashStream(event, request, pending.promise);
168	});
169}
170
171function startNavigateFetch(request) {
172	var controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
173	var fetchRequest = controller ? new Request(request, {signal: controller.signal}) : request;
174	var hardTimer = null;
175	var abort = function () {
176		if (controller) {
177			controller.abort();
178		}
179	};
180	var hardTimeout = new Promise(function (resolve, reject) {
181		hardTimer = setTimeout(function () {
182			abort();
183			reject(new Error('timeout'));
184		}, DOMAIN_FALLBACK_FETCH_HARD_TIMEOUT_MS);
185	});
186	var promise = Promise.race([fetch(fetchRequest), hardTimeout]).then(function (response) {
187		clearTimeout(hardTimer);
188
189		return response;
190	}, function (error) {
191		clearTimeout(hardTimer);
192		throw error;
193	});
194
195	return {promise: promise, abort: abort};
196}
197
198function respondNavigateFailure(request) {
199	return recordNavigateFailure().then(function (failureCount) {
200		return runDeadDomainFallback(request, failureCount >= DOMAIN_FALLBACK_NAVIGATE_FAILURE_THRESHOLD);
201	});
202}
203
204function respondSplashStream(event, request, fetchPromise) {
205	return getSplashHtml().then(function (splashHtml) {
206		var encoder = new TextEncoder();
207		var parts = splitSplashHtml(splashHtml);
208		var stream = new ReadableStream({
209			start: function (controller) {
210				controller.enqueue(encoder.encode(parts.open + buildRenderPadding()));
211
212				var finish = fetchPromise.then(function (response) {
213					return clearNavigateFailures().then(function () {
214						return buildLateResponseScript(response, request);
215					});
216				}, function () {
217					return recordNavigateFailure().then(function (failureCount) {
218						return buildFallbackRouterConfig(request, failureCount >= DOMAIN_FALLBACK_NAVIGATE_FAILURE_THRESHOLD);
219					}).then(buildFallbackRouterScript);
220				}).catch(function () {
221					return buildReloadScript(request.url);
222				}).then(function (script) {
223					controller.enqueue(encoder.encode(script + parts.close));
224					controller.close();
225				}).catch(function () {
226					try {
227						controller.close();
228					} catch (error) {
229					}
230				});
231
232				event.waitUntil(finish);
233			},
234		});
235
236		return new Response(stream, {
237			headers: {
238				'Content-Type': 'text/html; charset=UTF-8',
239				'Cache-Control': 'no-store',
240			},
241		});
242	});
243}
244
245function getSplashHtml() {
246	return getCachedPage(DOMAIN_FALLBACK_SPLASH).then(function (response) {
247		return response.text();
248	});
249}
250
251function splitSplashHtml(splashHtml) {
252	var bodyEnd = splashHtml.lastIndexOf('</body>');
253	if (bodyEnd === -1) {
254		return {open: splashHtml, close: ''};
255	}
256
257	return {
258		open: splashHtml.slice(0, bodyEnd),
259		close: splashHtml.slice(bodyEnd),
260	};
261}
262
263function buildRenderPadding() {
264	return '<!--' + ' '.repeat(1024) + '-->';
265}
266
267function htmlResponse(html) {
268	return new Response(html, {
269		headers: {'Content-Type': 'text/html; charset=UTF-8'},
270	});
271}
272
273function encodeForInlineScript(value) {
274	return JSON.stringify(value)
275		.replace(/<\//g, '<\\/')
276		.replace(/<!--/g, '<\\!--');
277}
278
279function buildReloadScript(url) {
280	return '<script>window.location.replace(' + encodeForInlineScript(url) + ');</script>';
281}
282
283function buildLateResponseScript(response, request) {
284	if (!response
285		|| response.type === 'opaqueredirect'
286		|| response.redirected
287		|| (response.status >= 300 && response.status < 400)
288	) {
289		return buildReloadScript(request.url);
290	}
291
292	var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
293	if (contentType.indexOf('text/html') === -1) {
294		return buildReloadScript(request.url);
295	}
296
297	return response.text().then(function (html) {
298		return '<script>(function(){'
299			+ 'var html=' + encodeForInlineScript(html) + ';'
300			+ 'function replace(){document.open();document.write(html);document.close();}'
301			+ 'function schedule(){setTimeout(replace,0);}'
302			+ 'if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",schedule);}else{schedule();}'
303			+ '})();</script>';
304	});
305}
306
307function buildFallbackRouterConfig(request, confirmedDead) {
308	var base = {
309		originalUrl: request.url,
310		fromDomain: self.location.hostname,
311		token: '',
312		shouldLookupNext: confirmedDead,
313		probeTimeoutMs: DOMAIN_FALLBACK_PROBE_TIMEOUT_MS,
314		techTimeoutMs: DOMAIN_FALLBACK_TECH_TIMEOUT_MS,
315		techNextDomainUrl: DOMAIN_FALLBACK_TECH_NEXT_DOMAIN_URL,
316	};
317
318	return getFallbackState().then(function (state) {
319		if (state && state.currentDomain === self.location.hostname && state.token) {
320			base.token = state.token;
321		}
322
323		return base;
324	}).catch(function () {
325		return base;
326	});
327}
328
329function runDeadDomainFallback(request, confirmedDead) {
330	return Promise.all([
331		getSplashHtml(),
332		buildFallbackRouterConfig(request, confirmedDead),
333	]).then(function (parts) {
334		var split = splitSplashHtml(parts[0]);
335
336		return htmlResponse(split.open + buildFallbackRouterScript(parts[1]) + split.close);
337	}).catch(function () {
338		return getCachedPage(DOMAIN_FALLBACK_SPLASH);
339	});
340}
341
342function buildFallbackRouterScript(cfg) {
343	var payload = JSON.stringify({
344		originalUrl: cfg.originalUrl,
345		fromDomain: cfg.fromDomain,
346		token: cfg.token,
347		shouldLookupNext: cfg.shouldLookupNext,
348		probeTimeoutMs: cfg.probeTimeoutMs,
349		techTimeoutMs: cfg.techTimeoutMs,
350		techNextDomainUrl: cfg.techNextDomainUrl,
351	});
352
353	var script = '<script>(function(){'
354		+ 'var cfg=' + payload + ';'
355		+ 'function probeDomain(domain){'
356		+ 'var controller=typeof AbortController!=="undefined"?new AbortController():null;'
357		+ 'var timer=controller?setTimeout(function(){controller.abort();},cfg.probeTimeoutMs):null;'
358		+ 'var opts={method:"GET",mode:"no-cors",cache:"no-store",credentials:"omit"};'
359		+ 'if(controller){opts.signal=controller.signal;}'
360		+ 'return fetch("https://"+domain+"/system/api/domain?domain="+encodeURIComponent(domain),opts)'
361		+ '.then(function(){if(timer){clearTimeout(timer);}return true;})'
362		+ '.catch(function(){if(timer){clearTimeout(timer);}return false;});'
363		+ '}'
364		+ 'function buildRedirectUrl(domain){'
365		+ 'var source=new URL(cfg.originalUrl);'
366		+ 'var target=new URL(source.pathname+source.search,"https://"+domain);'
367		+ 'if(!cfg.token){return target.toString();}'
368		+ 'var params=new URLSearchParams(target.search);'
369		+ 'params.set("token",cfg.token);'
370		+ 'params.set("relogin","1");'
371		+ 'params.set("domain_fallback","1");'
372		+ 'params.set("from_domain",cfg.fromDomain||"");'
373		+ 'params.set("from_url",cfg.originalUrl||"");'
374		+ 'target.search=params.toString();'
375		+ 'return target.toString();'
376		+ '}'
377		+ 'function showUnavailable(){'
378		+ 'document.body.innerHTML="<div style=\\"text-align:center;padding:24px;font-family:sans-serif;color:#e8ecf4;background:#1a1f2e;min-height:100vh;display:flex;align-items:center;justify-content:center\\"><div><img src=\\"/media/assets/app/src/img/logo.png\\" alt=\\"Taxi Money\\" width=\\"180\\" style=\\"display:block;width:180px;height:auto;margin:0 auto 28px\\"><h1 style=\\"font-size:20px;margin-bottom:12px\\">Сайт временно недоступен</h1><p style=\\"opacity:0.85;line-height:1.5\\">Попробуйте зайти позже или обратитесь в поддержку.</p><div style=\\"margin-top:24px;display:flex;flex-direction:column;gap:12px\\"><a href=\\"https://a.taxi-money.games/login?aid=1394\\" rel=\\"noopener noreferrer\\" style=\\"color:#6b9fff;font-size:15px;text-decoration:none\\">Базовое зеркало</a><a href=\\"https://t.me/txmoney\\" rel=\\"noopener noreferrer\\" target=\\"_blank\\" style=\\"color:#6b9fff;font-size:15px;text-decoration:none\\">Telegram-группа</a></div></div></div>";'
379		+ '}'
380		+ 'function fetchNextDomains(){'
381		+ 'var controller=typeof AbortController!=="undefined"?new AbortController():null;'
382		+ 'var timer=controller?setTimeout(function(){controller.abort();},cfg.techTimeoutMs):null;'
383		+ 'var url=cfg.techNextDomainUrl+"?domain="+encodeURIComponent(cfg.fromDomain)+"&_="+Date.now();'
384		+ 'var opts={method:"GET",cache:"no-store",credentials:"omit",mode:"cors"};'
385		+ 'if(controller){opts.signal=controller.signal;}'
386		+ 'return fetch(url,opts).then(function(response){'
387		+ 'if(timer){clearTimeout(timer);}'
388		+ 'if(!response||!response.ok){return[];}'
389		+ 'return response.json();'
390		+ '}).then(function(data){'
391		+ 'if(!data){return[];}'
392		+ 'if(data.next_domains&&data.next_domains.length){return data.next_domains;}'
393		+ 'if(data.next_domain){return[data.next_domain];}'
394		+ 'return[];'
395		+ '}).catch(function(){if(timer){clearTimeout(timer);}return[];});'
396		+ '}'
397		+ 'function redirectToFirstAlive(domains){'
398		+ 'var chain=Promise.resolve(null);'
399		+ 'domains.forEach(function(domain){'
400		+ 'chain=chain.then(function(found){'
401		+ 'if(found){return found;}'
402		+ 'return probeDomain(domain).then(function(alive){return alive?domain:null;});'
403		+ '});'
404		+ '});'
405		+ 'chain.then(function(aliveDomain){'
406		+ 'if(aliveDomain){window.location.replace(buildRedirectUrl(aliveDomain));return;}'
407		+ 'showUnavailable();'
408		+ '});'
409		+ '}'
410		+ 'function run(){'
411		+ 'if(!cfg.shouldLookupNext){window.location.replace(cfg.originalUrl);return;}'
412		+ 'fetchNextDomains().then(function(domains){'
413		+ 'if(!domains.length){showUnavailable();return;}'
414		+ 'redirectToFirstAlive(domains);'
415		+ '});'
416		+ '}'
417		+ 'run();'
418		+ '})();</script>';
419
420	return script;
421}
422
423function getCachedPage(path) {
424	return caches.match(path).then(function (cached) {
425		if (cached) {
426			return cached;
427		}
428
429		return new Response('Service unavailable', {
430			status: 503,
431			headers: {'Content-Type': 'text/plain; charset=UTF-8'},
432		});
433	});
434}
435
436function openFallbackDb() {
437	return new Promise(function (resolve, reject) {
438		var request = indexedDB.open(DOMAIN_FALLBACK_IDB_NAME, 1);
439
440		request.onupgradeneeded = function () {
441			var db = request.result;
442			if (!db.objectStoreNames.contains(DOMAIN_FALLBACK_IDB_STORE)) {
443				db.createObjectStore(DOMAIN_FALLBACK_IDB_STORE);
444			}
445		};
446
447		request.onsuccess = function () {
448			resolve(request.result);
449		};
450
451		request.onerror = function () {
452			reject(request.error);
453		};
454	});
455}
456
457function idbGet(store, key) {
458	return new Promise(function (resolve, reject) {
459		var request = store.get(key);
460
461		request.onsuccess = function () {
462			resolve(request.result);
463		};
464
465		request.onerror = function () {
466			reject(request.error);
467		};
468	});
469}
470
471function idbPut(store, key, value) {
472	return new Promise(function (resolve, reject) {
473		var request = store.put(value, key);
474
475		request.onsuccess = function () {
476			resolve(value);
477		};
478
479		request.onerror = function () {
480			reject(request.error);
481		};
482	});
483}
484
485function idbDelete(store, key) {
486	return new Promise(function (resolve, reject) {
487		var request = store.delete(key);
488
489		request.onsuccess = function () {
490			resolve();
491		};
492
493		request.onerror = function () {
494			reject(request.error);
495		};
496	});
497}
498
499function pruneNavigateFailures(timestamps) {
500	var minTs = Date.now() - DOMAIN_FALLBACK_NAVIGATE_FAILURE_WINDOW_MS;
501
502	return timestamps.filter(function (ts) {
503		return ts >= minTs;
504	});
505}
506
507function getNavigateFailures() {
508	return openFallbackDb().then(function (db) {
509		var transaction = db.transaction(DOMAIN_FALLBACK_IDB_STORE, 'readonly');
510		var store = transaction.objectStore(DOMAIN_FALLBACK_IDB_STORE);
511
512		return idbGet(store, DOMAIN_FALLBACK_IDB_KEY_NAVIGATE_FAILURES).then(function (value) {
513			if (!Array.isArray(value)) {
514				return [];
515			}
516
517			return pruneNavigateFailures(value);
518		});
519	});
520}
521
522function recordNavigateFailure() {
523	return getNavigateFailures().then(function (timestamps) {
524		timestamps.push(Date.now());
525		timestamps = pruneNavigateFailures(timestamps);
526
527		return openFallbackDb().then(function (db) {
528			var transaction = db.transaction(DOMAIN_FALLBACK_IDB_STORE, 'readwrite');
529			var store = transaction.objectStore(DOMAIN_FALLBACK_IDB_STORE);
530
531			return idbPut(store, DOMAIN_FALLBACK_IDB_KEY_NAVIGATE_FAILURES, timestamps).then(function () {
532				return timestamps.length;
533			});
534		});
535	});
536}
537
538function clearNavigateFailures() {
539	return openFallbackDb().then(function (db) {
540		var transaction = db.transaction(DOMAIN_FALLBACK_IDB_STORE, 'readwrite');
541		var store = transaction.objectStore(DOMAIN_FALLBACK_IDB_STORE);
542
543		return idbDelete(store, DOMAIN_FALLBACK_IDB_KEY_NAVIGATE_FAILURES);
544	}).catch(function () {
545		return null;
546	});
547}
548
549function getFallbackState() {
550	return openFallbackDb().then(function (db) {
551		var transaction = db.transaction(DOMAIN_FALLBACK_IDB_STORE, 'readonly');
552		var store = transaction.objectStore(DOMAIN_FALLBACK_IDB_STORE);
553
554		return idbGet(store, DOMAIN_FALLBACK_IDB_KEY);
555	});
556}
557
558function clearFallbackState() {
559	return openFallbackDb().then(function (db) {
560		var transaction = db.transaction(DOMAIN_FALLBACK_IDB_STORE, 'readwrite');
561		var store = transaction.objectStore(DOMAIN_FALLBACK_IDB_STORE);
562
563		return Promise.all([
564			idbDelete(store, DOMAIN_FALLBACK_IDB_KEY),
565			idbDelete(store, DOMAIN_FALLBACK_IDB_KEY_NAVIGATE_FAILURES),
566		]);
567	});
568}

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.