web/NPM Workspaces: ESbuild version cleanup (#14541)

* web: Check JS files. Add types.

* web: Fix issues surrounding Vite/ESBuild types.

* web: Clean up version constants. Tidy types

* web: Clean up docs, types.

* web: Clean up package paths.

* web: (ESLint) no-lonely-if

* web: Render slot before navbar.

* web: Fix line-height alignment.

* web: Truncate long headers.

* web: Clean up page header declarations. Add story. Update paths.

* web: Ignore out directory.

* web: Lint Lit.

* web: Use private alias.

* web: Fix implicit CJS mode.

* web: Update deps.

* web: await all imports.
This commit is contained in:
Teffen Ellis
2025-05-20 02:11:18 +02:00
committed by GitHub
parent c133ba9bd3
commit 1c5e906a3e
64 changed files with 1141 additions and 798 deletions

View File

@ -3,13 +3,10 @@
* @import { StorybookConfig } from "@storybook/web-components-vite";
* @import { InlineConfig, Plugin } from "vite";
*/
import { cwd } from "process";
import postcssLit from "rollup-plugin-postcss-lit";
import tsconfigPaths from "vite-tsconfig-paths";
const NODE_ENV = process.env.NODE_ENV || "development";
const CSSImportPattern = /import [\w\$]+ from .+\.(css)/g;
const CSSImportPattern = /import [\w$]+ from .+\.(css)/g;
const JavaScriptFilePattern = /\.m?(js|ts|tsx)$/;
/**
@ -30,6 +27,11 @@ const inlineCSSPlugin = {
},
};
/**
* @satisfies {InlineConfig}
*/
// const viteFinal = ;
/**
* @satisfies {StorybookConfig}
*/
@ -48,22 +50,21 @@ const config = {
docs: {
autodocs: "tag",
},
viteFinal({ plugins = [], ...config }) {
async viteFinal(config) {
const [{ mergeConfig }, { createBundleDefinitions }] = await Promise.all([
import("vite"),
import("@goauthentik/web/bundler/utils/node"),
]);
/**
* @satisfies {InlineConfig}
*/
const mergedConfig = {
...config,
define: {
"process.env.NODE_ENV": JSON.stringify(NODE_ENV),
"process.env.CWD": JSON.stringify(cwd()),
"process.env.AK_API_BASE_PATH": JSON.stringify(process.env.AK_API_BASE_PATH || ""),
},
plugins: [inlineCSSPlugin, ...plugins, postcssLit(), tsconfigPaths()],
const overrides = {
define: createBundleDefinitions(),
plugins: [inlineCSSPlugin, postcssLit(), tsconfigPaths()],
};
return mergedConfig;
return mergeConfig(config, overrides);
},
};
export default config;

View File

@ -1,10 +1,12 @@
/**
* @file MDX plugin for ESBuild.
*
* @import {
OnLoadArgs,
OnLoadResult,
Plugin,
PluginBuild
* } from 'esbuild'
* OnLoadArgs,
* OnLoadResult,
* Plugin,
* PluginBuild
* } from "esbuild"
*/
import * as fs from "node:fs/promises";
import * as path from "node:path";

29
web/bundler/utils/node.js Normal file
View File

@ -0,0 +1,29 @@
/**
* @file Bundler utilities.
*/
import { NodeEnvironment, serializeEnvironmentVars } from "@goauthentik/core/environment/node";
import { AuthentikVersion } from "@goauthentik/core/version/node";
/**
* Creates a mapping of environment variables to their respective runtime constants.
*/
export function createBundleDefinitions() {
const SerializedNodeEnvironment = /** @type {`"development"` | `"production"`} */ (
JSON.stringify(NodeEnvironment)
);
/**
* @satisfies {Record<ESBuildImportEnvKey, string>}
*/
const envRecord = {
AK_VERSION: AuthentikVersion,
AK_API_BASE_PATH: process.env.AK_API_BASE_PATH ?? "",
};
return {
...serializeEnvironmentVars(envRecord),
// We need to explicitly set this for NPM packages that use `process`
// to determine their environment.
"process.env.NODE_ENV": SerializedNodeEnvironment,
};
}

View File

@ -12,6 +12,7 @@ export default [
{
ignores: [
"dist/",
"out/",
// don't lint the cache
".wireit/",
// let packages have their own configurations
@ -71,7 +72,7 @@ export default [
...globals.node,
},
},
files: ["scripts/**/*.mjs", "*.ts", "*.mjs"],
files: ["scripts/**/*.mjs", "*.ts", "*.mjs", "**/node.js"],
rules: {
"no-unused-vars": "off",
// We WANT our scripts to output to the console!

350
web/package-lock.json generated
View File

@ -9,7 +9,6 @@
"version": "0.0.0",
"license": "MIT",
"workspaces": [
".",
"./packages/*"
],
"dependencies": {
@ -72,21 +71,21 @@
},
"devDependencies": {
"@eslint/js": "^9.11.1",
"@goauthentik/core": "^1.0.0",
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
"@goauthentik/monorepo": "^1.0.0",
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@hcaptcha/types": "^1.0.4",
"@lit/localize-tools": "^0.8.0",
"@rollup/plugin-replace": "^6.0.1",
"@storybook/addon-essentials": "^8.6.12",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-links": "^8.6.12",
"@storybook/blocks": "^8.6.12",
"@storybook/experimental-addon-test": "^8.6.12",
"@storybook/manager-api": "^8.6.12",
"@storybook/test": "^8.6.12",
"@storybook/web-components": "^8.6.12",
"@storybook/web-components-vite": "^8.6.12",
"@storybook/experimental-addon-test": "^8.6.14",
"@storybook/manager-api": "^8.6.14",
"@storybook/test": "^8.6.14",
"@storybook/web-components": "^8.6.14",
"@storybook/web-components-vite": "^8.6.14",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/chart.js": "^2.9.41",
"@types/codemirror": "^5.60.15",
@ -119,10 +118,10 @@
"prettier": "^3.3.3",
"pseudolocale": "^2.1.0",
"rollup-plugin-postcss-lit": "^2.1.0",
"storybook": "^8.6.12",
"storybook": "^8.6.14",
"storybook-addon-mock": "^5.0.0",
"turnstile-types": "^1.2.3",
"typescript": "^5.6.2",
"typescript": "^5.8.3",
"typescript-eslint": "^8.8.0",
"vite-plugin-lit-css": "^2.0.0",
"vite-tsconfig-paths": "^5.0.1",
@ -140,6 +139,22 @@
"@rollup/rollup-linux-x64-gnu": "4.23.0"
}
},
"../packages/core": {
"name": "@goauthentik/core",
"version": "1.0.0",
"extraneous": true,
"license": "MIT",
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.14.1",
"prettier": "^3.3.3",
"typescript": "^5.6.2"
},
"engines": {
"node": ">=20.11"
}
},
"../packages/monorepo": {
"name": "@goauthentik/monorepo",
"version": "1.0.4",
@ -157,9 +172,9 @@
}
},
"node_modules/@adobe/css-tools": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz",
"integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==",
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz",
"integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==",
"dev": true,
"license": "MIT"
},
@ -1587,12 +1602,12 @@
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2025.4.1-1747687715.tgz",
"integrity": "sha512-YN1iN+OYrBociCVT55AF4QsxFo4g7tk72QFHPXEkPGhBJC+x50h6lLW30S7FtfbEVRqYmvtBUsIW+iqHFhGvtA=="
},
"node_modules/@goauthentik/esbuild-plugin-live-reload": {
"resolved": "packages/esbuild-plugin-live-reload",
"node_modules/@goauthentik/core": {
"resolved": "packages/core",
"link": true
},
"node_modules/@goauthentik/monorepo": {
"resolved": "packages/monorepo",
"node_modules/@goauthentik/esbuild-plugin-live-reload": {
"resolved": "packages/esbuild-plugin-live-reload",
"link": true
},
"node_modules/@goauthentik/prettier-config": {
@ -1621,10 +1636,6 @@
"node": ">=20.11"
}
},
"node_modules/@goauthentik/web": {
"resolved": "",
"link": true
},
"node_modules/@goauthentik/web-sfe": {
"resolved": "packages/sfe",
"link": true
@ -3610,9 +3621,9 @@
}
},
"node_modules/@storybook/addon-actions": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.12.tgz",
"integrity": "sha512-B5kfiRvi35oJ0NIo53CGH66H471A3XTzrfaa6SxXEJsgxxSeKScG5YeXcCvLiZfvANRQ7QDsmzPUgg0o3hdMXw==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.14.tgz",
"integrity": "sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3627,13 +3638,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-backgrounds": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.12.tgz",
"integrity": "sha512-lmIAma9BiiCTbJ8YfdZkXjpnAIrOUcgboLkt1f6XJ78vNEMnLNzD9gnh7Tssz1qrqvm34v9daDjIb+ggdiKp3Q==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.14.tgz",
"integrity": "sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3646,13 +3657,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-controls": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.12.tgz",
"integrity": "sha512-9VSRPJWQVb9wLp21uvpxDGNctYptyUX0gbvxIWOHMH3R2DslSoq41lsC/oQ4l4zSHVdL+nq8sCTkhBxIsjKqdQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.14.tgz",
"integrity": "sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3665,20 +3676,20 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-docs": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.12.tgz",
"integrity": "sha512-kEezQjAf/p3SpDzLABgg4fbT48B6dkT2LiZCKTRmCrJVtuReaAr4R9MMM6Jsph6XjbIj/SvOWf3CMeOPXOs9sg==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.14.tgz",
"integrity": "sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mdx-js/react": "^3.0.0",
"@storybook/blocks": "8.6.12",
"@storybook/csf-plugin": "8.6.12",
"@storybook/react-dom-shim": "8.6.12",
"@storybook/blocks": "8.6.14",
"@storybook/csf-plugin": "8.6.14",
"@storybook/react-dom-shim": "8.6.14",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"ts-dedent": "^2.0.0"
@ -3688,25 +3699,25 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-essentials": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.12.tgz",
"integrity": "sha512-Y/7e8KFlttaNfv7q2zoHMPdX6hPXHdsuQMAjYl5NG9HOAJREu4XBy4KZpbcozRe4ApZ78rYsN/MO1EuA+bNMIA==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.14.tgz",
"integrity": "sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/addon-actions": "8.6.12",
"@storybook/addon-backgrounds": "8.6.12",
"@storybook/addon-controls": "8.6.12",
"@storybook/addon-docs": "8.6.12",
"@storybook/addon-highlight": "8.6.12",
"@storybook/addon-measure": "8.6.12",
"@storybook/addon-outline": "8.6.12",
"@storybook/addon-toolbars": "8.6.12",
"@storybook/addon-viewport": "8.6.12",
"@storybook/addon-actions": "8.6.14",
"@storybook/addon-backgrounds": "8.6.14",
"@storybook/addon-controls": "8.6.14",
"@storybook/addon-docs": "8.6.14",
"@storybook/addon-highlight": "8.6.14",
"@storybook/addon-measure": "8.6.14",
"@storybook/addon-outline": "8.6.14",
"@storybook/addon-toolbars": "8.6.14",
"@storybook/addon-viewport": "8.6.14",
"ts-dedent": "^2.0.0"
},
"funding": {
@ -3714,13 +3725,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-highlight": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.12.tgz",
"integrity": "sha512-9FITVxdoycZ+eXuAZL9ElWyML/0fPPn9UgnnAkrU7zkMi+Segq/Tx7y+WWanC5zfWZrXAuG6WTOYEXeWQdm//w==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.14.tgz",
"integrity": "sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3731,7 +3742,7 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-links": {
@ -3759,9 +3770,9 @@
}
},
"node_modules/@storybook/addon-measure": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.12.tgz",
"integrity": "sha512-tACmwqqOvutaQSduw8SMb62wICaT1rWaHtMN3vtWXuxgDPSdJQxLP+wdVyRYMAgpxhLyIO7YRf++Hfha9RHgFg==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.14.tgz",
"integrity": "sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3773,13 +3784,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-outline": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.12.tgz",
"integrity": "sha512-1ylwm+n1s40S91No0v9T4tCjZORu3GbnjINlyjYTDLLhQHyBQd3nWR1Y1eewU4xH4cW9SnSLcMQFS/82xHqU6A==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.14.tgz",
"integrity": "sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3791,13 +3802,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-toolbars": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.12.tgz",
"integrity": "sha512-HEcSzo1DyFtIu5/ikVOmh5h85C1IvK9iFKSzBR6ice33zBOaehVJK+Z5f487MOXxPsZ63uvWUytwPyViGInj+g==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.14.tgz",
"integrity": "sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==",
"dev": true,
"license": "MIT",
"funding": {
@ -3805,13 +3816,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/addon-viewport": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.12.tgz",
"integrity": "sha512-EXK2LArAnABsPP0leJKy78L/lbMWow+EIJfytEP5fHaW4EhMR6h7Hzaqzre6U0IMMr/jVFa1ci+m0PJ0eQc2bw==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.14.tgz",
"integrity": "sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3822,13 +3833,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/blocks": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.12.tgz",
"integrity": "sha512-DohlTq6HM1jDbHYiXL4ZvZ00VkhpUp5uftzj/CZDLY1fYHRjqtaTwWm2/OpceivMA8zDitLcq5atEZN+f+siTg==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.14.tgz",
"integrity": "sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3842,7 +3853,7 @@
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"storybook": "^8.6.12"
"storybook": "^8.6.14"
},
"peerDependenciesMeta": {
"react": {
@ -3854,13 +3865,13 @@
}
},
"node_modules/@storybook/builder-vite": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.6.12.tgz",
"integrity": "sha512-Gju21ud/3Qw4v2vLNaa5SuJECsI9ICNRr2G0UyCCzRvCHg8jpA9lDReu2NqhLDyFIuDG+ZYT38gcaHEUoNQ8KQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.6.14.tgz",
"integrity": "sha512-ajWYhy32ksBWxwWHrjwZzyC0Ii5ZTeu5lsqA95Q/EQBB0P5qWlHWGM3AVyv82Mz/ND03ebGy123uVwgf6olnYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/csf-plugin": "8.6.12",
"@storybook/csf-plugin": "8.6.14",
"browser-assert": "^1.2.1",
"ts-dedent": "^2.0.0"
},
@ -3869,7 +3880,7 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12",
"storybook": "^8.6.14",
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0"
}
},
@ -3887,9 +3898,9 @@
}
},
"node_modules/@storybook/components": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.12.tgz",
"integrity": "sha512-FiaE8xvCdvKC2arYusgtlDNZ77b8ysr8njAYQZwwaIHjy27TbR2tEpLDCmUwSbANNmivtc/xGEiDDwcNppMWlQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.14.tgz",
"integrity": "sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==",
"dev": true,
"license": "MIT",
"funding": {
@ -3901,13 +3912,13 @@
}
},
"node_modules/@storybook/core": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.12.tgz",
"integrity": "sha512-t+ZuDzAlsXKa6tLxNZT81gEAt4GNwsKP/Id2wluhmUWD/lwYW0uum1JiPUuanw8xD6TdakCW/7ULZc7aQUBLCQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.14.tgz",
"integrity": "sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/theming": "8.6.12",
"@storybook/theming": "8.6.14",
"better-opn": "^3.0.2",
"browser-assert": "^1.2.1",
"esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0",
@ -3946,9 +3957,9 @@
}
},
"node_modules/@storybook/csf-plugin": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.12.tgz",
"integrity": "sha512-6s8CnP1aoKPb3XtC0jRLUp8M5vTA8RhGAwQDKUsFpCC7g89JR9CaKs9FY2ZSzsNbjR15uASi7b3K8BzeYumYQg==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.14.tgz",
"integrity": "sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3959,20 +3970,20 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/experimental-addon-test": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/experimental-addon-test/-/experimental-addon-test-8.6.12.tgz",
"integrity": "sha512-auc8Ql0buH0WeaKVuSSuabxIiBWvqvAyxtXCm1sVMkL68GwrX3cmpNMwviz3mvKvM//F8zKi/31HMl1PZ5UnIA==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/experimental-addon-test/-/experimental-addon-test-8.6.14.tgz",
"integrity": "sha512-Ey1WFTRXSx6Tcv2vpxW16fhk03xQKUmsdg0yWKz9llkNVTGqmL5CNMWZ7j1ZnBGneeRJOvxNsz83SwBRrr588A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.12",
"@storybook/instrumenter": "8.6.12",
"@storybook/test": "8.6.12",
"@storybook/instrumenter": "8.6.14",
"@storybook/test": "8.6.14",
"polished": "^4.2.2",
"prompts": "^2.4.0",
"ts-dedent": "^2.2.0"
@ -3984,7 +3995,7 @@
"peerDependencies": {
"@vitest/browser": "^2.1.1 || ^3.0.0",
"@vitest/runner": "^2.1.1 || ^3.0.0",
"storybook": "^8.6.12",
"storybook": "^8.6.14",
"vitest": "^2.1.1 || ^3.0.0"
},
"peerDependenciesMeta": {
@ -4019,9 +4030,9 @@
}
},
"node_modules/@storybook/instrumenter": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.12.tgz",
"integrity": "sha512-VK5fYAF8jMwWP/u3YsmSwKGh+FeSY8WZn78flzRUwirp2Eg1WWjsqPRubAk7yTpcqcC/km9YMF3KbqfzRv2s/A==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.14.tgz",
"integrity": "sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -4033,13 +4044,13 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/manager-api": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.12.tgz",
"integrity": "sha512-O0SpISeJLNTQvhSBOsWzzkCgs8vCjOq1578rwqHlC6jWWm4QmtfdyXqnv7rR1Hk08kQ+Dzqh0uhwHx0nfwy4nQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.14.tgz",
"integrity": "sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==",
"dev": true,
"license": "MIT",
"funding": {
@ -4051,9 +4062,9 @@
}
},
"node_modules/@storybook/preview-api": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.12.tgz",
"integrity": "sha512-84FE3Hrs0AYKHqpDZOwx1S/ffOfxBdL65lhCoeI8GoWwCkzwa9zEP3kvXBo/BnEDO7nAfxvMhjASTZXbKRJh5Q==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.14.tgz",
"integrity": "sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==",
"dev": true,
"license": "MIT",
"funding": {
@ -4065,9 +4076,9 @@
}
},
"node_modules/@storybook/react-dom-shim": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.12.tgz",
"integrity": "sha512-51QvoimkBzYs8s3rCYnY5h0cFqLz/Mh0vRcughwYaXckWzDBV8l67WBO5Xf5nBsukCbWyqBVPpEQLww8s7mrLA==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.14.tgz",
"integrity": "sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==",
"dev": true,
"license": "MIT",
"funding": {
@ -4077,18 +4088,18 @@
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/test": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.12.tgz",
"integrity": "sha512-0BK1Eg+VD0lNMB1BtxqHE3tP9FdkUmohtvWG7cq6lWvMrbCmAmh3VWai3RMCCDOukPFpjabOr8BBRLVvhNpv2w==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.14.tgz",
"integrity": "sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/global": "^5.0.0",
"@storybook/instrumenter": "8.6.12",
"@storybook/instrumenter": "8.6.14",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.5.0",
"@testing-library/user-event": "14.5.2",
@ -4100,7 +4111,7 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/test/node_modules/@vitest/spy": {
@ -4117,9 +4128,9 @@
}
},
"node_modules/@storybook/theming": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.12.tgz",
"integrity": "sha512-6VjZg8HJ2Op7+KV7ihJpYrDnFtd9D1jrQnUS8LckcpuBXrIEbaut5+34ObY8ssQnSqkk2GwIZBBBQYQBCVvkOw==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.14.tgz",
"integrity": "sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==",
"dev": true,
"license": "MIT",
"funding": {
@ -4131,17 +4142,17 @@
}
},
"node_modules/@storybook/web-components": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-8.6.12.tgz",
"integrity": "sha512-j+609VT8abBlpV+tB/vqSRO/fKA1QpnKWlbE0JpolzmEbgla//pAZomPysoOnvTLL3lSX3conjiAAaTpwbjyLg==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-8.6.14.tgz",
"integrity": "sha512-Jczq7EbIR3EJXX/n+0bKLW8mZS2g5Q57Y67fkw2hNr2E81OBL/4XSU9Dv4pZJXCstE1Ta+ELHj/fqbBbTj7QZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/components": "8.6.12",
"@storybook/components": "8.6.14",
"@storybook/global": "^5.0.0",
"@storybook/manager-api": "8.6.12",
"@storybook/preview-api": "8.6.12",
"@storybook/theming": "8.6.12",
"@storybook/manager-api": "8.6.14",
"@storybook/preview-api": "8.6.14",
"@storybook/theming": "8.6.14",
"tiny-invariant": "^1.3.1",
"ts-dedent": "^2.0.0"
},
@ -4154,18 +4165,18 @@
},
"peerDependencies": {
"lit": "^2.0.0 || ^3.0.0",
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@storybook/web-components-vite": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-8.6.12.tgz",
"integrity": "sha512-1YVnkk7O9zPF5xTeWD5AxpmfCx9M7C9Du8pIwcypjHQLnb34PwiyjMRztYm/JKh5kCl4BZg187r2j3Q258ytHQ==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-8.6.14.tgz",
"integrity": "sha512-7lxz/hFMTSlhl1gkjqmEp9SchSHcoDCMJTu7LuM6fJWKLHydYB6zwIyL+qYvKDa+E+kgmUKc54yW5SqAWHkjoA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/builder-vite": "8.6.12",
"@storybook/web-components": "8.6.12",
"@storybook/builder-vite": "8.6.14",
"@storybook/web-components": "8.6.14",
"magic-string": "^0.30.0"
},
"engines": {
@ -4176,7 +4187,7 @@
"url": "https://opencollective.com/storybook"
},
"peerDependencies": {
"storybook": "^8.6.12"
"storybook": "^8.6.14"
}
},
"node_modules/@swagger-api/apidom-ast": {
@ -16090,7 +16101,8 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz",
"integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/markdown-extensions": {
"version": "2.0.0",
@ -16498,6 +16510,7 @@
"resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz",
"integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==",
"dev": true,
"license": "MIT",
"dependencies": {
"map-or-similar": "^1.5.0"
}
@ -21294,13 +21307,13 @@
"optional": true
},
"node_modules/storybook": {
"version": "8.6.12",
"resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.12.tgz",
"integrity": "sha512-Z/nWYEHBTLK1ZBtAWdhxC0l5zf7ioJ7G4+zYqtTdYeb67gTnxNj80gehf8o8QY9L2zA2+eyMRGLC2V5fI7Z3Tw==",
"version": "8.6.14",
"resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.14.tgz",
"integrity": "sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@storybook/core": "8.6.12"
"@storybook/core": "8.6.14"
},
"bin": {
"getstorybook": "bin/index.cjs",
@ -22771,10 +22784,11 @@
}
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -24867,6 +24881,38 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"packages/core": {
"name": "@goauthentik/core",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.14.1",
"prettier": "^3.3.3",
"typescript": "^5.6.2"
},
"engines": {
"node": ">=20.11"
}
},
"packages/core/node_modules/@types/node": {
"version": "22.15.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz",
"integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"packages/core/node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"packages/esbuild-plugin-live-reload": {
"name": "@goauthentik/esbuild-plugin-live-reload",
"version": "1.0.4",
@ -24910,6 +24956,7 @@
"packages/monorepo": {
"name": "@goauthentik/monorepo",
"version": "1.0.0",
"extraneous": true,
"license": "MIT",
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.4",
@ -24922,23 +24969,6 @@
"node": ">=20.11"
}
},
"packages/monorepo/node_modules/@types/node": {
"version": "22.15.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz",
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"packages/monorepo/node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"packages/sfe": {
"name": "@goauthentik/web-sfe",
"version": "0.0.0",

View File

@ -35,15 +35,52 @@
"type": "module",
"exports": {
"./package.json": "./package.json",
"./paths": "./paths.js",
"./scripts/*": "./scripts/*.mjs",
"./elements/*": "./src/elements/*",
"./common/*": "./src/common/*",
"./components/*": "./src/components/*",
"./flow/*": "./src/flow/*",
"./locales/*": "./src/locales/*",
"./user/*": "./src/user/*",
"./admin/*": "./src/admin/*"
"./admin/*": "./src/admin/*",
"./*/browser": {
"types": "./out/*/browser.d.ts",
"import": "./*/browser.js"
},
"./*/node": {
"types": "./out/*/node.d.ts",
"import": "./*/node.js"
},
"./*": {
"types": "./out/*/index.d.ts",
"import": "./*/index.js"
}
},
"imports": {
"#common/*.css": "./src/common/*.css",
"#common/*": "./src/common/*.js",
"#elements/*.css": "./src/elements/*.css",
"#elements/*": "./src/elements/*.js",
"#components/*.css": "./src/components/*.css",
"#components/*": "./src/components/*.js",
"#user/*.css": "./src/user/*.css",
"#user/*": "./src/user/*.js",
"#admin/*.css": "./src/admin/*.css",
"#admin/*": "./src/admin/*.js",
"#flow/*.css": "./src/flow/*.css",
"#flow/*": "./src/flow/*.js",
"#stories/*": "./src/stories/*.js",
"#*/browser": {
"types": "./out/*/browser.d.ts",
"import": "./*/browser.js"
},
"#*/node": {
"types": "./out/*/node.d.ts",
"import": "./*/node.js"
},
"#*": {
"types": "./out/*/index.d.ts",
"import": "./*/index.js"
}
},
"dependencies": {
"@codemirror/lang-css": "^6.3.1",
@ -105,21 +142,21 @@
},
"devDependencies": {
"@eslint/js": "^9.11.1",
"@goauthentik/core": "^1.0.0",
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
"@goauthentik/monorepo": "^1.0.0",
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@hcaptcha/types": "^1.0.4",
"@lit/localize-tools": "^0.8.0",
"@rollup/plugin-replace": "^6.0.1",
"@storybook/addon-essentials": "^8.6.12",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-links": "^8.6.12",
"@storybook/blocks": "^8.6.12",
"@storybook/experimental-addon-test": "^8.6.12",
"@storybook/manager-api": "^8.6.12",
"@storybook/test": "^8.6.12",
"@storybook/web-components": "^8.6.12",
"@storybook/web-components-vite": "^8.6.12",
"@storybook/experimental-addon-test": "^8.6.14",
"@storybook/manager-api": "^8.6.14",
"@storybook/test": "^8.6.14",
"@storybook/web-components": "^8.6.14",
"@storybook/web-components-vite": "^8.6.14",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/chart.js": "^2.9.41",
"@types/codemirror": "^5.60.15",
@ -152,10 +189,10 @@
"prettier": "^3.3.3",
"pseudolocale": "^2.1.0",
"rollup-plugin-postcss-lit": "^2.1.0",
"storybook": "^8.6.12",
"storybook": "^8.6.14",
"storybook-addon-mock": "^5.0.0",
"turnstile-types": "^1.2.3",
"typescript": "^5.6.2",
"typescript": "^5.8.3",
"typescript-eslint": "^8.8.0",
"vite-plugin-lit-css": "^2.0.0",
"vite-tsconfig-paths": "^5.0.1",
@ -382,7 +419,6 @@
"node": ">=20"
},
"workspaces": [
".",
"./packages/*"
],
"prettier": "@goauthentik/prettier-config",

View File

@ -1,4 +1,4 @@
# `@goauthentik/monorepo`
# `@goauthentik/core`
This package contains utility scripts common to all TypeScript and JavaScript packages in the
`@goauthentik` monorepo.

View File

@ -0,0 +1,66 @@
/**
* @file Utility functions for working with environment variables.
*/
/// <reference types="../types/node.js" />
//#region Constants
/**
* The current Node.js environment, defaulting to "development" when not set.
*
* Note, this should only be used during the build process.
*
* If you need to check the environment at runtime, use `process.env.NODE_ENV` to
* ensure that module tree-shaking works correctly.
*
* @category Environment
* @runtime node
*/
export const NodeEnvironment = process.env.NODE_ENV || "development";
/**
* A source environment variable, which can be a string, number, boolean, null, or undefined.
* @typedef {string | number | boolean | null | undefined} EnvironmentVariable
*/
/**
* A type helper for serializing environment variables.
*
* @category Environment
* @template {EnvironmentVariable} T
* @typedef {T extends string ? `"${T}"` : T} JSONify
*/
//#endregion
//#region Utilities
/**
* Given an object of environment variables, serializes them into a mapping of
* environment variable names to their respective runtime constants.
*
* This is useful for defining environment variables while bundling with ESBuild, Vite, etc.
*
* @category Environment
* @runtime node
*
* @template {Record<string, EnvironmentVariable>} EnvRecord
* @template {string} [Prefix='import.meta.env.']
*
* @param {EnvRecord} input
* @param {Prefix} [prefix='import.meta.env.']
*
* @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify<EnvRecord[K]>}}
*/
export function serializeEnvironmentVars(
input,
prefix = /** @type {Prefix} */ ("import.meta.env."),
) {
const env = Object.fromEntries(
Object.entries(input).map(([key, value]) => [prefix + key, JSON.stringify(value ?? "")]),
);
return /** @type {any} */ (env);
}
//#endregion

View File

@ -0,0 +1,12 @@
/**
* @file Dummy entry point for the `core` package.
*
* This exists to make TypeScript's module resolution more predictable.
*
* @internal
* @ignore
*/
export {};
export default {};

View File

@ -0,0 +1,59 @@
{
"name": "@goauthentik/core",
"version": "1.0.0",
"description": "Core functionality for the authentik monorepo",
"license": "MIT",
"private": true,
"scripts": {
"build": "tsc -p .",
"prettier": "prettier --write .",
"prettier-check": "prettier --check ."
},
"main": "index.js",
"type": "module",
"exports": {
"./package.json": "./package.json",
"./*/browser": {
"types": "./out/*/browser.d.ts",
"import": "./*/browser.js"
},
"./*/node": {
"types": "./out/*/node.d.ts",
"import": "./*/node.js"
},
"./*": {
"types": "./out/*/index.d.ts",
"import": "./*/index.js"
},
".": {
"import": "./index.js",
"types": "./out/index.d.ts"
}
},
"imports": {
"#*/browser": {
"types": "./out/*/browser.d.ts",
"import": "./*/browser.js"
},
"#*/node": {
"types": "./out/*/node.d.ts",
"import": "./*/node.js"
},
"#*": {
"types": "./out/*/index.d.ts",
"import": "./*/index.js"
}
},
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.14.1",
"prettier": "^3.3.3",
"typescript": "^5.6.2"
},
"engines": {
"node": ">=20.11"
},
"types": "./out/index.d.ts",
"prettier": "@goauthentik/prettier-config"
}

View File

@ -10,22 +10,26 @@ const relativeDirname = dirname(fileURLToPath(import.meta.url));
/**
* The root of the authentik monorepo.
*
* @runtime node
*/
// TODO: Revise when this package is moved to the monorepo's `packages/monorepo` directory.
export const MonoRepoRoot = /** @type {MonoRepoRoot} */ (
resolve(relativeDirname, "..", "..", "..")
resolve(relativeDirname, "..", "..", "..", "..")
);
const require = createRequire(import.meta.url);
/**
* Resolve a package name to its location in the monorepo to the single node_modules directory.
* @param {string} packageName
*
* @param {string} packageName
* @param {ImportMeta} [meta] The `import.meta` object of the module.
*
* @runtime node
* @returns {string} The resolved path to the package.
* @throws {Error} If the package cannot be resolved.
*/
export function resolvePackage(packageName) {
export function resolvePackage(packageName, meta) {
const require = createRequire(meta ? meta.url : import.meta.url);
const relativePackageJSONPath = join(packageName, "package.json");
/** @type {string} */
@ -34,7 +38,7 @@ export function resolvePackage(packageName) {
try {
absolutePackageJSONPath = require.resolve(relativePackageJSONPath);
} catch (cause) {
const error = new Error(`Failed to resolve package "${packageName}"`);
const error = new Error(`🚫 Failed to resolve package "${packageName}"`);
error.cause = cause;

View File

@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
* @param {ImportMeta} meta The `import.meta` object of the module.
*
* @return {boolean} Whether the module was run directly.
* @runtime node
*/
export function isMain(meta) {
// Are we not in a module context?

View File

@ -1,9 +1,11 @@
{
"extends": "@goauthentik/tsconfig",
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"resolveJsonModule": true,
"baseUrl": ".",
"checkJs": true,
"allowJs": true,
"emitDeclarationOnly": true
}
}

54
web/packages/core/types/node.d.ts vendored Normal file
View File

@ -0,0 +1,54 @@
/**
* @file Global variables provided by Node.js
*/
declare module "module" {
global {
/**
* @deprecated This is not present in ESM files.
*
* ```js
* import { dirname } from "node:path";
* import { fileURLToPath } from "node:url";
*
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
* ```
*/
// eslint-disable-next-line no-var
var __dirname: string;
}
}
declare module "process" {
global {
namespace NodeJS {
interface ProcessEnv {
/**
* The port used by the Docker Compose HTTP service.
*/
COMPOSE_PORT_HTTP?: string;
/**
* The port used by the Docker Compose HTTPS service.
*/
COMPOSE_PORT_HTTPS?: string;
/**
* An environment variable used to determine
* whether Node.js is running in production mode.
*
* @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production}
* @runtime node
*/
readonly NODE_ENV?: "development" | "production";
/**
* @todo Determine where this is used and if it is needed,
* give it a better name.
* @deprecated
* @runtime node
*/
readonly AK_API_BASE_PATH?: string;
}
}
}
}

View File

@ -0,0 +1,21 @@
/**
* @file Utility functions for working with semantic versions.
*
* @runtime common
*/
/**
* Creates a URL to the release notes for the given version.
*
* @param {string} semver
* @returns {URL}
* @runtime common
*/
export function createReleaseNotesURL(semver) {
const segments = semver.split(".");
const versionFamily = segments.slice(0, -1).join(".");
const release = `${versionFamily}#fixed-in-${segments.join("")}`;
return new URL(`/docs/releases/${release}`, "https://goauthentik.io");
}

View File

@ -1,16 +1,24 @@
/**
* @file Utility functions for working with semantic versions.
*
* @runtime node
*/
import { MonoRepoRoot } from "#paths/node";
import { execSync } from "node:child_process";
import PackageJSON from "../../../package.json" with { type: "json" };
import { MonoRepoRoot } from "./paths.js";
import PackageJSON from "../../../../package.json" with { type: "json" };
/**
* The current version of authentik in SemVer format.
*
* @runtime node
*/
export const AuthentikVersion = /**@type {`${number}.${number}.${number}`} */ (PackageJSON.version);
/**
* Reads the last commit hash from the current git repository.
*
* @runtime node
*/
export function readGitBuildHash() {
try {
@ -34,6 +42,7 @@ export function readGitBuildHash() {
*
* This must match the behavior defined in authentik's server-side `get_full_version` function.
*
* @runtime node
* @see {@link "authentik\_\_init\_\_.py"}
*/
export function readBuildIdentifier() {

View File

@ -21,7 +21,7 @@ const log = console.debug.bind(console, logPrefix);
* ESBuild may tree-shake it out of production builds.
*
* ```ts
* if (process.env.NODE_ENV === "development") {
* if (process.env.NODE_ENV=== "development") {
* await import("@goauthentik/esbuild-plugin-live-reload/client")
* .catch(() => console.warn("Failed to import watcher"))
* }

View File

@ -4,15 +4,20 @@
export {};
declare global {
/**
* Environment variables injected by ESBuild.
*/
interface ImportMetaEnv {
/**
* The injected watcher URL for ESBuild.
* This is used for live reloading in development mode.
*
* @format url
*/
readonly ESBUILD_WATCHER_URL?: string;
}
interface ImportMeta {
readonly env: {
/**
* The injected watcher URL for ESBuild.
* This is used for live reloading in development mode.
*
* @format url
*/
ESBUILD_WATCHER_URL: string;
};
readonly env: ImportMetaEnv;
}
}

View File

@ -1,42 +0,0 @@
/**
* @file Utility functions for building and copying files.
*/
/**
* A source environment variable, which can be a string, number, boolean, null, or undefined.
* @typedef {string | number | boolean | null | undefined} EnvironmentVariable
*/
/**
* A type helper for serializing environment variables.
*
* @template {EnvironmentVariable} T
* @typedef {T extends string ? `"${T}"` : T} JSONify
*/
/**
* Given an object of environment variables, returns a new object with the same keys and values, but
* with the values serialized as strings.
*
* @template {Record<string, EnvironmentVariable>} EnvRecord
* @template {string} [Prefix='process.env.']
*
* @param {EnvRecord} input
* @param {Prefix} [prefix='process.env.']
*
* @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify<EnvRecord[K]>}}
*/
export function serializeEnvironmentVars(input, prefix = /** @type {Prefix} */ ("process.env.")) {
/**
* @type {Record<string, string>}
*/
const env = {};
for (const [key, value] of Object.entries(input)) {
const namespaceKey = prefix + key;
env[namespaceKey] = JSON.stringify(value || "");
}
return /** @type {any} */ (env);
}

View File

@ -1,16 +0,0 @@
/**
* @file Constants for JavaScript and TypeScript files.
*/
/// <reference types="../../types/global.js" />
/**
* The current Node.js environment, defaulting to "development" when not set.
*
* Note, this should only be used during the build process.
*
* If you need to check the environment at runtime, use `process.env.NODE_ENV` to
* ensure that module tree-shaking works correctly.
*
*/
export const NodeEnvironment = process.env.NODE_ENV || "development";

View File

@ -1,7 +0,0 @@
/// <reference types="./types/global.js" />
export * from "./paths.js";
export * from "./constants.js";
export * from "./build.js";
export * from "./version.js";
export * from "./scripting.js";

View File

@ -1,28 +0,0 @@
{
"name": "@goauthentik/monorepo",
"version": "1.0.0",
"description": "Utilities for the authentik monorepo.",
"license": "MIT",
"private": true,
"main": "index.js",
"type": "module",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./out/index.d.ts",
"import": "./index.js"
}
},
"devDependencies": {
"@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.14.1",
"prettier": "^3.3.3",
"typescript": "^5.6.2"
},
"engines": {
"node": ">=20.11"
},
"types": "./out/index.d.ts",
"prettier": "@goauthentik/prettier-config"
}

View File

@ -1,15 +0,0 @@
declare module "process" {
global {
namespace NodeJS {
interface ProcessEnv {
/**
* An environment variable used to determine
* whether Node.js is running in production mode.
*
* @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production}
*/
NODE_ENV?: "production" | "development";
}
}
}
}

View File

@ -12,7 +12,7 @@ const relativeDirname = dirname(fileURLToPath(import.meta.url));
/**
* The root of the web package.
*/
export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(relativeDirname));
export const PackageRoot = /** @type {WebPackageIdentifier} */ (resolve(relativeDirname, ".."));
/**
* The name of the distribution directory.
@ -25,7 +25,7 @@ export const DistDirectoryName = "dist";
* This is where the built files are located after running the build process.
*/
export const DistDirectory = /** @type {`${WebPackageIdentifier}/${DistDirectoryName}`} */ (
resolve(relativeDirname, DistDirectoryName)
resolve(PackageRoot, DistDirectoryName)
);
//#endregion

View File

@ -1,17 +1,33 @@
import { spawnSync } from "child_process";
import fs from "fs";
import path from "path";
import process from "process";
/**
* @file Lit Localize build script.
*
* @remarks
* Determines if all the Xliff translation source files are present and
* if the Typescript source files generated from those sources are up-to-date.
*
* If they are not, it runs the locale building script, intercepting the
* long spew of "this string is not translated" and replacing it with a
* summary of how many strings are missing with respect to the source locale.
*
* @import { ConfigFile } from "@lit/localize-tools/lib/types/config"
*/
import { PackageRoot } from "#paths/node";
import { spawnSync } from "node:child_process";
import { readFileSync, statSync } from "node:fs";
import path from "node:path";
/**
* Determines if all the Xliff translation source files are present and if the Typescript source
* files generated from those sources are up-to-date. If they are not, it runs the locale building
* script, intercepting the long spew of "this string is not translated" and replacing it with a
* summary of how many strings are missing with respect to the source locale.
* @type {ConfigFile}
*/
const localizeRules = JSON.parse(
readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"),
);
const localizeRules = JSON.parse(fs.readFileSync("./lit-localize.json", "utf-8"));
/**
*
* @param {string} loc
* @returns {boolean}
*/
function generatedFileIsUpToDateWithXliffSource(loc) {
const xliff = path.join("./xliff", `${loc}.xlf`);
const gened = path.join("./src/locales", `${loc}.ts`);
@ -22,7 +38,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) {
// generates a unique error message and halts the build.
try {
var xlfStat = fs.statSync(xliff);
var xlfStat = statSync(xliff);
} catch (_error) {
console.error(`lit-localize expected '${loc}.xlf', but XLF file is not present`);
process.exit(1);
@ -30,7 +46,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) {
// If the generated file doesn't exist, of course it's not up to date.
try {
var genedStat = fs.statSync(gened);
var genedStat = statSync(gened);
} catch (_error) {
return false;
}

View File

@ -1,17 +1,16 @@
/// <reference types="../types/esbuild.js" />
/**
* @file ESBuild script for building the authentik web UI.
*
* @import { BuildOptions } from "esbuild";
*/
import { mdxPlugin } from "#bundler/mdx-plugin/node";
import { createBundleDefinitions } from "#bundler/utils/node";
import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "#paths/node";
import { NodeEnvironment } from "@goauthentik/core/environment/node";
import { MonoRepoRoot, resolvePackage } from "@goauthentik/core/paths/node";
import { readBuildIdentifier } from "@goauthentik/core/version/node";
import { liveReloadPlugin } from "@goauthentik/esbuild-plugin-live-reload/plugin";
import {
MonoRepoRoot,
NodeEnvironment,
readBuildIdentifier,
resolvePackage,
serializeEnvironmentVars,
} from "@goauthentik/monorepo";
import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "@goauthentik/web/paths";
import { deepmerge } from "deepmerge-ts";
import esbuild from "esbuild";
import copy from "esbuild-plugin-copy";
@ -19,17 +18,9 @@ import { polyfillNode } from "esbuild-plugin-polyfill-node";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
const logPrefix = "[Build]";
const definitions = serializeEnvironmentVars({
NODE_ENV: NodeEnvironment,
CWD: process.cwd(),
AK_API_BASE_PATH: process.env.AK_API_BASE_PATH,
});
const patternflyPath = resolvePackage("@patternfly/patternfly");
const patternflyPath = resolvePackage("@patternfly/patternfly", import.meta);
/**
* @type {Readonly<BuildOptions>}
@ -86,7 +77,7 @@ const BASE_ESBUILD_OPTIONS = {
root: MonoRepoRoot,
}),
],
define: definitions,
define: createBundleDefinitions(),
format: "esm",
logOverride: {
/**
@ -168,6 +159,19 @@ async function doWatch() {
await buildContext.rebuild();
await buildContext.watch();
const httpURL = new URL("http://localhost");
httpURL.port = process.env.COMPOSE_PORT_HTTP ?? "9000";
const httpsURL = new URL("http://localhost");
httpsURL.port = process.env.COMPOSE_PORT_HTTPS ?? "9443";
console.log(`\n${logPrefix} 🚀 Server running\n\n`);
console.log(` 🔓 ${httpURL.href}`);
console.log(` 🔒 ${httpsURL.href}`);
console.log(`\n---`);
return /** @type {Promise<void>} */ (
new Promise((resolve) => {
process.on("SIGINT", () => {

View File

@ -35,6 +35,11 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url));
const projectRoot = path.join(__dirname, "..");
process.chdir(projectRoot);
/**
*
* @param {string[]} flags
* @returns
*/
const hasFlag = (flags) => process.argv.length > 1 && flags.includes(process.argv[2]);
const [configFile, files] = hasFlag(["-n", "--nightmare"])

View File

@ -152,6 +152,7 @@ export default [
{
ignores: [
"dist/",
"out/",
".wireit/",
"packages/",
// don't ever lint node_modules

View File

@ -1,22 +1,36 @@
import { readFileSync } from "fs";
import path from "path";
/**
* @file Pseudo-localization script.
*
* @import { ConfigFile } from "@lit/localize-tools/lib/types/config.js"
* @import { Config } from '@lit/localize-tools/lib/types/config.js';
* @import { ProgramMessage } from "@lit/localize-tools/src/messages.js"
* @import { Locale } from "@lit/localize-tools/src/types/locale.js"
*/
import { PackageRoot } from "#paths/node";
import { readFileSync } from "node:fs";
import path from "node:path";
import pseudolocale from "pseudolocale";
import { fileURLToPath } from "url";
import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js";
import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js";
import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const pseudoLocale = "pseudo-LOCALE";
const pseudoLocale = /** @type {Locale} */ ("pseudo-LOCALE");
const targetLocales = [pseudoLocale];
const baseConfig = JSON.parse(readFileSync(path.join(__dirname, "../lit-localize.json"), "utf-8"));
/**
* @type {ConfigFile}
*/
const baseConfig = JSON.parse(readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"));
// Need to make some internal specifications to satisfy the transformer. It doesn't actually matter
// which Localizer we use (transformer or runtime), because all of the functionality we care about
// is in their common parent class, but I had to pick one. Everything else here is just pure
// exploitation of the lit/localize-tools internals.
/**
* @satisfies {Config}
*/
const config = {
...baseConfig,
baseDir: path.join(__dirname, ".."),
@ -28,6 +42,11 @@ const config = {
resolve: (path) => path,
};
/**
*
* @param {ProgramMessage} message
* @returns
*/
const pseudoMessagify = (message) => ({
name: message.name,
contents: message.contents.map((content) =>
@ -36,7 +55,7 @@ const pseudoMessagify = (message) => ({
});
const localizer = new TransformLitLocalizer(config);
const messages = localizer.extractSourceMessages().messages;
const { messages } = localizer.extractSourceMessages();
const translations = messages.map(pseudoMessagify);
const sorted = sortProgramMessages([...messages]);
const formatter = makeFormatter(config);

View File

@ -1,5 +1,4 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { VERSION } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global";
import { DefaultBrand } from "@goauthentik/common/ui/config";
import "@goauthentik/elements/EmptyState";
@ -45,7 +44,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
}
return [
[msg("Version"), version.versionCurrent],
[msg("UI Version"), VERSION],
[msg("UI Version"), import.meta.env.AK_VERSION],
[msg("Build"), build],
[msg("Python version"), status.runtime.pythonVersion],
[msg("Platform"), status.runtime.platform],

View File

@ -1,29 +1,26 @@
import { EVENT_API_DRAWER_TOGGLE, EVENT_NOTIFICATION_DRAWER_TOGGLE } from "#common/constants";
import { configureSentry } from "#common/sentry/index";
import { me } from "#common/users";
import { WebsocketClient } from "#common/ws";
import { AuthenticatedInterface } from "#elements/Interface/Interface";
import { WithLicenseSummary } from "#elements/Interface/licenseSummaryProvider";
import "#elements/ak-locale-context/ak-locale-context";
import "#elements/banner/EnterpriseStatusBanner";
import "#elements/banner/EnterpriseStatusBanner";
import "#elements/banner/VersionBanner";
import "#elements/banner/VersionBanner";
import "#elements/messages/MessageContainer";
import "#elements/messages/MessageContainer";
import "#elements/notifications/APIDrawer";
import "#elements/notifications/NotificationDrawer";
import { getURLParam, updateURLParams } from "#elements/router/RouteMatch";
import "#elements/router/RouterOutlet";
import "#elements/sidebar/Sidebar";
import "#elements/sidebar/SidebarItem";
import "@goauthentik/admin/AdminInterface/AboutModal";
import type { AboutModal } from "@goauthentik/admin/AdminInterface/AboutModal";
import { ROUTES } from "@goauthentik/admin/Routes";
import {
EVENT_API_DRAWER_TOGGLE,
EVENT_NOTIFICATION_DRAWER_TOGGLE,
} from "@goauthentik/common/constants";
import { configureSentry } from "@goauthentik/common/sentry";
import { me } from "@goauthentik/common/users";
import { WebsocketClient } from "@goauthentik/common/ws";
import { AuthenticatedInterface } from "@goauthentik/elements/Interface";
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider.js";
import { SidebarToggleEventDetail } from "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/ak-locale-context";
import "@goauthentik/elements/banner/EnterpriseStatusBanner";
import "@goauthentik/elements/banner/EnterpriseStatusBanner";
import "@goauthentik/elements/banner/VersionBanner";
import "@goauthentik/elements/banner/VersionBanner";
import "@goauthentik/elements/messages/MessageContainer";
import "@goauthentik/elements/messages/MessageContainer";
import "@goauthentik/elements/notifications/APIDrawer";
import "@goauthentik/elements/notifications/NotificationDrawer";
import { getURLParam, updateURLParams } from "@goauthentik/elements/router/RouteMatch";
import "@goauthentik/elements/router/RouterOutlet";
import "@goauthentik/elements/sidebar/Sidebar";
import "@goauthentik/elements/sidebar/SidebarItem";
import { SidebarToggleEventDetail } from "@goauthentik/components/ak-page-header.js";
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, eventOptions, property, query } from "lit/decorators.js";

View File

@ -1,9 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { parseAPIResponseError, pluckErrorDetail } from "@goauthentik/common/errors/network";
import { MessageLevel } from "@goauthentik/common/messages";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { DEFAULT_CONFIG } from "#common/api/config";
import { parseAPIResponseError, pluckErrorDetail } from "#common/errors/network";
import { MessageLevel } from "#common/messages";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import { showMessage } from "#elements/messages/MessageContainer";
import * as Sentry from "@sentry/browser";
import { CSSResult, TemplateResult, html } from "lit";

View File

@ -1,29 +1,27 @@
import "@goauthentik/admin/admin-overview/TopApplicationsTable";
import "@goauthentik/admin/admin-overview/cards/AdminStatusCard";
import "@goauthentik/admin/admin-overview/cards/FipsStatusCard";
import "@goauthentik/admin/admin-overview/cards/RecentEventsCard";
import "@goauthentik/admin/admin-overview/cards/SystemStatusCard";
import "@goauthentik/admin/admin-overview/cards/VersionStatusCard";
import "@goauthentik/admin/admin-overview/cards/WorkerStatusCard";
import "@goauthentik/admin/admin-overview/charts/AdminLoginAuthorizeChart";
import "@goauthentik/admin/admin-overview/charts/OutpostStatusChart";
import "@goauthentik/admin/admin-overview/charts/SyncStatusChart";
import { VERSION } from "@goauthentik/common/constants";
import { me } from "@goauthentik/common/users";
import { AKElement } from "@goauthentik/elements/Base";
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider.js";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/cards/AggregatePromiseCard";
import "@goauthentik/elements/cards/QuickActionsCard.js";
import type { QuickAction } from "@goauthentik/elements/cards/QuickActionsCard.js";
import { paramURL } from "@goauthentik/elements/router/RouterOutlet";
import "#admin/admin-overview/TopApplicationsTable";
import "#admin/admin-overview/cards/AdminStatusCard";
import "#admin/admin-overview/cards/FipsStatusCard";
import "#admin/admin-overview/cards/RecentEventsCard";
import "#admin/admin-overview/cards/SystemStatusCard";
import "#admin/admin-overview/cards/VersionStatusCard";
import "#admin/admin-overview/cards/WorkerStatusCard";
import "#admin/admin-overview/charts/AdminLoginAuthorizeChart";
import "#admin/admin-overview/charts/OutpostStatusChart";
import "#admin/admin-overview/charts/SyncStatusChart";
import { me } from "#common/users";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import { WithLicenseSummary } from "#elements/Interface/licenseSummaryProvider";
import "#elements/cards/AggregatePromiseCard";
import type { QuickAction } from "#elements/cards/QuickActionsCard";
import "#elements/cards/QuickActionsCard";
import { paramURL } from "#elements/router/RouterOutlet";
import { createReleaseNotesURL } from "@goauthentik/core/version";
import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { map } from "lit/directives/map.js";
import { when } from "lit/directives/when.js";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFDivider from "@patternfly/patternfly/components/Divider/divider.css";
@ -33,21 +31,8 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { SessionUser } from "@goauthentik/api";
export function versionFamily(): string {
const parts = VERSION.split(".");
parts.pop();
return parts.join(".");
}
const RELEASE = `${VERSION.split(".").slice(0, -1).join(".")}#fixed-in-${VERSION.replaceAll(
".",
"",
)}`;
const AdminOverviewBase = WithLicenseSummary(AKElement);
type Renderer = () => TemplateResult | typeof nothing;
@customElement("ak-admin-overview")
export class AdminOverviewPage extends AdminOverviewBase {
static get styles(): CSSResult[] {
@ -83,7 +68,11 @@ export class AdminOverviewPage extends AdminOverviewBase {
[msg("Check the logs"), paramURL("/events/log")],
[msg("Explore integrations"), "https://goauthentik.io/integrations/", true],
[msg("Manage users"), paramURL("/identity/users")],
[msg("Check the release notes"), `https://goauthentik.io/docs/releases/${RELEASE}`, true],
[
msg("Check the release notes"),
createReleaseNotesURL(import.meta.env.AK_VERSION).href,
true,
],
];
@state()
@ -193,45 +182,6 @@ export class AdminOverviewPage extends AdminOverviewBase {
</div>`
: nothing} `;
}
renderActions() {
const release = `${versionFamily()}#fixed-in-${VERSION.replaceAll(".", "")}`;
const quickActions: [string, string][] = [
[msg("Create a new application"), paramURL("/core/applications", { createForm: true })],
[msg("Check the logs"), paramURL("/events/log")],
[msg("Explore integrations"), "https://goauthentik.io/integrations/"],
[msg("Manage users"), paramURL("/identity/users")],
[msg("Check the release notes"), `https://goauthentik.io/docs/releases/${release}`],
];
const action = ([label, url]: [string, string]) => {
const isExternal = url.startsWith("https://");
const ex = (truecase: Renderer, falsecase: Renderer) =>
when(isExternal, truecase, falsecase);
const content = html`${label}${ex(
() => html`<i class="fas fa-external-link-alt ak-external-link"></i>`,
() => nothing,
)}`;
return html`<li>
${ex(
() =>
html`<a
href="${url}"
class="pf-u-mb-xl"
rel="noopener noreferrer"
target="_blank"
>${content}</a
>`,
() => html`<a href="${url}" class="pf-u-mb-xl" )>${content}</a>`,
)}
</li>`;
};
return html`${map(quickActions, action)}`;
}
}
declare global {

View File

@ -1,7 +1,7 @@
import "@goauthentik/admin/admin-overview/charts/AdminModelPerDay";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/cards/AggregatePromiseCard";
import "#admin/admin-overview/charts/AdminModelPerDay";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import "#elements/cards/AggregatePromiseCard";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit";

View File

@ -1,16 +1,15 @@
import "@goauthentik/admin/admin-settings/AdminSettingsForm";
import { AdminSettingsForm } from "@goauthentik/admin/admin-settings/AdminSettingsForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/components/events/ObjectChangelog";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/ModalForm";
import "#admin/admin-settings/AdminSettingsForm";
import { AdminSettingsForm } from "#admin/admin-settings/AdminSettingsForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import "#components/ak-page-header";
import "#components/events/ObjectChangelog";
import { AKElement } from "#elements/Base";
import "#elements/CodeMirror";
import "#elements/EmptyState";
import "#elements/Tabs";
import "#elements/buttons/ModalButton";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import "#elements/forms/ModalForm";
import { msg } from "@lit/localize";
import { html, nothing } from "lit";

View File

@ -1,18 +1,18 @@
import "@goauthentik/admin/applications/ApplicationAuthorizeChart";
import "@goauthentik/admin/applications/ApplicationCheckAccessForm";
import "@goauthentik/admin/applications/ApplicationForm";
import "@goauthentik/admin/applications/entitlements/ApplicationEntitlementPage";
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFSize } from "@goauthentik/common/enums.js";
import "@goauthentik/components/events/ObjectChangelog";
import "@goauthentik/elements/AppIcon";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/SpinnerButton";
import "#admin/applications/ApplicationAuthorizeChart";
import "#admin/applications/ApplicationCheckAccessForm";
import "#admin/applications/ApplicationForm";
import "#admin/applications/entitlements/ApplicationEntitlementPage";
import "#admin/policies/BoundPoliciesList";
import "#admin/rbac/ObjectPermissionsPage";
import { DEFAULT_CONFIG } from "#common/api/config";
import { PFSize } from "#common/enums";
import "#components/ak-page-header";
import "#components/events/ObjectChangelog";
import "#elements/AppIcon";
import { AKElement } from "#elements/Base";
import "#elements/EmptyState";
import "#elements/Tabs";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { msg } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";

View File

@ -1,11 +1,11 @@
import { EventGeo, EventUser } from "@goauthentik/admin/events/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EventWithContext } from "@goauthentik/common/events";
import { actionToLabel } from "@goauthentik/common/labels";
import { formatElapsedTime } from "@goauthentik/common/temporal";
import "@goauthentik/components/ak-event-info";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader";
import { EventGeo, EventUser } from "#admin/events/utils";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EventWithContext } from "#common/events";
import { actionToLabel } from "#common/labels";
import { formatElapsedTime } from "#common/temporal";
import "#components/ak-event-info";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import { msg, str } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, html } from "lit";

View File

@ -1,16 +1,16 @@
import "@goauthentik/admin/flows/BoundStagesList";
import "@goauthentik/admin/flows/FlowDiagram";
import "@goauthentik/admin/flows/FlowForm";
import { DesignationToLabel } from "@goauthentik/admin/flows/utils";
import "@goauthentik/admin/policies/BoundPoliciesList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import { AndNext, DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { isResponseErrorLike } from "@goauthentik/common/errors/network";
import "@goauthentik/components/events/ObjectChangelog";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/SpinnerButton";
import "#admin/flows/BoundStagesList";
import "#admin/flows/FlowDiagram";
import "#admin/flows/FlowForm";
import { DesignationToLabel } from "#admin/flows/utils";
import "#admin/policies/BoundPoliciesList";
import "#admin/rbac/ObjectPermissionsPage";
import { AndNext, DEFAULT_CONFIG } from "#common/api/config";
import { isResponseErrorLike } from "#common/errors/network";
import "#components/ak-page-header";
import "#components/events/ObjectChangelog";
import { AKElement } from "#elements/Base";
import "#elements/Tabs";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { msg } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit";

View File

@ -3,11 +3,11 @@ import "@goauthentik/admin/groups/RelatedUserList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import "@goauthentik/components/ak-page-header";
import "@goauthentik/components/ak-status-label";
import "@goauthentik/components/events/ObjectChangelog";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";

View File

@ -1,18 +1,18 @@
import "@goauthentik/admin/providers/google_workspace/GoogleWorkspaceProviderViewPage";
import "@goauthentik/admin/providers/ldap/LDAPProviderViewPage";
import "@goauthentik/admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage";
import "@goauthentik/admin/providers/oauth2/OAuth2ProviderViewPage";
import "@goauthentik/admin/providers/proxy/ProxyProviderViewPage";
import "@goauthentik/admin/providers/rac/RACProviderViewPage";
import "@goauthentik/admin/providers/radius/RadiusProviderViewPage";
import "@goauthentik/admin/providers/saml/SAMLProviderViewPage";
import "@goauthentik/admin/providers/scim/SCIMProviderViewPage";
import "@goauthentik/admin/providers/ssf/SSFProviderViewPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/buttons/SpinnerButton";
import "#admin/providers/google_workspace/GoogleWorkspaceProviderViewPage";
import "#admin/providers/ldap/LDAPProviderViewPage";
import "#admin/providers/microsoft_entra/MicrosoftEntraProviderViewPage";
import "#admin/providers/oauth2/OAuth2ProviderViewPage";
import "#admin/providers/proxy/ProxyProviderViewPage";
import "#admin/providers/rac/RACProviderViewPage";
import "#admin/providers/radius/RadiusProviderViewPage";
import "#admin/providers/saml/SAMLProviderViewPage";
import "#admin/providers/scim/SCIMProviderViewPage";
import "#admin/providers/ssf/SSFProviderViewPage";
import { DEFAULT_CONFIG } from "#common/api/config";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import "#elements/EmptyState";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { CSSResult, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";

View File

@ -1,11 +1,11 @@
import "@goauthentik/admin/rbac/InitialPermissionsForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "#admin/rbac/InitialPermissionsForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import "#elements/forms/DeleteBulkForm";
import "#elements/forms/ModalForm";
import { PaginatedResponse } from "#elements/table/Table";
import { TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -1,11 +1,11 @@
import "@goauthentik/admin/roles/RoleForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "#admin/roles/RoleForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import "#elements/forms/DeleteBulkForm";
import "#elements/forms/ModalForm";
import { PaginatedResponse } from "#elements/table/Table";
import { TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -1,15 +1,15 @@
import "@goauthentik/admin/groups/RelatedGroupList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/roles/RoleForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { renderDescriptionList } from "@goauthentik/components/DescriptionList";
import "@goauthentik/components/events/ObjectChangelog";
import "@goauthentik/components/events/UserEvents";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/forms/ModalForm";
import "#admin/groups/RelatedGroupList";
import "#admin/rbac/ObjectPermissionsPage";
import "#admin/roles/RoleForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { renderDescriptionList } from "#components/DescriptionList";
import "#components/ak-page-header";
import "#components/events/ObjectChangelog";
import "#components/events/UserEvents";
import { AKElement } from "#elements/Base";
import "#elements/Tabs";
import "#elements/forms/ModalForm";
import { msg, str } from "@lit/localize";
import { css, html, nothing } from "lit";

View File

@ -1,14 +1,14 @@
import "@goauthentik/admin/sources/kerberos/KerberosSourceViewPage";
import "@goauthentik/admin/sources/ldap/LDAPSourceViewPage";
import "@goauthentik/admin/sources/oauth/OAuthSourceViewPage";
import "@goauthentik/admin/sources/plex/PlexSourceViewPage";
import "@goauthentik/admin/sources/saml/SAMLSourceViewPage";
import "@goauthentik/admin/sources/scim/SCIMSourceViewPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/buttons/SpinnerButton";
import "#admin/sources/kerberos/KerberosSourceViewPage";
import "#admin/sources/ldap/LDAPSourceViewPage";
import "#admin/sources/oauth/OAuthSourceViewPage";
import "#admin/sources/plex/PlexSourceViewPage";
import "#admin/sources/saml/SAMLSourceViewPage";
import "#admin/sources/scim/SCIMSourceViewPage";
import { DEFAULT_CONFIG } from "#common/api/config";
import "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import "#elements/EmptyState";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";

View File

@ -1,15 +1,15 @@
import "@goauthentik/admin/rbac/ObjectPermissionModal";
import "@goauthentik/admin/stages/invitation/InvitationForm";
import "@goauthentik/admin/stages/invitation/InvitationListLink";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PFColor } from "@goauthentik/elements/Label";
import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "#admin/rbac/ObjectPermissionModal";
import "#admin/stages/invitation/InvitationForm";
import "#admin/stages/invitation/InvitationListLink";
import { DEFAULT_CONFIG } from "#common/api/config";
import { PFColor } from "#elements/Label";
import "#elements/buttons/ModalButton";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import "#elements/forms/DeleteBulkForm";
import "#elements/forms/ModalForm";
import { PaginatedResponse } from "#elements/table/Table";
import { TableColumn } from "#elements/table/Table";
import { TablePage } from "#elements/table/TablePage";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";

View File

@ -1,44 +1,38 @@
import "@goauthentik/admin/groups/RelatedGroupList";
import "@goauthentik/admin/providers/rac/ConnectionTokenList";
import "@goauthentik/admin/rbac/ObjectPermissionsPage";
import "@goauthentik/admin/users/UserActiveForm";
import "@goauthentik/admin/users/UserApplicationTable";
import "@goauthentik/admin/users/UserChart";
import "@goauthentik/admin/users/UserForm";
import "@goauthentik/admin/users/UserImpersonateForm";
import {
renderRecoveryEmailRequest,
requestRecoveryLink,
} from "@goauthentik/admin/users/UserListPage";
import "@goauthentik/admin/users/UserPasswordForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { PFSize } from "@goauthentik/common/enums.js";
import { userTypeToLabel } from "@goauthentik/common/labels";
import { formatElapsedTime } from "@goauthentik/common/temporal";
import { me } from "@goauthentik/common/users";
import "@goauthentik/components/DescriptionList";
import {
type DescriptionPair,
renderDescriptionList,
} from "@goauthentik/components/DescriptionList";
import "@goauthentik/components/ak-status-label";
import "@goauthentik/components/events/ObjectChangelog";
import "@goauthentik/components/events/UserEvents";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/CodeMirror";
import { WithCapabilitiesConfig } from "@goauthentik/elements/Interface/capabilitiesProvider";
import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/ActionButton";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/ModalForm";
import "@goauthentik/elements/oauth/UserAccessTokenList";
import "@goauthentik/elements/oauth/UserRefreshTokenList";
import "@goauthentik/elements/user/SessionList";
import "@goauthentik/elements/user/UserConsentList";
import "@goauthentik/elements/user/UserReputationList";
import "@goauthentik/elements/user/sources/SourceSettings";
import "#admin/groups/RelatedGroupList";
import "#admin/providers/rac/ConnectionTokenList";
import "#admin/rbac/ObjectPermissionsPage";
import "#admin/users/UserActiveForm";
import "#admin/users/UserApplicationTable";
import "#admin/users/UserChart";
import "#admin/users/UserForm";
import "#admin/users/UserImpersonateForm";
import { renderRecoveryEmailRequest, requestRecoveryLink } from "#admin/users/UserListPage";
import "#admin/users/UserPasswordForm";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { PFSize } from "#common/enums";
import { userTypeToLabel } from "#common/labels";
import { formatElapsedTime } from "#common/temporal";
import { me } from "#common/users";
import "#components/DescriptionList";
import { type DescriptionPair, renderDescriptionList } from "#components/DescriptionList";
import "#components/ak-page-header";
import "#components/ak-status-label";
import "#components/events/ObjectChangelog";
import "#components/events/UserEvents";
import { AKElement } from "#elements/Base";
import "#elements/CodeMirror";
import { WithCapabilitiesConfig } from "#elements/Interface/capabilitiesProvider";
import "#elements/Tabs";
import "#elements/buttons/ActionButton/ak-action-button";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
import "#elements/forms/ModalForm";
import "#elements/oauth/UserAccessTokenList";
import "#elements/oauth/UserRefreshTokenList";
import "#elements/user/SessionList";
import "#elements/user/UserConsentList";
import "#elements/user/UserReputationList";
import "#elements/user/sources/SourceSettings";
import { msg, str } from "@lit/localize";
import { TemplateResult, css, html, nothing } from "lit";

View File

@ -3,7 +3,7 @@ import {
EventMiddleware,
LoggingMiddleware,
} from "@goauthentik/common/api/middleware.js";
import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants.js";
import { EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants.js";
import { globalAK } from "@goauthentik/common/global.js";
import { SentryMiddleware } from "@goauthentik/common/sentry/middleware";
@ -79,4 +79,6 @@ export function AndNext(url: string): string {
return `?next=${encodeURIComponent(url)}`;
}
console.debug(`authentik(early): version ${VERSION}, apiBase ${DEFAULT_CONFIG.basePath}`);
console.debug(
`authentik(early): version ${import.meta.env.AK_VERSION}, apiBase ${DEFAULT_CONFIG.basePath}`,
);

View File

@ -1,12 +1,35 @@
/**
* @file Global constants used throughout the application.
*
* @todo Much of this content can be moved to a specific file, element, or component.
*/
/// <reference types="../../types/esbuild.js" />
//#region Patternfly
export const SECONDARY_CLASS = "pf-m-secondary";
export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2025.4.1";
//#endregion
//#region Application
export const TITLE_DEFAULT = "authentik";
/**
* The delimiter used to parse the URL for the current route.
*
* @todo Move this to the ak-router.
*/
export const ROUTE_SEPARATOR = ";";
//#endregion
//#region Events
export const EVENT_REFRESH = "ak-refresh";
export const EVENT_NOTIFICATION_DRAWER_TOGGLE = "ak-notification-toggle";
export const EVENT_API_DRAWER_TOGGLE = "ak-api-drawer-toggle";
@ -20,7 +43,17 @@ export const EVENT_MESSAGE = "ak-message";
export const EVENT_THEME_CHANGE = "ak-theme-change";
export const EVENT_REFRESH_ENTERPRISE = "ak-refresh-enterprise";
//#endregion
//#region WebSocket
export const WS_MSG_TYPE_MESSAGE = "message";
export const WS_MSG_TYPE_REFRESH = "refresh";
//#endregion
//#region LocalStorage
export const LOCALSTORAGE_AUTHENTIK_KEY = "authentik-local-settings";
//#endregion

View File

@ -1,4 +1,3 @@
import { VERSION } from "@goauthentik/common/constants";
import { SentryIgnoredError } from "@goauthentik/common/sentry";
export interface PlexPinResponse {
@ -19,7 +18,7 @@ export const DEFAULT_HEADERS = {
"Accept": "application/json",
"Content-Type": "application/json",
"X-Plex-Product": "authentik",
"X-Plex-Version": VERSION,
"X-Plex-Version": import.meta.env.AK_VERSION,
"X-Plex-Device-Vendor": "goauthentik.io",
};

View File

@ -1,4 +1,3 @@
import { VERSION } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global";
import { me } from "@goauthentik/common/users";
import { readInterfaceRouteParam } from "@goauthentik/elements/router/utils";
@ -41,7 +40,7 @@ export function configureSentry(canDoPpi = false) {
/MutationObserver.observe/gi,
/NS_ERROR_FAILURE/gi,
],
release: `authentik@${VERSION}`,
release: `authentik@${import.meta.env.AK_VERSION}`,
integrations: [
browserTracingIntegration({
// https://docs.sentry.io/platforms/javascript/tracing/instrumentation/automatic-instrumentation/#custom-routing

View File

@ -1,15 +1,11 @@
/**
* @file Theme utilities.
*/
import {
type StyleRoot,
createStyleSheetUnsafe,
setAdoptedStyleSheets,
} from "@goauthentik/web/common/stylesheets.js";
import { UIConfig } from "@goauthentik/web/common/ui/config.js";
import { type StyleRoot, createStyleSheetUnsafe, setAdoptedStyleSheets } from "#common/stylesheets";
import { UIConfig } from "#common/ui/config";
import AKBase from "@goauthentik/web/common/styles/authentik.css";
import AKBaseDark from "@goauthentik/web/common/styles/theme-dark.css";
import AKBase from "#common/styles/authentik.css";
import AKBaseDark from "#common/styles/theme-dark.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api";

View File

@ -1,5 +1,4 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { VERSION } from "@goauthentik/common/constants";
import { PFSize } from "@goauthentik/common/enums.js";
import {
EventContext,
@ -76,7 +75,7 @@ ${context.message as string}
**Version and Deployment (please complete the following information):**
- authentik version: ${VERSION}
- authentik version: ${import.meta.env.AK_VERSION}
- Deployment: [e.g. docker-compose, helm]
**Additional context**

View File

@ -0,0 +1,84 @@
import "#components/ak-nav-buttons";
import { AKPageNavbar } from "#components/ak-page-navbar";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { CSSResult, LitElement, css } from "lit";
import { customElement, property } from "lit/decorators.js";
export interface PageHeaderInit {
header?: string;
description?: string;
icon?: string;
iconImage?: boolean;
}
//#region Events
export interface SidebarToggleEventDetail {
open?: boolean;
}
//#endregion
//#region Page Header
/**
* A page header component, used to display the page title and description.
*
* Internally, this component dispatches the `ak-page-header` event, which is
* listened to by the `ak-page-navbar` component.
*
* @singleton
*/
@customElement("ak-page-header")
export class AKPageHeader extends LitElement implements PageHeaderInit {
@property({ type: String })
header?: string;
@property({ type: String })
description?: string;
@property({ type: String })
icon?: string;
@property({ type: Boolean })
iconImage = false;
static get styles(): CSSResult[] {
return [
css`
:host {
display: none;
}
`,
];
}
connectedCallback(): void {
super.connectedCallback();
AKPageNavbar.setNavbarDetails({
header: this.header,
description: this.description,
icon: this.icon,
iconImage: this.iconImage,
});
}
updated(): void {
AKPageNavbar.setNavbarDetails({
header: this.header,
description: this.description,
icon: this.icon,
iconImage: this.iconImage,
});
}
}
//#endregion
declare global {
interface HTMLElementTagNameMap {
"ak-page-header": AKPageHeader;
}
}

View File

@ -1,17 +1,18 @@
import { EVENT_WS_MESSAGE, TITLE_DEFAULT } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global";
import { UIConfig, UserDisplay, getConfigForUser } from "@goauthentik/common/ui/config";
import { DefaultBrand } from "@goauthentik/common/ui/config";
import { me } from "@goauthentik/common/users";
import "@goauthentik/components/ak-nav-buttons";
import { AKElement } from "@goauthentik/elements/Base";
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
import { isAdminRoute } from "@goauthentik/elements/router/utils";
import { themeImage } from "@goauthentik/elements/utils/images";
import { EVENT_WS_MESSAGE, TITLE_DEFAULT } from "#common/constants";
import { globalAK } from "#common/global";
import { UIConfig, UserDisplay, getConfigForUser } from "#common/ui/config";
import { DefaultBrand } from "#common/ui/config";
import { me } from "#common/users";
import "#components/ak-nav-buttons";
import type { PageHeaderInit, SidebarToggleEventDetail } from "#components/ak-page-header";
import { AKElement } from "#elements/Base";
import { WithBrandConfig } from "#elements/Interface/brandProvider";
import { isAdminRoute } from "#elements/router/utils";
import { themeImage } from "#elements/utils/images";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";
import { CSSResult, LitElement, TemplateResult, css, html, nothing } from "lit";
import { CSSResult, TemplateResult, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
@ -25,23 +26,6 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { SessionUser } from "@goauthentik/api";
//#region Events
export interface SidebarToggleEventDetail {
open?: boolean;
}
//#endregion
//#region Page Navbar
export interface PageNavbarDetails {
header?: string;
description?: string;
icon?: string;
iconImage?: boolean;
}
/**
* A global navbar component at the top of the page.
*
@ -51,13 +35,13 @@ export interface PageNavbarDetails {
@customElement("ak-page-navbar")
export class AKPageNavbar
extends WithBrandConfig(AKElement)
implements PageNavbarDetails, SidebarToggleEventDetail
implements PageHeaderInit, SidebarToggleEventDetail
{
//#region Static Properties
private static elementRef: AKPageNavbar | null = null;
static readonly setNavbarDetails = (detail: Partial<PageNavbarDetails>): void => {
static readonly setNavbarDetails = (detail: Partial<PageHeaderInit>): void => {
const { elementRef } = AKPageNavbar;
if (!elementRef) {
console.debug(
@ -115,7 +99,6 @@ export class AKPageNavbar
flex-direction: row;
display: grid;
row-gap: var(--pf-global--spacer--sm);
column-gap: var(--pf-global--spacer--sm);
grid-template-columns: [brand] auto [toggle] auto [primary] 1fr [secondary] auto;
grid-template-rows: auto auto;
@ -123,7 +106,7 @@ export class AKPageNavbar
"brand toggle primary secondary"
"brand toggle description secondary";
@media (min-width: 426px) {
@media (min-width: 769px) {
height: var(--host-navbar-height);
}
@ -146,9 +129,17 @@ export class AKPageNavbar
grid-column: primary;
grid-row: primary / description;
align-content: center;
align-self: center;
padding-block: var(--pf-global--spacer--md);
@media (max-width: 768px) {
padding-block: var(--pf-global--spacer--sm);
}
&.block-sibling {
align-self: end;
}
@media (min-width: 426px) {
&.block-sibling {
padding-block-end: 0;
@ -156,10 +147,6 @@ export class AKPageNavbar
}
}
@media (max-width: 768px) {
padding-block: var(--pf-global--spacer--sm);
}
.accent-icon {
height: 1em;
width: 1em;
@ -249,9 +236,14 @@ export class AKPageNavbar
color: var(--pf-global--active-color--100);
}
.page-title {
display: flex;
gap: var(--pf-global--spacer--xs);
.pf-c-content .page-title {
display: box;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
box-orient: vertical;
-webkit-box-orient: vertical;
overflow: hidden;
}
h1 {
@ -370,7 +362,8 @@ export class AKPageNavbar
}
render(): TemplateResult {
return html`<navbar aria-label="Main" class="navbar">
return html` <slot></slot>
<navbar aria-label="Main" class="navbar">
<aside class="brand ${this.open ? "" : "pf-m-collapsed"}">
<a href="#/">
<div class="logo">
@ -422,75 +415,14 @@ export class AKPageNavbar
</ak-nav-buttons>
</div>
</section>
</navbar>
<slot></slot>`;
</navbar>`;
}
//#endregion
}
//#endregion
//#region Page Header
/**
* A page header component, used to display the page title and description.
*
* Internally, this component dispatches the `ak-page-header` event, which is
* listened to by the `ak-page-navbar` component.
*
* @singleton
*/
@customElement("ak-page-header")
export class AKPageHeader extends LitElement implements PageNavbarDetails {
@property({ type: String })
header?: string;
@property({ type: String })
description?: string;
@property({ type: String })
icon?: string;
@property({ type: Boolean })
iconImage = false;
static get styles(): CSSResult[] {
return [
css`
:host {
display: none;
}
`,
];
}
connectedCallback(): void {
super.connectedCallback();
AKPageNavbar.setNavbarDetails({
header: this.header,
description: this.description,
icon: this.icon,
iconImage: this.iconImage,
});
}
updated(): void {
AKPageNavbar.setNavbarDetails({
header: this.header,
description: this.description,
icon: this.icon,
iconImage: this.iconImage,
});
}
}
//#endregion
declare global {
interface HTMLElementTagNameMap {
"ak-page-header": AKPageHeader;
"ak-page-navbar": AKPageNavbar;
}
}

View File

@ -0,0 +1,58 @@
import { DefaultBrand } from "#common/ui/config";
import "#components/ak-page-header";
import { AKPageNavbar } from "#components/ak-page-navbar";
import { Meta } from "@storybook/web-components";
import { html } from "lit";
import { customElement } from "lit/decorators.js";
import { CurrentBrand } from "@goauthentik/api";
const metadata: Meta<AKPageNavbar> = {
title: "Components / Page Navbar",
component: "ak-page-navbar",
parameters: {
docs: {
description: {
component: "A page navbar for the authentik web interface",
},
},
},
};
export default metadata;
@customElement("story-ak-page-navbar")
class AKPageNavbarStory extends AKPageNavbar {
brand: CurrentBrand = {
...DefaultBrand,
brandingLogo: new URL(DefaultBrand.brandingLogo, "http://localhost:9000").toString(),
};
}
declare global {
interface HTMLElementTagNameMap {
"story-ak-page-navbar": AKPageNavbarStory;
}
}
export const SimplePageNavbar = () => {
return html`
<story-ak-page-navbar open @sidebar-toggle=${() => {}}>
<ak-page-header header="Page Title" description="Page Description"> </ak-page-header>
</story-ak-page-navbar>
`;
};
export const PageNavbarWithIcon = () => {
return html`
<story-ak-page-navbar open @sidebar-toggle=${() => {}}>
<ak-page-header
header="Page Title"
description="Page Description"
icon="pf-icon pf-icon-user"
>
</ak-page-header>
</story-ak-page-navbar>
`;
};

View File

@ -1,4 +1,3 @@
import { VERSION } from "@goauthentik/common/constants";
import { AKElement } from "@goauthentik/elements/Base";
import { WithVersion } from "@goauthentik/elements/Interface/versionProvider";
@ -10,20 +9,19 @@ import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
@customElement("ak-version-banner")
export class VersionBanner extends WithVersion(AKElement) {
static get styles() {
return [PFBanner];
}
static styles = [PFBanner];
render() {
return this.version && this.version.versionCurrent !== VERSION
? html`
<div class="pf-c-banner pf-m-sticky pf-m-gold">
${msg(
str`A newer version (${this.version.versionCurrent}) of the UI is available.`,
)}
</div>
`
: nothing;
if (!this.version?.versionCurrent) return nothing;
if (this.version.versionCurrent === import.meta.env.AK_VERSION) return nothing;
return html`
<div class="pf-c-banner pf-m-sticky pf-m-gold">
${msg(
str`A newer version (${this.version.versionCurrent}) of the UI is available.`,
)}
</div>
`;
}
}

View File

@ -16,7 +16,7 @@ indicating if the browser should open the link in a new tab.
## Usage
```Typescript
import "@goauthentik/elements/cards/QuickActionsCard.js";
import "@goauthentik/web/elements/cards/QuickActionsCard";
const ACTIONS: QuickAction[] = [
["Create a new application", "/core/applications"],

View File

@ -1,6 +1,6 @@
import "@goauthentik/elements/PageHeader";
import { updateURLParams } from "@goauthentik/elements/router/RouteMatch";
import { Table } from "@goauthentik/elements/table/Table";
import "#components/ak-page-header";
import { updateURLParams } from "#elements/router/RouteMatch";
import { Table } from "#elements/table/Table";
import { msg } from "@lit/localize";
import { CSSResult } from "lit";

View File

@ -215,13 +215,11 @@ export class RacInterface extends Interface {
);
return;
}
} else {
if (this.connectionAttempt >= RECONNECT_ATTEMPTS) {
this.reconnectingMessage = msg(
str`Connection failed after ${this.connectionAttempt} attempts.`,
);
return;
}
} else if (this.connectionAttempt >= RECONNECT_ATTEMPTS) {
this.reconnectingMessage = msg(
str`Connection failed after ${this.connectionAttempt} attempts.`,
);
return;
}
const delay = 500 * this.connectionAttempt;
this.reconnectingMessage = msg(

View File

@ -2,6 +2,9 @@
{
"extends": "@goauthentik/tsconfig",
"compilerOptions": {
"checkJs": true,
"allowJs": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"emitDeclarationOnly": true,
"experimentalDecorators": true,
@ -58,6 +61,9 @@
"src/**/*.comp.ts"
],
"references": [
{
"path": "./packages/core"
},
{
"path": "./packages/esbuild-plugin-live-reload"
}

39
web/types/esbuild.d.ts vendored Normal file
View File

@ -0,0 +1,39 @@
/**
* @file Import meta environment variables available via ESBuild.
*/
export {};
declare global {
interface ESBuildImportEnv {
/**
* The authentik version injected by ESBuild during build time.
*
* @format semver
*/
readonly AK_VERSION: string;
/**
* @todo Determine where this is used and if it is needed,
* give it a better name.
* @deprecated
*/
readonly AK_API_BASE_PATH: string;
}
type ESBuildImportEnvKey = keyof ESBuildImportEnv;
/**
* Environment variables injected by ESBuild.
*/
interface ImportMetaEnv extends ESBuildImportEnv {
/**
* An environment variable used to determine
* whether Node.js is running in production mode.
*/
readonly NODE_ENV: "development" | "production";
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
}

View File

@ -1,5 +1,5 @@
/**
* @file Environment variables available via ESBuild.
* @file Global variables provided by Node.js
*/
declare module "module" {
@ -23,13 +23,19 @@ declare module "process" {
global {
namespace NodeJS {
interface ProcessEnv {
CWD: string;
/**
* An environment variable used to determine
* whether Node.js is running in production mode.
*
* @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production}
*/
readonly NODE_ENV?: "development" | "production";
/**
* @todo Determine where this is used and if it is needed,
* give it a better name.
* @deprecated
*/
AK_API_BASE_PATH: string;
readonly AK_API_BASE_PATH?: string;
}
}
}

View File

@ -1,17 +1,15 @@
import replace from "@rollup/plugin-replace";
/// <reference types="@wdio/browser-runner" />
import { createBundleDefinitions } from "#bundler/utils/node";
import { browser } from "@wdio/globals";
import type { Options } from "@wdio/types";
import path from "path";
import { cwd } from "process";
import { fileURLToPath } from "url";
import type { UserConfig } from "vite";
import litCss from "vite-plugin-lit-css";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { InlineConfig } from "vite";
import litCSS from "vite-plugin-lit-css";
import tsconfigPaths from "vite-tsconfig-paths";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const isProdBuild = process.env.NODE_ENV === "production";
const apiBasePath = process.env.AK_API_BASE_PATH || "";
const runHeadless = process.env.CI !== undefined;
const testSafari = process.env.WDIO_TEST_SAFARI !== undefined;
@ -72,21 +70,9 @@ export const config: Options.Testrunner = {
runner: [
"browser",
{
viteConfig: (userConfig: UserConfig = { plugins: [] }) => ({
...userConfig,
plugins: [
litCss(),
replace({
"process.env.NODE_ENV": JSON.stringify(
isProdBuild ? "production" : "development",
),
"process.env.CWD": JSON.stringify(cwd()),
"process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
"preventAssignment": true,
}),
...(userConfig?.plugins ?? []),
tsconfigPaths(),
],
viteConfig: {
define: createBundleDefinitions(),
plugins: [litCSS(), tsconfigPaths()],
resolve: {
alias: {
"@goauthentik/admin": path.resolve(__dirname, "src/admin"),
@ -101,7 +87,7 @@ export const config: Options.Testrunner = {
"@goauthentik/user": path.resolve(__dirname, "src/user"),
},
},
}),
} satisfies InlineConfig,
},
],