mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
* core, web: Vendored client follow-ups - Updated packages for use with TypeScript 6 - Fix search results including symlinks. * Bump docker package. * web: bump vite from 8.0.2 to 8.0.3 in /web Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.2 to 8.0.3. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@8.0.3/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Fix import declaration order. * Fix live reload imports, package declarations. * Tidy admin entrypoint. * Rename. * Fix import. * Fix import. * Update paths. Update Knip. * Bump knip. * Update esbuild.d.ts Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com> * Bump. * Re-enable deprecation warning. --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com> Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
243 lines
5.8 KiB
JavaScript
243 lines
5.8 KiB
JavaScript
/**
|
|
* @file Client-side observer for ESBuild events.
|
|
*
|
|
* @import { BaseLogger } from "@goauthentik/logger-js";
|
|
* @import { Message as ESBuildMessage } from "esbuild";
|
|
*/
|
|
|
|
/// <reference types="./types.js" />
|
|
|
|
import { createLogger } from "@goauthentik/esbuild-plugin-live-reload/shared";
|
|
|
|
if (typeof EventSource === "undefined") {
|
|
throw new TypeError("Environment doesn't appear to have an EventSource constructor");
|
|
}
|
|
|
|
/**
|
|
* @template {unknown} [Data=unknown]
|
|
* @typedef {(event: MessageEvent) => void} BuildEventListener
|
|
*/
|
|
|
|
/**
|
|
* A symbol used to dispose of resources.
|
|
*
|
|
* @type {typeof Symbol.dispose}
|
|
*/
|
|
const disposeSymbol = Symbol.dispose || Symbol.for("dispose");
|
|
|
|
/**
|
|
* A client-side watcher for ESBuild.
|
|
*
|
|
* Note that this should be conditionally imported in your code, so that
|
|
* ESBuild may tree-shake it out of production builds.
|
|
*
|
|
* ```ts
|
|
* if (process.env.NODE_ENV === "development") {
|
|
* await import("@goauthentik/esbuild-plugin-live-reload")
|
|
* .catch(() => console.warn("Failed to import watcher"))
|
|
* }
|
|
* ```
|
|
*
|
|
* @implements {Disposable}
|
|
* @category Plugin
|
|
* @runtime browser
|
|
*/
|
|
export class ESBuildObserver extends EventSource {
|
|
/**
|
|
* @type {BaseLogger}
|
|
* @protected
|
|
*/
|
|
logger;
|
|
|
|
/**
|
|
* Whether the watcher has a recent connection to the server.
|
|
*/
|
|
alive = true;
|
|
|
|
/**
|
|
* The number of errors that have occurred since the watcher started.
|
|
*/
|
|
errorCount = 0;
|
|
|
|
/**
|
|
* Whether a reload has been requested while offline.
|
|
*/
|
|
deferredReload = false;
|
|
|
|
/**
|
|
* The last time a message was received from the server.
|
|
*/
|
|
lastUpdatedAt = Date.now();
|
|
|
|
/**
|
|
* Whether the browser considers itself online.
|
|
*/
|
|
online = true;
|
|
|
|
/**
|
|
* The ID of the animation frame for the reload.
|
|
*/
|
|
#reloadFrameID = -1;
|
|
|
|
/**
|
|
* The interval for the keep-alive check.
|
|
* @type {ReturnType<typeof setInterval> | undefined}
|
|
*/
|
|
#keepAliveInterval;
|
|
|
|
#trackActivity = () => {
|
|
this.lastUpdatedAt = Date.now();
|
|
this.alive = true;
|
|
};
|
|
|
|
/**
|
|
* @type {BuildEventListener}
|
|
*/
|
|
#startListener = () => {
|
|
this.#trackActivity();
|
|
this.logger.info("⏰ Build started...");
|
|
};
|
|
|
|
#internalErrorListener = () => {
|
|
this.errorCount += 1;
|
|
|
|
if (this.errorCount > 100) {
|
|
clearTimeout(this.#keepAliveInterval);
|
|
|
|
this.close();
|
|
this.logger.info("⛔️ Closing connection");
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @type {BuildEventListener<string>}
|
|
*/
|
|
#errorListener = (event) => {
|
|
this.#trackActivity();
|
|
|
|
this.logger.warn("⛔️⛔️⛔️ Build error...");
|
|
|
|
/**
|
|
* @type {ESBuildMessage[]}
|
|
*/
|
|
const esbuildErrorMessages = JSON.parse(event.data);
|
|
|
|
for (const error of esbuildErrorMessages) {
|
|
this.logger.warn(error.text);
|
|
|
|
if (error.location) {
|
|
this.logger.debug(
|
|
`file://${error.location.file}:${error.location.line}:${error.location.column}`,
|
|
);
|
|
this.logger.debug(error.location.lineText);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @type {BuildEventListener}
|
|
*/
|
|
#endListener = () => {
|
|
cancelAnimationFrame(this.#reloadFrameID);
|
|
|
|
this.#trackActivity();
|
|
|
|
if (!this.online) {
|
|
this.logger.info("🚫 Build finished while offline.");
|
|
this.deferredReload = true;
|
|
|
|
return;
|
|
}
|
|
|
|
this.logger.info("🛎️ Build completed! Reloading...");
|
|
|
|
// We use an animation frame to keep the reload from happening before the
|
|
// event loop has a chance to process the message.
|
|
this.#reloadFrameID = requestAnimationFrame(() => {
|
|
location.reload();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @type {BuildEventListener}
|
|
*/
|
|
#keepAliveListener = () => {
|
|
this.#trackActivity();
|
|
this.logger.info("🏓 Keep-alive");
|
|
};
|
|
|
|
/**
|
|
* Initialize the ESBuild observer. This should only be called once.
|
|
*
|
|
* @param {string | URL} [url]
|
|
* @param {BaseLogger} [logger]
|
|
* @returns {ESBuildObserver}
|
|
*/
|
|
static initialize = (url, logger) => {
|
|
const esbuildObserver = new ESBuildObserver(url, logger);
|
|
|
|
return esbuildObserver;
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @param {string | URL} [url]
|
|
* @param {BaseLogger} [logger]
|
|
*/
|
|
constructor(url, logger = createLogger()) {
|
|
if (!url) {
|
|
throw new TypeError("ESBuildObserver: Cannot construct without a URL");
|
|
}
|
|
|
|
super(url);
|
|
|
|
this.logger = logger;
|
|
|
|
this.addEventListener("esbuild:start", this.#startListener);
|
|
this.addEventListener("esbuild:end", this.#endListener);
|
|
this.addEventListener("esbuild:error", this.#errorListener);
|
|
this.addEventListener("esbuild:keep-alive", this.#keepAliveListener);
|
|
|
|
this.addEventListener("error", this.#internalErrorListener);
|
|
|
|
addEventListener("offline", () => {
|
|
this.online = false;
|
|
});
|
|
|
|
addEventListener("online", () => {
|
|
this.online = true;
|
|
|
|
if (!this.deferredReload) return;
|
|
|
|
this.logger.info("🛎️ Reloading after offline build...");
|
|
this.deferredReload = false;
|
|
|
|
location.reload();
|
|
});
|
|
|
|
this.logger.debug("🛎️ Listening for build changes...");
|
|
|
|
this.#keepAliveInterval = setInterval(() => {
|
|
const now = Date.now();
|
|
|
|
if (now - this.lastUpdatedAt < 10_000) return;
|
|
|
|
this.alive = false;
|
|
}, 15_000);
|
|
|
|
addEventListener("beforeunload", this.dispose);
|
|
}
|
|
|
|
[disposeSymbol]() {
|
|
clearTimeout(this.#keepAliveInterval);
|
|
|
|
return this.close();
|
|
}
|
|
|
|
dispose = () => {
|
|
return this[disposeSymbol]();
|
|
};
|
|
}
|
|
|
|
export default ESBuildObserver;
|