Caution
Ampere hasn't been released yet and is still unstable. Refrain from using it ouside of testing and development purposes.
Ampere hasn't been officially released yet so NPM installations will need to be done through GitHub.
# For npm
npm install git+https://github.com/cohenerickson/Ampere.git
# For pnpm
pnpm install git+https://github.com/cohenerickson/Ampere.git
# For yarn
yarn install git+https://github.com/cohenerickson/Ampere.git
import { amperePath } from "ampere";
import express from "express";
const app = express();
app.use(express.static("public"));
app.use("/ampere", express.static(amperePath));
app.listen(3000);
Ampere has a basic configuration file just like many other proxies, it allows for the modification of the prefix, server, file locations, encoding, and more.
const config: Config = {
prefix: "/~/",
server: "https://tomp.app/",
logLevel: 0,
codec: {
encode: (value: string) => btoa(value),
decode: (value: string) => atob(value)
},
files: {
directory: "/ampere/",
config: "config.js",
client: "client.js",
worker: "worker.js",
bundle: "bundle.js"
},
plugins: []
};
Object.defineProperty(Object.prototype, "__$ampere", {
value: Object.assign(globalThis.__$ampere || {}, { config }),
configurable: false,
enumerable: false
});
Important
ALL config files must include this code at the bottom, without it Ampere won't be able to detect your config.
Object.defineProperty(Object.prototype, "__$ampere", {
value: Object.assign(globalThis.__$ampere || {}, { config }),
configurable: false,
enumerable: false
});
Ampere also supports a relatively advanced plugin API. This API can do almost anything you wish.
Plugins can run scripts on both the client and the worker they allow for modifications of core behavor and allow for new features to be implemented.
Client plugins have access to the non-proxied window context which allows them to easily extend the functionality and support of websites.
const plugin: Plugin = {
name: "Client Plugin Example",
version: "1.0.0",
description: "Example client plugin which modifies the user-agent",
client(window: Window & typeof globalThis) {
Object.defineProperty(window.navigator, "userAgent", {
value: "Some UA"
});
}
};
Plugins also support modifications on the Service-Worker through an extensive event system.
const plugin: Plugin = {
name: "Worker Plugin Example",
version: "1.0.0",
description: "Example worker plugin which modifies the user-agent",
worker(worker: AmpereWorker) {
worker.on("request", (req: Request) => {
req.headers.set("User-Agent", "Some UA");
});
}
};
request
takes a callback with one parameter of typeRequest
. This request can be modified to change the behavor of requests. Returning a new request will override the old one.response
takes a callback with one parameter of typeResponse
. This callback behaves the same as the request callback but with aResponse
object instead.pre:html
takes a callback with one parameter of typestring
. This string is the HTML content before the Ampere HTML rewriter is run. Returning a different string will modify the value passed to the Ampere HTML rewriter.post:html
takes a callback with one parameter of typestring
. This string is the HTML content after the Ampere HTML rewriter is run. Returning a different string will modify the response body of requests.pre:css
behaves the same aspre:html
but for CSS.post:css
behaves the same aspost:html
but for CSS.pre:js
behaves the same aspre:html
andpre:css
but for JS.post:js
behaves the same aspost:html
andpre:css
but for JS.pre:manifest
behaves the same as other events prefixed withpre:
but for Web Manifests.post:manifest
behaves the same as other events prefixed withpost:
but for Web Manifests.
Note
Pre-post rewriting events without the prefix will default to pre-rewriting events
Example: An event with the name of js
will be handled as if it were pre:js
Dispite the advanced plugin API, there are still limitations, that's why we allow you to easily extend the AmpereWorker
class.
class MyWorker extends AmpereWorker {
async makeRequest(url: URL, init: RequestInit): Promise<Response> {
__$ampere.logger.info("Fetching", url.href);
// do some logic
return await __$ampere.bareClient.fetch(url, init);
}
}