UNPKG

@worker-tools/deno-fetch-event-adapter

Version:

Dispatches global `fetch` events using Deno's native HTTP server.

349 lines (346 loc) 11.4 kB
// deno-fmt-ignore-file // deno-lint-ignore-file // This code was bundled using `deno bundle` and it's not recommended to edit it manually class DenoStdInternalError extends Error { constructor(message){ super(message); this.name = "DenoStdInternalError"; } } function assert(expr, msg = "") { if (!expr) { throw new DenoStdInternalError(msg); } } const { hasOwn } = Object; function get(obj, key) { if (hasOwn(obj, key)) { return obj[key]; } } function getForce(obj, key) { const v = get(obj, key); assert(v != null); return v; } function isNumber(x) { if (typeof x === "number") return true; if (/^0x[0-9a-f]+$/i.test(String(x))) return true; return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(String(x)); } function hasKey(obj, keys) { let o = obj; keys.slice(0, -1).forEach((key)=>{ o = get(o, key) ?? {}; }); const key1 = keys[keys.length - 1]; return key1 in o; } function parse(args, { "--": doubleDash = false , alias: alias3 = {} , boolean: __boolean = false , default: defaults = {} , stopEarly =false , string =[] , unknown =(i)=>i } = {}) { const flags = { bools: {}, strings: {}, unknownFn: unknown, allBools: false }; if (__boolean !== undefined) { if (typeof __boolean === "boolean") { flags.allBools = !!__boolean; } else { const booleanArgs = typeof __boolean === "string" ? [ __boolean ] : __boolean; for (const key of booleanArgs.filter(Boolean)){ flags.bools[key] = true; } } } const aliases = {}; if (alias3 !== undefined) { for(const key in alias3){ const val = getForce(alias3, key); if (typeof val === "string") { aliases[key] = [ val ]; } else { aliases[key] = val; } for (const alias1 of getForce(aliases, key)){ aliases[alias1] = [ key ].concat(aliases[key].filter((y)=>alias1 !== y )); } } } if (string !== undefined) { const stringArgs = typeof string === "string" ? [ string ] : string; for (const key of stringArgs.filter(Boolean)){ flags.strings[key] = true; const alias = get(aliases, key); if (alias) { for (const al of alias){ flags.strings[al] = true; } } } } const argv = { _: [] }; function argDefined(key, arg) { return flags.allBools && /^--[^=]+$/.test(arg) || get(flags.bools, key) || !!get(flags.strings, key) || !!get(aliases, key); } function setKey(obj, keys, value) { let o = obj; keys.slice(0, -1).forEach(function(key) { if (get(o, key) === undefined) { o[key] = {}; } o = get(o, key); }); const key4 = keys[keys.length - 1]; if (get(o, key4) === undefined || get(flags.bools, key4) || typeof get(o, key4) === "boolean") { o[key4] = value; } else if (Array.isArray(get(o, key4))) { o[key4].push(value); } else { o[key4] = [ get(o, key4), value ]; } } function setArg(key, val, arg = undefined) { if (arg && flags.unknownFn && !argDefined(key, arg)) { if (flags.unknownFn(arg, key, val) === false) return; } const value = !get(flags.strings, key) && isNumber(val) ? Number(val) : val; setKey(argv, key.split("."), value); const alias = get(aliases, key); if (alias) { for (const x of alias){ setKey(argv, x.split("."), value); } } } function aliasIsBoolean(key) { return getForce(aliases, key).some((x)=>typeof get(flags.bools, x) === "boolean" ); } for (const key3 of Object.keys(flags.bools)){ setArg(key3, defaults[key3] === undefined ? false : defaults[key3]); } let notFlags = []; if (args.includes("--")) { notFlags = args.slice(args.indexOf("--") + 1); args = args.slice(0, args.indexOf("--")); } for(let i = 0; i < args.length; i++){ const arg = args[i]; if (/^--.+=/.test(arg)) { const m = arg.match(/^--([^=]+)=(.*)$/s); assert(m != null); const [, key, value] = m; if (flags.bools[key]) { const booleanValue = value !== "false"; setArg(key, booleanValue, arg); } else { setArg(key, value, arg); } } else if (/^--no-.+/.test(arg)) { const m = arg.match(/^--no-(.+)/); assert(m != null); setArg(m[1], false, arg); } else if (/^--.+/.test(arg)) { const m = arg.match(/^--(.+)/); assert(m != null); const [, key] = m; const next = args[i + 1]; if (next !== undefined && !/^-/.test(next) && !get(flags.bools, key) && !flags.allBools && (get(aliases, key) ? !aliasIsBoolean(key) : true)) { setArg(key, next, arg); i++; } else if (/^(true|false)$/.test(next)) { setArg(key, next === "true", arg); i++; } else { setArg(key, get(flags.strings, key) ? "" : true, arg); } } else if (/^-[^-]+/.test(arg)) { const letters = arg.slice(1, -1).split(""); let broken = false; for(let j = 0; j < letters.length; j++){ const next = arg.slice(j + 2); if (next === "-") { setArg(letters[j], next, arg); continue; } if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { setArg(letters[j], next.split(/=(.+)/)[1], arg); broken = true; break; } if (/[A-Za-z]/.test(letters[j]) && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { setArg(letters[j], next, arg); broken = true; break; } if (letters[j + 1] && letters[j + 1].match(/\W/)) { setArg(letters[j], arg.slice(j + 2), arg); broken = true; break; } else { setArg(letters[j], get(flags.strings, letters[j]) ? "" : true, arg); } } const [key] = arg.slice(-1); if (!broken && key !== "-") { if (args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1]) && !get(flags.bools, key) && (get(aliases, key) ? !aliasIsBoolean(key) : true)) { setArg(key, args[i + 1], arg); i++; } else if (args[i + 1] && /^(true|false)$/.test(args[i + 1])) { setArg(key, args[i + 1] === "true", arg); i++; } else { setArg(key, get(flags.strings, key) ? "" : true, arg); } } } else { if (!flags.unknownFn || flags.unknownFn(arg) !== false) { argv._.push(flags.strings["_"] ?? !isNumber(arg) ? arg : Number(arg)); } if (stopEarly) { argv._.push(...args.slice(i + 1)); break; } } } for (const key2 of Object.keys(defaults)){ if (!hasKey(argv, key2.split("."))) { setKey(argv, key2.split("."), defaults[key2]); if (aliases[key2]) { for (const x of aliases[key2]){ setKey(argv, x.split("."), defaults[key2]); } } } } if (doubleDash) { argv["--"] = []; for (const key of notFlags){ argv["--"].push(key); } } else { for (const key of notFlags){ argv._.push(key); } } return argv; } const importMeta = { url: "file:///home/runner/work/deno-fetch-event-adapter/deno-fetch-event-adapter/listen.ts", main: import.meta.main }; class AdaptedFetchEvent extends Event { #event; #request; constructor(event, hostname){ super('fetch'); if (typeof event === 'string' || typeof hostname === 'object') throw Error('Overload not implemented'); this.#event = event; const headers = new Headers([ ...this.#event.request.headers, ...hostname ? [ [ 'x-forwarded-for', hostname ] ] : [], ]); this.#request = new Proxy(this.#event.request, { get (target, prop) { return prop === 'headers' ? headers : Reflect.get(target, prop); } }); } get request() { return this.#request; } respondWith(r) { this.#event.respondWith(r); } waitUntil(_f) {} get clientId() { return ''; } get preloadResponse() { return Promise.resolve(); } get replacesClientId() { return ''; } get resultingClientId() { return ''; } } Object.defineProperty(self, 'FetchEvent', { configurable: false, enumerable: false, writable: false, value: AdaptedFetchEvent }); const NAME = 'Deno Fetch Event Adapter'; (async ()=>{ let server; if (!self.location) { throw new Error(`${NAME}: When using Deno Fetch Event Adapter, a --location is required.`); } if (self.location.protocol === 'https:' || self.location.port === '433') { const { cert: certFile , key: keyFile } = parse(Deno.args, { alias: { cert: [ 'c', 'cert-file' ], key: [ 'k', 'key-file' ] } }); if (!certFile || !keyFile) { throw new Error(`${NAME}: When using HTTPS or port 443, a --cert and --key are required.`); } server = Deno.listenTls({ hostname: self.location.hostname, port: Number(self.location.port || 443), certFile, keyFile }); } else { server = Deno.listen({ hostname: self.location.hostname, port: Number(self.location.port || 80) }); } for await (const conn of server){ (async ()=>{ try { for await (const event of Deno.serveHttp(conn)){ const { hostname } = conn.remoteAddr; self.dispatchEvent(new AdaptedFetchEvent(event, hostname)); } } catch (error) { self.dispatchEvent(new ErrorEvent('error', { message: error?.message, filename: importMeta.url, error })); } })(); } })();