Files
authentik/web/package.json
Teffen Ellis 220eb26e5f web: MDX without React (#21949)
* packages/theme: add the @goauthentik/theme design-system package (#23341)

* packages/fonts: add @goauthentik/fonts package

Extract the bundled web fonts out of web/ into a dedicated
@goauthentik/fonts workspace package: the RedHat variable faces, the
PatternFly pficon icon face, and the FontAwesome Free solid face, each
with its upstream license recorded under licenses/.

web/ now pulls the faces and icons from the package's
@goauthentik/fonts/faces.css and @goauthentik/fonts/icons.css entry
points instead of the old #fonts/* import and the inlined pficon.scss
vendor sheet.

Anchor esbuild's [dir] at the monorepo root via outbase so assets pulled
from the out-of-web package no longer resolve to a "_.._" segment, which
Go's //go:embed silently drops from the embedded outpost build.

Co-Authored-By: Ken Sternberg <ken@goauthentik.io>

* packages/theme: add @goauthentik/theme design-system package

Add @goauthentik/theme, which defines authentik's design tokens (color,
typography, fonts, spacing, shape, shadow, motion, z-index) in TypeScript
and builds them into CSS via styleframe.

Token names carry a distinct separator per category so the token type is
recoverable from the name alone. That is worth the verbosity: it keeps
the DX legible and leaves room for automatic theme management and future
tooling built on top of the token set.

Co-Authored-By: Ken Sternberg <ken@goauthentik.io>

* web/theme: add a demo page for the theme tokens

Add a self-contained demo page, built by build-demo.mjs, that renders
every theme token — colors, typography, spacing, shape, shadow, motion —
so the design system can be eyeballed in isolation while it evolves.

Co-Authored-By: Ken Sternberg <ken@goauthentik.io>

* Heal lockfile.

* Fix spelling.

* Fix grouping.

---------

Co-authored-by: Ken Sternberg <ken@goauthentik.io>

* web/elements/ak-mdx: drop React + runtime MDX eval, use unified pipeline

Replace `@mdx-js/mdx`'s `evaluate`/`run` (which depends on `'unsafe-eval'`
in the page CSP) with a pure `unified`/remark/rehype pipeline. URL-mode
content now arrives from the build-time `mdx-plugin` as pre-rendered HTML
and is stamped through a Trusted Types passthrough policy
(`CompiledMarkdownTrustPolicy`) so admin-side custom elements like
`<ak-alert>` and `<ak-md-a>` survive. Content-mode (admin-supplied
markdown) is compiled in-browser via `compileRuntimeMarkdown` and routed
through the existing `BrandedHTMLPolicy` (DOMPurify).

`<ak-md-a>` replaces the React `MDXAnchor`/`MDXWrapper` pair: a tiny Lit
custom element with `display: contents` that intercepts in-doc fragment
clicks for shadow-root scrolling. The remark plugins gain `caution` and
`tip` admonition types and promote `:::name[Title]` directive labels to
`<strong>`. `one-dark.css` learns `:host` so syntax-highlighted code
blocks inherit the palette inside `<ak-mdx>`'s shadow tree.

Removes `@mdx-js/mdx`, `react`, `react-dom`, `rehype-mermaid`, and
`remark-mdx-frontmatter`. Adds `unified`, `remark-parse`, `remark-rehype`,
and `mdast-util-to-string`.

Co-Authored-By: Agent <279763771+playpen-agent@users.noreply.github.com>

* web/bundler/mdx-plugin: pre-render markdown to HTML at build time

Compile each `.md` / `.mdx` file through a build-time `unified` pipeline
(remark-parse, GFM, frontmatter, directives, custom admonition/headings/
lists transforms; rehype-rehype, anchor wrapping, syntax highlighting,
mermaid extraction) and emit a JSON envelope of
`{ content: HTML, frontmatter, publicPath, publicDirectory }`. The
on-load result still ships via the `file` loader so the runtime side
keeps its existing fetch path. The compiled HTML uses `<ak-md-a>` and
`<ak-alert>` custom elements so `<ak-mdx>` can stamp it directly into
shadow DOM with no client-side JavaScript evaluation.

Plugin is split across four sibling files (`node.js`, `compile.js`,
`remark.js`, `rehype.js`) so each concern lives in its own module. The
title/wrapper HTML is built as a hast tree and serialized through
`hast-util-to-html` rather than string-concatenated, dropping the
hand-rolled `escapeHTML` helper and unifying escape semantics with the
rest of the document.

Co-Authored-By: Agent <279763771+playpen-agent@users.noreply.github.com>

* web/test: e2e ak-mdx pipeline via OAuth2 provider docs

The OAuth2 provider docs page exercises the full pipeline in one place:
frontmatter title, multiple H2 slugs, `:::caution`/`:::info` admonitions
(with and without titles), relative-doc links, external links, and an
embedded mermaid sequence diagram. Tests boot the admin UI, provision a
fresh OAuth2 provider, navigate to its view page, and assert against the
compiled DOM inside `<ak-mdx>`'s shadow root.

Co-Authored-By: Agent <279763771+playpen-agent@users.noreply.github.com>

* web/elements/ak-mdx: sanitize replacer output, note pipeline drift

Address PR review feedback on the URL-mode trust boundary. `<ak-mdx>`'s
`replacers` hook runs over pre-rendered build-time HTML before it is
stamped into the DOM, and consumers (e.g. `ProxyProviderViewPage`) splice
admin-controlled values such as `provider.externalHost` into it. The old
React pipeline ran replacers on raw markdown that was then compiled, so
those values were HTML-escaped on serialization; the new URL mode passed
the post-replacer HTML straight through, dropping that guarantee.

Replace the passthrough `CompiledMarkdownTrustPolicy` with
`CompiledMarkdownSanitizePolicy`: a DOMPurify policy that whitelists the
custom elements (`<ak-alert>`, `<ak-md-a>`, `<ak-diagram>`) and the
`part`/`level` attributes our pipeline emits, and strips anything else a
replacer could inject.

Also add a reciprocal drift note to the runtime `markdown.ts` pointing at
`bundler/mdx-plugin/`, mirroring the existing note on the bundler side.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix anchor slugification.

* Spellcheck.

---------

Co-authored-by: Ken Sternberg <ken@goauthentik.io>
Co-authored-by: Agent <279763771+playpen-agent@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-24 22:55:37 +01:00

307 lines
11 KiB
JSON

{
"name": "@goauthentik/web",
"version": "2026.11.0-rc1",
"license": "MIT",
"private": true,
"scripts": {
"build": "wireit",
"build:sfe": "pnpm --filter @goauthentik/web-sfe run build",
"build-locales": "node scripts/build-locales.mjs",
"build-proxy": "wireit",
"bundler:watch": "node scripts/build-web.mjs --watch",
"extract-locales": "lit-localize extract",
"format": "wireit",
"lint": "eslint --fix .",
"lint:imports": "knip --config scripts/knip.config.ts",
"lint:types": "wireit",
"lint-check": "eslint --max-warnings 0 .",
"lit-analyse": "wireit",
"precommit": "wireit",
"prettier": "prettier --cache --write -u .",
"prettier-check": "prettier --cache --check -u .",
"pseudolocalize": "node ./scripts/pseudolocalize.mjs",
"storybook": "storybook dev -p 6006",
"storybook:build": "wireit",
"test": "vitest",
"test:e2e": "playwright test",
"tsc": "wireit",
"watch": "run-s build-locales bundler:watch"
},
"type": "module",
"exports": {
"./package.json": "./package.json",
"./styles/*": "./src/styles/*",
"./elements/*": "./src/elements/*",
"./common/*": "./src/common/*",
"./components/*": "./src/components/*",
"./flow/*": "./src/flow/*",
"./locales/*": "./src/locales/*",
"./user/*": "./src/user/*",
"./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": {
"#styles/*.css": "./src/styles/*.css",
"#styles/*": "./src/styles/*.js",
"#common/*": "./src/common/*.js",
"#elements/dialogs": "./src/elements/dialogs/index.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",
"#locales/*": "./src/locales/*.js",
"#stories/*": "./src/stories/*.js",
"#tests/*": "./tests/*.js",
"#e2e": "./e2e/index.ts",
"#e2e/*": "./e2e/*.ts",
"#types/*": "./types/*/index.d.ts",
"#*/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",
"@codemirror/lang-html": "^6.4.11",
"@codemirror/lang-javascript": "^6.2.5",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/legacy-modes": "^6.5.3",
"@codemirror/theme-one-dark": "^6.1.3",
"@eslint/js": "catalog:",
"@formatjs/intl-listformat": "^8.3.13",
"@fortawesome/fontawesome-free": "^7.3.1",
"@goauthentik/api": "link:packages/client-ts",
"@goauthentik/brand-assets": "^2.0.0",
"@goauthentik/core": "workspace:*",
"@goauthentik/esbuild-plugin-live-reload": "^2.0.3",
"@goauthentik/eslint-config": "^2.0.3",
"@goauthentik/fonts": "link:../packages/fonts",
"@goauthentik/prettier-config": "^3.5.0",
"@goauthentik/theme": "link:../packages/theme",
"@goauthentik/tsconfig": "^1.0.9",
"@hcaptcha/types": "^1.2.0",
"@lit/context": "^1.1.6",
"@lit/localize": "^0.12.2",
"@lit/localize-tools": "^0.8.2",
"@lit/reactive-element": "^2.1.2",
"@lit/task": "^1.0.3",
"@mermaid-js/layout-elk": "^0.2.2",
"@mrmarble/djangoql-completion": "^0.8.3",
"@open-wc/lit-helpers": "^0.7.0",
"@patternfly/elements": "^4.4.0",
"@patternfly/patternfly": "^4.224.5",
"@playwright/test": "catalog:",
"@protomaps/basemaps": "^5.7.2",
"@sentry/browser": "^10.70.0",
"@storybook/addon-docs": "^10.5.10",
"@storybook/addon-links": "^10.5.10",
"@storybook/web-components": "^10.5.10",
"@storybook/web-components-vite": "^10.5.10",
"@types/codemirror": "^5.60.17",
"@types/grecaptcha": "^3.0.9",
"@types/guacamole-common-js": "^1.5.5",
"@types/node": "catalog:",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "catalog:",
"@typescript-eslint/parser": "catalog:",
"@typescript-eslint/utils": "catalog:",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
"@vitest/browser": "catalog:",
"@vitest/browser-playwright": "catalog:",
"@webcomponents/webcomponentsjs": "^2.8.0",
"base64-js": "^1.5.1",
"change-case": "^5.4.4",
"chart.js": "^4.5.1",
"chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.2",
"core-js": "^3.49.0",
"country-flag-icons": "^1.6.20",
"date-fns": "^4.4.0",
"deepmerge-ts": "^8.0.0",
"dompurify": "^3.4.13",
"esbuild": "catalog:",
"eslint": "catalog:",
"eslint-plugin-lit": "^2.3.1",
"eslint-plugin-wc": "^3.1.0",
"fuse.js": "^7.4.2",
"github-slugger": "^2.0.0",
"globals": "^17.8.0",
"guacamole-common-js": "^1.5.0",
"h3-js": "^4.5.0",
"hast-util-to-html": "^9.0.5",
"hastscript": "^9.0.1",
"knip": "^6.29.0",
"lex": "workspace:*",
"lit": "^3.3.3",
"lit-analyzer": "^2.0.3",
"lit-element": "^4.2.2",
"lit-html": "^3.3.3",
"maplibre-gl": "^5.24.0",
"md-front-matter": "^1.0.4",
"mermaid": "^11.16.1",
"node-domexception": "workspace:*",
"npm-run-all": "^4.1.5",
"pino": "^10.3.1",
"pino-pretty": "^13.1.3",
"playwright": "catalog:",
"pmtiles": "^4.4.1",
"prettier": "catalog:",
"prettier-plugin-packagejson": "catalog:",
"pseudolocale": "^2.2.0",
"rapidoc": "^9.3.8",
"rehype-highlight": "^7.0.2",
"rehype-parse": "^9.0.1",
"rehype-stringify": "^10.0.1",
"remark-directive": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"remark-rehype": "^11.1.2",
"storybook": "^10.5.10",
"style-mod": "^4.1.3",
"stylelint": "^17.14.1",
"trusted-types": "^2.0.0",
"ts-pattern": "^5.9.0",
"turnstile-types": "^1.2.3",
"type-fest": "^5.8.0",
"typescript": "catalog:",
"typescript-eslint": "catalog:",
"unist-util-visit": "^5.1.0",
"urlpattern-polyfill": "^10.1.0",
"vite": "catalog:",
"vitest": "catalog:",
"webcomponent-qr-code": "^2.0.0",
"wireit": "^0.14.13",
"yaml": "^2.9.0"
},
"optionalDependencies": {
"@esbuild/darwin-arm64": "^0.28.1",
"@esbuild/linux-arm64": "^0.28.1",
"@esbuild/linux-x64": "^0.28.1",
"@goauthentik/prettier-config-dev": "link:../packages/prettier-config",
"@rollup/rollup-darwin-arm64": "^4.62.4",
"@rollup/rollup-linux-arm64-gnu": "^4.62.4",
"@rollup/rollup-linux-x64-gnu": "^4.62.4"
},
"wireit": {
"build": {
"command": "${NODE_RUNNER} scripts/build-web.mjs",
"dependencies": [
"build-locales"
],
"files": [
"src/**/*.{css,jpg,png,ts,js,json}",
"!src/**/*.stories.ts",
"!src/**/*.tests.ts",
"!src/locales/*.ts",
"!src/locale-codes.ts",
"icons/**/*"
],
"output": [
"./dist/admin/**",
"./dist/user/**",
"./dist/flow/**",
"./dist/standalone/api-browser/**",
"./dist/standalone/loading/**",
"./dist/enterprise/**",
"./dist/poly-*.js",
"./dist/poly-*.js.map",
"./dist/styles/**"
],
"#comment": [
"`pnpm run build` and `pnpm run watch` are the most common ",
"commands you should be using when working on the front end",
"The files and output spec here expect you to use `pnpm run build --watch` ",
"instead of `pnpm run watch`. The former is more comprehensive, but ",
"the latter is faster."
],
"env": {
"NODE_RUNNER": {
"external": true,
"default": "node"
}
}
},
"build-proxy": {
"command": "node scripts/build-web.mjs --styles-only",
"dependencies": [
"build-locales"
]
},
"lint:components": {
"command": "lit-analyzer src"
},
"lint:types": {
"command": "tsc -p .",
"dependencies": [
"build-locales"
]
},
"lit-analyse": {
"command": "lit-analyzer src"
},
"locales:repair": {
"command": "prettier --write ./src/locale-codes.ts"
},
"precommit": {
"command": "prettier --write .",
"dependencies": [
"lint",
"lint:types",
"lint:components"
]
},
"storybook:build": {
"command": "storybook build",
"env": {
"NODE_OPTIONS": "--max_old_space_size=8192"
}
},
"tsc": {
"command": "tsgo -p .",
"dependencies": [
"build-locales"
]
}
},
"engines": {
"node": ">=24",
"pnpm": ">=11.20.0"
},
"devEngines": {
"runtime": {
"name": "node",
"onFail": "warn",
"version": ">=24"
}
},
"packageManager": "pnpm@11.20.0+sha512.9a6f330a95b66446ea088faf1521405a8a01f07fde7124cc9958dfed52d4bb436737e65b08f85f37b46fcba375092558ac51262b816844b22f63406ed166bfee",
"prettier": "./prettier.config.mjs"
}