User:Thundercraft5/sw.js

// Add any test code here. // DO NOT SUBMIT TO JSRT! /* global self, Request */ /* jshint undef:true, esversion: 6 */ const map = { "test": "User:Thundercraft5/sw.js/module.js", "test2": "User:Thundercraft5/sw.js/module2.js", };

const pathAliases = { "self": "User:${USER}/${PATH}", "wiki": "MediaWiki:${PATH}", };

const userInfo = { id: null, name: null, messages: null, groups: null, groupmemberships: null, implicitgroups: null, rights: null, changeablegroups: null, editcount: null, ratelimits: null, latestcontrib: null, };

const npmProviders = { "unpkg": "https://unpkg.com/${PACKAGE}@${VERSION|latest}/${PATH}", "esm-sh": "https://esm.sh/${PACKAGE}@${VERSION|latest}/${PATH}", "jsdelivr": "https://cdn.jsdelivr.net/npm/${PACKAGE}@${VERSION|latest}/${PATH}", };

function apiFetch(method, params = {}, fetchOptions = {}) { method = method.toUpperCase; const defaults = { format: "json", };	/* jshint ignore:start */ const entries = Object.entries({ ...params, ...defaults }); const toString = => entries.map(([k, v]) => `${k}=${Array.isArray(v) ? v.join("|") : v}`).join("&"); /* jshint ignore:end */

if (method === "POST") { /* jshint ignore:start */ return fetch("/api.php", {			body: toString,			method,			headers: {				["content-type"]: "application/x-www-form-urlencoded; charset=UTF-8"			},			...fetchOptions,		}).then(r => r.json); /* jshint ignore:end */ } else { /* jshint ignore:start */ return fetch(`/api.php?${ toString }`, { method, ...fetchOptions }).then(r => r.json); /* jshint ignore:end */ } }

function formatString(s, replacements) { return s.replace(/\${(? \w+)(?:\|(?.+?)?)?}/g, (...args) => {		const { name, defaultValue } = args.pop;		return replacements[name] || defaultValue || "";	}); }

function normalizeUrl(pagename) { const url = new URL(location); url.searchParams.append("action", "raw"); url.searchParams.append("ctype", "text/javascript"); url.searchParams.set("title", pagename); url.pathname = `/index.php`; return url; }

function redirectToPage(pagename) { return Response.redirect(`/@${pagename}`) }

function resolveImportPath(path) { let url; const isSpecifier = ![".", "/"].some(s => path.includes(s)); const { groups: providerMatch } = path.match(/^(? [\w\-]+):(? (? [a-zA-Z\-0-9]+)(?:@(? [\d\.]{1,3}\d+|latest))?(? [^\&\?\#]+)?)/) || {groups:{}}; if (npmProviders[providerMatch.provider]) { const { provider, path, version = "latest", package: packageName } = providerMatch; url = new URL(formatString(npmProviders[provider], { PACKAGE: packageName, PATH: path, VERSION: version, }));	} else if (pathAliases[providerMatch.provider?.toLowerCase]) { const { provider, text } = providerMatch; console.log(userInfo); return redirectToPage(formatString(pathAliases[provider], { USER: userInfo.name, PATH: text, }));	} else { if (isSpecifier) { normalized = map[normalized]; if (!normalized) throw new Error(`Module specifier "${normalized}" could not be resolved`); return redirectToPage(normalized); }		console.log(normalized); url = normalizeUrl(normalized); } 	return url; }

async function eventHandler { let { request: { url }, request } = this; url = new URL(url); console.log(this.clientId, url, Object.fromEntries(request.headers)); if (url.pathname.match(/^\/@(?!.*\/wiki\/).*(\.[mc]?js$)?/)) { let normalized = url.pathname.replace(/^\/@/g, ""); const resolved = resolveImportPath(normalized); if (resolved instanceof Response) return resolved; else url = resolved; return fetch(new Request(url, { ...request })) .then(async response => {				const headers = Object.fromEntries(response.headers);				const validTypes = ["application/javascript", "text/javascript"];				const type = headers?.["content-type"]?.split(";").shift;				if (!validTypes.includes(type)) 					throw new Error(`Server responded with a MIME type of "${type}", expected ${validTypes.map(s => `"${s}"`).join(" or ")} instead`);				return [					{ ...response, url }, 					headers,					await response.text,				];			}) .then(([response, headers, text]) => {				const imports = text.split("; ").slice(0, -1);				return new Response(new Blob([text], { type: headers["content-type"] }), { ...response, });			}); 	} };

self.addEventListener('fetch', event => { 	const result = eventHandler.call(event);	event.respondWith(result.then(r => {		if (r === undefined) return fetch(event.request);		else return r;	})); });

self.addEventListener('activate', event => {	console.log(event); });

self.addEventListener('install', event => {	console.log(event);		event.waitUntil(Promise.all([		apiFetch("GET", { "action": "query", "format": "json", "meta": "userinfo", "uiprop": "latestcontrib|ratelimits|editcount|changeablegroups|rights|implicitgroups|groups|groupmemberships|blockinfo|hasmsg" }).then(({ query: { userinfo } }) => Object.assign(userInfo, userinfo)),		apiFetch("GET", { "action": "query", "format": "json", "assert": "user", "prop": "revisions", "generator": "allpages", "rvprop": "ids|content", "rvslots": "*", "gapnamespace": "8", "gaplimit": "max", }),	])); });