@worker-tools/html-rewriter
Version:
WASM-based implementation of Cloudflare's HTML Rewriter for use in Deno, browsers, etc.
137 lines • 6.61 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _HTMLRewriter_elementHandlers, _HTMLRewriter_documentHandlers, _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.withEnableEsiTags = exports.HTMLRewriter = void 0;
// FIXME: replace multiple 1 import from skypack!?
require("./_dnt.polyfills.js");
const _base = __importStar(require("./vendor/html_rewriter.js"));
const { default: initWASM } = _base;
const base = _base;
const resolvable_promise_1 = require("@worker-tools/resolvable-promise");
const kEnableEsiTags = Symbol("kEnableEsiTags");
// In case a server doesn't return the proper mime type (e.g. githubusercontent.com)..
const toWASMResponse = (response) => {
var _b;
if ((_b = response.headers.get('content-type')) === null || _b === void 0 ? void 0 : _b.startsWith('application/wasm'))
return response;
const { body, headers: hs, ...props } = response;
const headers = new Headers(hs);
headers.set('content-type', 'application/wasm');
return new Response(body, { ...props, headers });
};
const initialized = new resolvable_promise_1.ResolvablePromise();
let executing = false;
class HTMLRewriter {
constructor() {
_HTMLRewriter_elementHandlers.set(this, []);
_HTMLRewriter_documentHandlers.set(this, []);
Object.defineProperty(this, _a, {
enumerable: true,
configurable: true,
writable: true,
value: false
});
if (!initialized.settled && !executing) {
executing = true;
fetch(new URL("./vendor/html_rewriter_bg.wasm", require("url").pathToFileURL(__filename).href).href)
.then(r => r.ok ? r : (() => { throw Error('WASM response not ok'); })())
.then(toWASMResponse)
.then(initWASM)
.then(() => initialized.resolve())
.catch(err => {
executing = false;
console.error(err);
});
}
}
on(selector, handlers) {
__classPrivateFieldGet(this, _HTMLRewriter_elementHandlers, "f").push([selector, handlers]);
return this;
}
onDocument(handlers) {
__classPrivateFieldGet(this, _HTMLRewriter_documentHandlers, "f").push(handlers);
return this;
}
transform(response) {
const body = response.body;
// HTMLRewriter doesn't run the end handler if the body is null, so it's
// pointless to setup the transform stream.
if (body === null)
return new Response(body, response);
if (response instanceof Response) {
// Make sure we validate chunks are BufferSources and convert them to
// Uint8Arrays as required by the Rust glue code.
response = new Response(response.body, response);
}
let rewriter;
const transformStream = new TransformStream({
start: async (controller) => {
// Create a rewriter instance for this transformation that writes its
// output to the transformed response's stream. Note that each
// BaseHTMLRewriter can only be used once.
await initialized;
rewriter = new base.HTMLRewriter((output) => {
// enqueue will throw on empty chunks
if (output.length !== 0)
controller.enqueue(output);
}, { enableEsiTags: this[kEnableEsiTags] });
// Add all registered handlers
for (const [selector, handlers] of __classPrivateFieldGet(this, _HTMLRewriter_elementHandlers, "f")) {
rewriter.on(selector, handlers);
}
for (const handlers of __classPrivateFieldGet(this, _HTMLRewriter_documentHandlers, "f")) {
rewriter.onDocument(handlers);
}
},
// The finally() below will ensure the rewriter is always freed.
// chunk is guaranteed to be a Uint8Array as we're using the
// @miniflare/core Response class, which transforms to a byte stream.
transform: (chunk) => rewriter.write(chunk),
flush: () => rewriter.end(),
});
const promise = body.pipeTo(transformStream.writable);
promise.catch(() => { }).finally(() => rewriter === null || rewriter === void 0 ? void 0 : rewriter.free());
// Return a response with the transformed body, copying over headers, etc
const res = new Response(transformStream.readable, response);
// If Content-Length is set, it's probably going to be wrong, since we're
// rewriting content, so remove it
res.headers.delete("Content-Length");
return res;
}
}
exports.HTMLRewriter = HTMLRewriter;
_HTMLRewriter_elementHandlers = new WeakMap(), _HTMLRewriter_documentHandlers = new WeakMap(), _a = kEnableEsiTags;
function withEnableEsiTags(rewriter) {
rewriter[kEnableEsiTags] = true;
return rewriter;
}
exports.withEnableEsiTags = withEnableEsiTags;
//# sourceMappingURL=index.js.map