diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c366d097..05bb16ce9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ on: - closed permissions: - contents: read + contents: read # Baseline for actions/checkout; elevated scopes are granted per-job concurrency: group: pages-preview-${{ github.event.pull_request.number }} @@ -22,13 +22,24 @@ jobs: build: runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: read # Only reads for checkout; gh-pages push and PR comment use the platform-mesh-publisher app token steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + persist-credentials: false + + - id: app-token + name: Generate platform-mesh-publisher app token + if: ${{ !github.event.pull_request.head.repo.fork }} # Secrets are unavailable on fork PRs; preview deploy below is likewise skipped + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: "1415820" # platform-mesh-publisher + private-key: ${{ secrets.PM_PUBLISHER_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: 24 cache: npm @@ -49,4 +60,5 @@ jobs: - uses: rossjrw/pr-preview-action@ffa7509e91a3ec8dfc2e5536c4d5c1acdf7a6de9 # v1 if: ${{ !github.event.pull_request.head.repo.fork }} with: + token: ${{ steps.app-token.outputs.token }} source-dir: .vitepress/dist diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 820f2d1f3..3b060a95f 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -11,9 +11,9 @@ permissions: jobs: scorecard: - uses: platform-mesh/.github/.github/workflows/job-ossf-scorecard.yml@068efd5c6c7a6d0c4b28f5887de7ca156cb5f7b8 # main + uses: platform-mesh/.github/.github/workflows/job-ossf-scorecard.yml@ab6caea57060a3eba5fc58cadbb2aaa1b06da18a # main permissions: - security-events: write - id-token: write - contents: read - actions: read + security-events: write # Needed to upload Scorecard results to the GitHub Security tab + id-token: write # Needed for keyless publishing of Scorecard results + contents: read # Needed to read repository contents + actions: read # Needed to read GitHub Actions workflows diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 784a7a5f3..5263ea21c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: read # Baseline for actions/checkout; elevated scopes are granted per-job concurrency: group: pages-${{ github.ref_name }} @@ -18,15 +18,25 @@ jobs: build: runs-on: ubuntu-latest permissions: - contents: write + contents: read # Only reads for checkout; pushes to gh-pages use the platform-mesh-publisher app token steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + persist-credentials: false + + - id: app-token + name: Generate platform-mesh-publisher app token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: "1415820" # platform-mesh-publisher + private-key: ${{ secrets.PM_PUBLISHER_PRIVATE_KEY }} + permission-contents: write + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: 24 - cache: npm + cache: npm # zizmor: ignore[cache-poisoning] - id: configure uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6 @@ -34,9 +44,9 @@ jobs: - id: set-version name: Set documentation version run: | - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then echo "version=main" >> $GITHUB_OUTPUT - elif [[ "${{ github.ref }}" == refs/heads/release-* ]]; then + elif [[ "${GITHUB_REF}" == refs/heads/release-* ]]; then echo "version=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT else echo "version=" >> $GITHUB_OUTPUT @@ -48,18 +58,20 @@ jobs: DOCS_VERSION: ${{ steps.set-version.outputs.version }} PAGES_BASE: '' - - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4 + - uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4 if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-') }} with: + token: ${{ steps.app-token.outputs.token }} folder: .vitepress/dist branch: gh-pages target-folder: ${{ steps.set-version.outputs.version }} clean-exclude: pr-preview force: false - - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4 + - uses: JamesIves/github-pages-deploy-action@fa24774553152dd7873cd16ebd8d959b010c5445 # v4 if: ${{ github.ref == 'refs/heads/main' }} with: + token: ${{ steps.app-token.outputs.token }} folder: . branch: gh-pages target-folder: . diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 000000000..83291b25e --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,26 @@ +name: Zizmor +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '30 4 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + zizmor: + uses: platform-mesh/.github/.github/workflows/job-zizmor.yml@ab6caea57060a3eba5fc58cadbb2aaa1b06da18a # main + with: + persona: 'auditor' + permissions: + security-events: write # Needed to write to the GitHub Security tab + contents: read # Needed to read repository contents + actions: read # Needed to read GitHub Actions workflows diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 000000000..410b5cce4 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,8 @@ +# zizmor configuration for platform-mesh.github.io workflows. +# https://docs.zizmor.sh/configuration/ +rules: + # Repo convention: jobs are identified by their key (e.g. `build`), not a + # separate display name. Adding `name:` to every job would fight the + # established style across the workflows here. + anonymous-definition: + disable: true diff --git a/.vitepress/config.mts b/.vitepress/config.mts index 85390bc77..4b492d3af 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -68,7 +68,10 @@ export default withMermaid({ ) }, ] - } + }, + optimizeDeps: { + include: ['mermaid'], + }, }, @@ -121,6 +124,7 @@ export default withMermaid({ items: [ { text: 'Set up Platform Mesh locally', link: '/how-to-guides/set-up-platform-mesh-locally' }, { text: 'Set up remote deployment', link: '/how-to-guides/set-up-remote-deployment' }, + { text: 'Air-gapped deployment', link: '/how-to-guides/install-air-gapped' }, { text: 'Speed up local rebuilds', link: '/how-to-guides/speed-up-local-rebuilds' }, ] }, @@ -223,7 +227,15 @@ export default withMermaid({ { text: 'OpenFGA', link: '/reference/components/openfga' }, { text: 'rebac-authz-webhook', link: '/reference/components/rebac-authz-webhook' }, { text: 'Kubernetes GraphQL gateway', link: '/reference/components/kubernetes-graphql-gateway' }, - { text: 'Portal', link: '/reference/components/portal' }, + { + text: 'Portal', + link: '/reference/components/portal', + collapsed: false, + items: [ + { text: 'Portal UI library', link: '/reference/components/portal/portal-ui-lib' }, + { text: 'Portal server library', link: '/reference/components/portal/portal-server-lib' }, + ], + }, { text: 'Marketplace', link: '/reference/components/marketplace' }, { text: 'virtual-workspaces', link: '/reference/components/virtual-workspaces' }, { text: 'Observability', link: '/reference/components/observability' }, @@ -244,6 +256,7 @@ export default withMermaid({ { text: 'IAM Store resource', link: '/reference/resources/iamstore-resource' }, { text: 'ContentConfiguration', link: '/reference/resources/content-configuration' }, { text: 'Metadata catalog', link: '/reference/resources/metadata-catalog' }, + { text: 'ProviderPermissions', link: '/reference/resources/provider-permissions-resource' }, ] }, { diff --git a/.vitepress/theme/components/VersionSelector.vue b/.vitepress/theme/components/VersionSelector.vue index 29b4dce0c..7fc816b4f 100644 --- a/.vitepress/theme/components/VersionSelector.vue +++ b/.vitepress/theme/components/VersionSelector.vue @@ -29,6 +29,7 @@ interface Version { // Define available versions - update this list when adding new versions const versions: Version[] = [ { name: 'main', label: 'main (latest)' }, + { name: 'release-0.5', label: 'v0.5' }, { name: 'release-0.4', label: 'v0.4' }, { name: 'release-0.3', label: 'v0.3' }, { name: 'release-0.2', label: 'v0.2' }, diff --git a/CODEOWNERS b/CODEOWNERS index 7470d17eb..fb79e1278 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @platform-mesh/kube +* @platform-mesh/go-maintainers @platform-mesh/node-maintainers diff --git a/community/talks.md b/community/talks.md index 90dfbeb47..a90b3ce20 100644 --- a/community/talks.md +++ b/community/talks.md @@ -8,33 +8,43 @@ This page lists Platform Mesh talks — upcoming conference sessions and recordi ## Upcoming -### Polymorphic interfaces in kcp: The three vendor problem +### Scaling Kube-Apiserver to Thousands of Tenants – Lessons Learned From kcp -[KCD Helsinki 2026](https://community2.cncf.io/events/details/cncf-kcd-helsinki-presents-kubernetes-community-days-helsinki-2026/) — May 20, 2026. +[ContainerDays Hamburg 2026](https://www.containerdays.io/containerdays-hamburg-2026/) — September 2–4, 2026. -### Platform Mesh: Breaking API Lock-In for True Multi-Cloud Service Portability +## 2026 -[ContainerDays Hamburg 2026](https://www.containerdays.io/containerdays-hamburg-2026/) — September 2–4, 2026. +### Kubernetes Plane Aerodynamics: Breaking the Architectural Sound Barrier -## Recordings +[KubeCon + CloudNativeCon India 2026](https://events.linuxfoundation.org/kubecon-cloudnativecon-india/) — Mumbai, June 2026. -### Platform Mesh: Breaking API Lock-In for True Multi-Cloud Service Portability +[Watch on YouTube](https://youtu.be/oh24ueXj8cc) -[KubeCon + CloudNativeCon Europe 2026](https://kccnceu2026.sched.com/) — Amsterdam, March 2026. +### Polymorphic interfaces in kcp: The three vendor problem -[Watch on YouTube](https://www.youtube.com/watch?v=43X0_U3cc-Y) +[KCD Helsinki 2026](https://community2.cncf.io/events/details/cncf-kcd-helsinki-presents-kubernetes-community-days-helsinki-2026/) — Helsinki, May 2026. + +No recording available, check out Cloud Native Suisse Romande 2025 talk. ### Sovereignty = func(Ecosystems, Interoperability) Platform Mesh and [OCM](https://ocm.software/) in the context of sovereignty. -[ALASCA Tech-Talk #35](https://alasca.cloud/en/alasca-tech-talks/). +[ALASCA Tech-Talk #35](https://alasca.cloud/en/alasca-tech-talks/) — Online, April 2026. [Watch on YouTube](https://www.youtube.com/watch?v=hzkrbW_J7U0) +### Platform Mesh: Breaking API Lock-In for True Multi-Cloud Service Portability + +[KubeCon + CloudNativeCon Europe 2026](https://kccnceu2026.sched.com/) — Amsterdam, March 2026. + +[Watch on YouTube](https://www.youtube.com/watch?v=43X0_U3cc-Y) + +## 2025 + ### Polymorphic interfaces in kcp: The three vendor problem -[Cloud Native Suisse Romande](https://community.cncf.io/cloud-native-suisse-romande/). +[Cloud Native Suisse Romande 2025](https://community.cncf.io/cloud-native-suisse-romande/) — Geneva, December 2025. [Watch on YouTube](https://www.youtube.com/watch?v=AG9-DdW32xg) @@ -43,3 +53,15 @@ Platform Mesh and [OCM](https://ocm.software/) in the context of sovereignty. [ContainerDays Conference 2025](https://www.containerdays.io/containerdays-conference-2025/) — Hamburg, September 2025. [Watch on YouTube](https://www.youtube.com/watch?v=8GFDj_-scSQ) + +### Building Europe's Cloud Future: NeoNephos' Platform Mesh + +[Open Source Summit Europe 2025](https://events.linuxfoundation.org/archive/2025/open-source-summit-europe/) — Amsterdam, August 2025. + +[Watch on YouTube](https://youtu.be/k7U2KT-rw7o) + +### NeoNephos' OpenMFP and Platform Mesh: Building Composable Enterprise Arcitectures + +[Open Source Summit Europe 2025](https://events.linuxfoundation.org/archive/2025/open-source-summit-europe/) — Amsterdam, August 2025. + +[Watch on YouTube](https://youtu.be/vpDGQgCaLt8) diff --git a/how-to-guides/index.md b/how-to-guides/index.md index fbc1825eb..093d9a7ec 100644 --- a/how-to-guides/index.md +++ b/how-to-guides/index.md @@ -6,6 +6,7 @@ How-to guides are task-focused. Use them when you already know what you want to - [Set up Platform Mesh locally](./set-up-platform-mesh-locally.md) - [Set up remote deployment](./set-up-remote-deployment.md) +- [Air-gapped deployment](./install-air-gapped.md) - [Speed up local rebuilds](./speed-up-local-rebuilds.md) ## Platform operators diff --git a/how-to-guides/install-air-gapped.md b/how-to-guides/install-air-gapped.md new file mode 100644 index 000000000..5f6c9c0e2 --- /dev/null +++ b/how-to-guides/install-air-gapped.md @@ -0,0 +1,331 @@ +--- +title: Air-gapped Platform Mesh deployment +personas: [platform-owner] +--- + +# Air-gapped Platform Mesh deployment + +Install Platform Mesh in an environment that cannot reach public container registries. + +You copy the whole product into your own registry once, using a single command. Then you +tell the cluster to use that registry. From there, installation works exactly like a normal +install: Platform Mesh rewrites every image reference it manages so nothing reaches out to +the internet. + +::: warning Development preview +This is verified on Kind against a published release, but it is not yet guarded by a +release gate. Expect it to work; do not yet expect it to keep working without checking. +::: + +## How it works + +Platform Mesh ships as an [OCM](https://ocm.software) component: essentially a manifest +listing every chart and every image that belongs to a release. + +Running `ocm transfer` copies that component, and all its images, into your registry. As it +copies, it rewrites the addresses inside the manifest to point at your registry instead of +the public one. + +Later, when the operator installs a chart, it does not use the chart's default image +address. Instead it reads the address from the transferred manifest, and writes that into +the Helm values. + +That is the whole trick, and it has a pleasant consequence: there is no separate air-gap +mode. The same configuration works either way. Point it at a public registry and the +injected values happen to match the chart defaults. Point it at your own registry and +everything comes from there instead. + +## Before you start + +You need: + +- **OCM CLI v1**, version 0.24.0 or newer. This matters: not the v2 CLI. Releases are built + with v1 tooling, and the two generations handle uploads differently, so mixing them + against the same registry causes problems. +- **A registry** that the target cluster can reach, with credentials that can both push and + pull. +- **Platform Mesh operator v0.83.9 or newer.** Older versions inject only the image tag and + leave the registry pointing at the public default, so the transfer has no effect. + +::: warning Use the charts from the release +Third-party charts are fine to use. openfga, cert-manager, Traefik, etcd-druid and the +OpenTelemetry operator are all upstream charts, and all of them get localized correctly. +What actually matters is not who wrote the chart, but whether the release knows how to +address its images: which values field holds the address, and whether that field expects a +separate registry or a full host-qualified repository path. + +That knowledge is tied to one exact chart version. If you install a different version than +the one in the release, or a fork, or a copy you patched yourself, the values field may have +moved, and the image injection lands nowhere. Nothing will warn you about this: the release +installs, the pods start, and they quietly pull from the chart's own public defaults +instead. +::: + +## 1. Copy the release into your registry + +On a machine with internet access, pull the release into a transport archive: + +```bash +ocm transfer componentversion \ + --recursive --copy-resources \ + ghcr.io/platform-mesh//github.com/platform-mesh/platform-mesh: \ + ./platform-mesh-.ctf +``` + +Both flags matter here. `--recursive` follows the references to every component the release +is built from. `--copy-resources` puts the actual images into the archive, instead of just +leaving pointers to where they currently live. + +Carry the archive across the gap, as a directory or a tar, and push it into your +registry: + +```bash +ocm transfer componentversion \ + ctf::./platform-mesh-.ctf//github.com/platform-mesh/platform-mesh: \ + registry.internal/platform-mesh +``` + +Then check that the images really arrived as images: + +```bash +ocm get componentversions -r registry.internal/platform-mesh//github.com/platform-mesh/platform-mesh: -o yaml \ + | grep -A2 'type: ociImage' +``` + +Each entry should say `type: ociArtifact` and point at your registry. If you see +`localBlob` instead, that image was carried across the gap but never unpacked into the +registry. The operator cannot use it, and the corresponding `Resource` will stay stuck in a +not-ready state. + +## 2. Tell the cluster which registry to use + +The transfer changed the addresses *inside the manifest*. It did not tell your cluster +where to find the manifest in the first place. That is what the `Repository` object does: + +```yaml +apiVersion: delivery.ocm.software/v1alpha1 +kind: Repository +metadata: + name: platform-mesh + namespace: platform-mesh-system +spec: + interval: 15m + repositorySpec: + type: OCIRegistry + baseUrl: registry.internal + subPath: platform-mesh +``` + +::: tip Do not leave the interval at one minute +A typical installation has around sixty `Resource` objects, and every one of them resolves +against this repository. At a one-minute interval, that adds up to a steady stream of +requests for something that only actually changes when you transfer a new release. A +self-hosted Harbor will start rate-limiting you well before that. + +Fifteen minutes is a reasonable starting point. There is no benefit to a short interval +here: a new release is picked up as soon as you change the version, not when the repository +happens to poll. +::: + +This object is not something extra you create for air-gapped installs. It is part of the +bootstrap manifests you apply anyway, next to Flux and the OCM controller. You are just +changing one field in it. + +You do have to create this object yourself, though; the operator cannot do it for you. That +is because the operator's own image also lives in this registry, so the registry address +has to be known before the operator can even start running. + +**This is the only change to how Platform Mesh itself resolves images.** Getting kubelet +to actually pull them is a separate step, covered next. + +## 3. Grant pull access + +Having a correct, localized image address is not the same thing as having permission to +pull it. Your registry almost certainly requires authentication, and neither the +`Repository` object above nor the operator itself grants any Pod that access. That +permission is strictly between your cluster and your registry; Platform Mesh does not +manage it. + +Two things need to happen, in every namespace that will run a localized image: + +1. **A pull secret exists, and every ServiceAccount that already exists references it.** + + ```bash + kubectl create secret docker-registry registry-auth \ + --docker-server=registry.internal \ + --docker-username= --docker-password= \ + -n + + kubectl patch serviceaccount default -n \ + -p '{"imagePullSecrets": [{"name": "registry-auth"}]}' + ``` + +2. **New ServiceAccounts get the same treatment automatically.** Most charts create their + own dedicated ServiceAccount as part of their install, and that install usually happens + well after you ran step 1 for that namespace. So patching only what exists today misses + everything a later `HelmRelease` still creates. A `MutatingAdmissionPolicy` fixes this + properly: instead of patching at one point in time, it attaches the pull secret + automatically, every time a ServiceAccount is created: + + ```yaml + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: MutatingAdmissionPolicy + metadata: + name: inject-registry-pull-secret + spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: [""] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["serviceaccounts"] + matchConditions: + - name: not-already-set + expression: '!has(object.imagePullSecrets) || !object.imagePullSecrets.exists(s, s.name == "registry-auth")' + mutations: + - patchType: JSONPatch + jsonPatch: + expression: | + [ + JSONPatch{ + op: "add", + path: "/imagePullSecrets", + value: (has(object.imagePullSecrets) ? object.imagePullSecrets : []) + + [{"name": "registry-auth"}] + } + ] + --- + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: MutatingAdmissionPolicyBinding + metadata: + name: inject-registry-pull-secret + spec: + policyName: inject-registry-pull-secret + ``` + + One detail worth noting: the patch type is `JSONPatch`, not `ApplyConfiguration`. In the + OpenAPI schema, `imagePullSecrets` is an atomic list rather than a mergeable one, so a + server-side-apply patch gets rejected outright whenever the create request already sets + a value for it, even an empty `[]`. Some charts' own ServiceAccount templates do exactly + that. + +::: tip Flux needs its own credential separately +`OCIRepository.spec.secretRef` is resolved separately, by source-controller, in the +`OCIRepository`'s own namespace. This is independent of the ServiceAccount-based pulls that +kubelet does, described above. A chart's Helm-sourced OCI pull and its Pods' image pulls +both read from the same registry, but they authenticate through completely separate +mechanisms. So set `secretRef` on every `OCIRepository` that points at your registry too. +::: + +## 4. Install + +Install as usual. For each image, the operator creates a `Resource` object, looks up its +address in the transferred manifest, and writes it into the Helm values before the chart +is applied. + +### Declare images in the profile, not in values + +This is the part people get wrong. An image is localized only if the profile declares it +under `imageResources`: + +```yaml +services: + openfga: + imageResources: + - name: openfga-image + annotations: + repo: oci + artifact: image + for: openfga + image-ref: combined +``` + +Setting the image under `values` instead localizes nothing: + +```yaml +services: + openfga: + values: + image: + repository: openfga/openfga # stays exactly this, gap or no gap + tag: v1.14.0 +``` + +Neither case reports an error. Without an `imageResources` entry no `Resource` object is +created, so there is nothing to resolve and the chart uses whatever the values say. + +If you set both, the injection wins and your value is quietly ignored. Our own test profile +pinned `kcp.image.tag: v0.32.0` under values while also declaring the image resource, and +the pods came up with `v0.32.2` from the component. Worth knowing before you spend an hour +wondering why a pinned version has no effect. + +## What you have to mirror yourself + +Two groups of images are outside the operator's reach. + +**The bootstrap layer** runs before the operator exists, so it cannot be localized by it: +the six Flux controllers, the OCM controller, and kro. + +**Your Kubernetes distribution**: API server, controller manager, scheduler, proxy, +CoreDNS, etcd, your CNI, your storage provisioner. These have nothing to do with Platform +Mesh. + +Everything else, including the operator's own image, is handled for you. + +## Check that it worked + +**Did every image get an address?** Empty columns mean nothing was injected: + +```bash +kubectl get resources.delivery.ocm.software -A \ + -o custom-columns='NAME:.metadata.name,TAG:.status.additional.tag,REPO:.status.additional.repository' +``` + +**Is anything still pulling from outside?** Bootstrap and distribution images are expected +to show up here; anything else means a gap in your mirror: + +```bash +kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' \ + | tr ' ' '\n' | sort -u | grep -v registry.internal +``` + +**Did anything fail to pull?** + +```bash +kubectl get pods -A --field-selector=status.phase!=Running +``` + +::: tip These checks only mean something with the gap closed +While the cluster still has internet access, a misconfigured image will happily pull from +its public default instead of failing. Every check above can pass even though the +installation is not actually air-gap capable. Run them once with egress blocked, or they do +not prove anything. +::: + +## When something goes wrong + +**A pod pulls from Docker Hub, even though you never configured Docker Hub anywhere.** + +This looks stranger than it actually is. Some charts expect the registry to be baked into +`image.repository` itself, for example `ghcr.io/kcp-dev/kcp-operator`, rather than having a +separate `registry` field. If the operator writes only the repository, without the host, +the reference is no longer fully qualified, so the container runtime fills in the missing +piece for you. On containerd and Docker, that default is `docker.io`, which is why a +missing host shows up as a Docker Hub pull. On CRI-O, the behavior depends on +`unqualified-search-registries`, and the pull may just fail outright instead. + +Images like this need the `image-ref: combined` annotation, which keeps the registry folded +into the repository string. This affects openfga, kcp-operator, init-agent, etcd-druid and +the OpenTelemetry operator. + +**A `Resource` stays not ready, with an error like `resource with identity … not found`.** + +This means the release you transferred does not declare that image at all. Check that you +transferred the right component version. + +**A service pulls from the public registry, and nothing reports an error.** + +This service simply has no image declared for it, so no `Resource` was created, and the +chart's own default just applies quietly. Nothing fails, nothing warns you, and you will +not notice until the gap is actually closed. The second check above is what catches these. diff --git a/how-to-guides/set-up-platform-mesh-locally.md b/how-to-guides/set-up-platform-mesh-locally.md index 6588cadc4..fed0733a9 100644 --- a/how-to-guides/set-up-platform-mesh-locally.md +++ b/how-to-guides/set-up-platform-mesh-locally.md @@ -45,7 +45,7 @@ Set `KIND_EXPERIMENTAL_PROVIDER=podman` before running the setup. ```bash git clone https://github.com/platform-mesh/helm-charts.git cd helm-charts -git checkout 0.3.0 +git checkout 0.4.0 cd local-setup ``` diff --git a/index.html b/index.html index 17ba59ab7..2ee17c2be 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ Platform Mesh - + diff --git a/llms.txt b/llms.txt index 00bb7d334..605e25726 100644 --- a/llms.txt +++ b/llms.txt @@ -74,6 +74,8 @@ Both paths require a Kubernetes operator that reconciles the service's resources - [rebac-authz-webhook](reference/components/rebac-authz-webhook.md): kcp authorization webhook backed by OpenFGA. - [Kubernetes GraphQL Gateway](reference/components/kubernetes-graphql-gateway.md): GraphQL interface for kcp resources. - [Portal](reference/components/portal.md): Consumer-facing web UI. +- [Portal UI library](reference/components/portal/portal-ui-lib.md): Angular library with Platform Mesh portal options and generic UI web components. +- [Portal server library](reference/components/portal/portal-server-lib.md): NestJS library with Platform Mesh portal backend providers. - [Marketplace](reference/components/marketplace.md): Service discovery and binding for consumers. - [api-syncagent](reference/components/api-syncagent.md): CRD-based provider integration path. - [multi-cluster-runtime](reference/components/multi-cluster-runtime.md): Custom controller provider integration path. diff --git a/package-lock.json b/package-lock.json index 3b1a931bc..29c08ac6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,16 +14,16 @@ } }, "node_modules/@algolia/abtesting": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.19.0.tgz", - "integrity": "sha512-Lhnez3hhXHk25lfxLAMxvkP4fmN3+1RgADhD2ssMDBYuAsDVReeyP+3SGRx+ntq8ijMrLqUyfvO72TB6jsTteQ==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.23.0.tgz", + "integrity": "sha512-j45MBISstltys9QyQ4xf6quRiN1g7vMuwQL9VM4dx8YuRZvCQ173b9royZAx6iAbRX3IB1VnG1z//NuwyQ8jpQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" @@ -79,41 +79,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.53.0.tgz", - "integrity": "sha512-0ZjA5Hcmaoz5Lj6OG0zhfIyeqzJZnLW2CRJA1W17UwMFGRtZAJ9yJKRvPEDA6gkpsIoQxORTSW6sWFiuYncPNQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.57.0.tgz", + "integrity": "sha512-JVFFujiZUCguk5tz3LZr4fTQxqpIrj4/Jw3SI7kMljSqtfLxYn/s/TWH0J2s4iNfsDpxPhgFGMotCpmDI4kZ8w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.53.0.tgz", - "integrity": "sha512-kWNodP75iiEaOtemC9F/hlxNBG5E2QUjN1BusnE6m2b4l7Qh/BUO3fGCVsmKJI65VO4VKGGmT43ICvHtTcJ2JQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.57.0.tgz", + "integrity": "sha512-6KqECK4ED3JJQEoDrQWnGPQzElA828xAD4qK5ceawNNyP/LcSvzAoLHjFkoTPksZ/kxj6VUtCRH+IHZesLltng==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.53.0.tgz", - "integrity": "sha512-YPN45TXD9Wrse185t/Ta7nktZsqpv97oOjCzp2sblHnCL6rBc9TDeJAg1IGl2UpdwnSD05Zu/5wLB4watOUMyg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.57.0.tgz", + "integrity": "sha512-uqpGF3oXYsoCbQq5d7BzNrNTfIfuvJyGP1CKvSW27T9boUg7KOwyxsAw1AX0a3jSW2HrYEJ/NN+Z4MiGivbpeQ==", "dev": true, "license": "MIT", "engines": { @@ -121,151 +121,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.53.0.tgz", - "integrity": "sha512-qAcYTDJE6m924FDDUQvdD6vh7DYaqOeSpFS74IP37/JRV0v4cGBauyxTF2WzDnokUylQDbqreoFIJZfg0Fitmw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.57.0.tgz", + "integrity": "sha512-u5NboJVJXDEFplvNnqqX4CxkXPYysjJRj47hOSh9329H8kG5gFLKJBIiS5utMQ+GZm8xQl3Te7NInDk6elEADQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.53.0.tgz", - "integrity": "sha512-fQaY+DkSJOpuUVUe8MQTwrdiKAqkJGhpDarB08duBn/sUv7Bkib6MDRQauCcWTWTe4HIW+EbwQP9R4kci1V/Yw==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.57.0.tgz", + "integrity": "sha512-uzc0b2LmHAK9/QID4xeo35OG84AkZl4YewkCqawqAOGLjT2eZpM/OZx45ESygMHG30Ws+ZTSdluPtMJcUnrbWQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.53.0.tgz", - "integrity": "sha512-o72tsiEZGfeS/dxL9IADfzcZWGEwKDEe5CvtrBuT//3JR+SHuTtHRI2ZTf7D7bcKagcbojvO8hnkHdfoakSlYg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.57.0.tgz", + "integrity": "sha512-dIAhnM6ue/ssa5PjgNfu4g8A4yTojl9ZOUzZU3wIaIKRerL2R/3Emuf9n/D6ICXXP167KC6XCeC7nliSw7cuSw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.53.0.tgz", - "integrity": "sha512-Ds16IyPm/dNJPCU8OzApo2gwGrgWT5BYHhE3NFwZbpCveqyvPDB9sZDDkJ5DsdOGT2aC+R3i0/M1OVXF2qdgPg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.57.0.tgz", + "integrity": "sha512-2TTPTTKSJmCptvhCm4Xf3bBYMqZni+Pgc2hVdqc4l9wsBpSJNVTVIKpnd10OubUgkGcmppVDj1XQqYaf6EnPSQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.53.0.tgz", - "integrity": "sha512-oNbT6z4NwD8Pou9VPINGlN/tlG1afESh2EbxqnP6rwl95xKVD/Zlciis1PpNeO/9U/rrajc1+7DcfKi03tX1KQ==", + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.57.0.tgz", + "integrity": "sha512-W4JseHKt+pzOxlFV+T3MWEG0h4Z2Se5zjoXUD0ewlw8aOWMG/yjRdopUdLQsXULepB/My2tDuZjkwk2sMfsUrQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.53.0.tgz", - "integrity": "sha512-G+KZb/yd+qAOFn/cEvTGeLxQm8aP3a0od50l3z/ylccY+/o4YG3TNcjU1tFQHW4mXC137GPyR7W70R0kRQDLnA==", + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.57.0.tgz", + "integrity": "sha512-BrxJVE0/eLinEPICCD7BKN/2xnt0nkjge70u8zzE2ISP3fuB3tjLgcwpanUycvlHBFLI4gK0l5ol54p6IYuR/Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.53.0.tgz", - "integrity": "sha512-6aVfYd55Un6IUgPLbo84WfgFZlS3L0vA1ttzXL5vahHewUJ8jYgd89TzlWRTeej7w70mb9RWsVlFYGmJ/diQww==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.57.0.tgz", + "integrity": "sha512-Gc29jkeiLKlVfHvyrIgyUHHE+aYTdXEeLfK42rjr5/1TTVsYwUJz0XkvoIBIqfMjcDg6gXeHb1jTUZ0H+SYIlQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/client-common": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.53.0.tgz", - "integrity": "sha512-ke27DqgzCOlt+RbeEdCxtXxMQOnAOi8ujr2wid0DmDKzR95Kw/f9sBsuhBxtjevCqJRJszfRTLY0B1pbO6IhkA==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.57.0.tgz", + "integrity": "sha512-PIPnPN7MP3fp2VAi01BVXhCWmD366ZB2Hkq5TlYKtThd4KxUtMmaaNDpFgVCTXtSIqWVZLJntOHRvxg/sIPd8Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0" + "@algolia/client-common": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.53.0.tgz", - "integrity": "sha512-GngiOqt2Gq4oLno6yXQVj9om+qSO9SWAoduoTOEg79dKZ62brB8OOIvSJG/vDNoanYi6a7Al9uDZwXvi+bcVTg==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.57.0.tgz", + "integrity": "sha512-AX3RlOudXMdTwtwUqdAf5hAVLvXfOZZH1FZh6ALDdrhVLT0TtAIe48N6nYcWcTnwoTxK/wDIQqZ19IMjK8zJAA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0" + "@algolia/client-common": "5.57.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.53.0.tgz", - "integrity": "sha512-6mF9LZMUk0QqWvrnxkxBqhswwz6Xfiwy6/gmTzL5HrlhdVG3ITAqGV2k3XmVThP1h0Ulc3VQwiNCD7/Nr4JNlQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.57.0.tgz", + "integrity": "sha512-cWZc1dKb7wy9/wPpwMtL1y89gK2G7y2A47Coa7zwf1ydtIeJm4+S+XxoQ2b/ZRiQnrC1YHavLjYUPDCdnT7Khg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.53.0" + "@algolia/client-common": "5.57.0" }, "engines": { "node": ">= 14.0.0" @@ -307,13 +307,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -323,9 +323,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "dev": true, "license": "MIT", "dependencies": { @@ -404,9 +404,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -417,13 +417,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -434,13 +434,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -451,13 +451,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -468,13 +468,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -485,13 +485,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -502,13 +502,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -519,13 +519,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -536,13 +536,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -553,13 +553,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -570,13 +570,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -587,13 +587,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -604,13 +604,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -621,13 +621,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -638,13 +638,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -655,13 +655,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -672,13 +672,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -689,13 +689,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -706,13 +723,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -723,13 +757,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -740,13 +791,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -757,13 +808,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -774,13 +825,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -791,13 +842,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.85", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.85.tgz", - "integrity": "sha512-Hp5LXvd3LRk+e+1558wtonA7c1Z0/Phmi7xCqpgtb8bs8cuyGnP34GDbt5uhhUXxKlzacnnhAcXgcDxe9bUa1w==", + "version": "1.2.93", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.93.tgz", + "integrity": "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -812,9 +863,9 @@ "license": "MIT" }, "node_modules/@iconify/utils": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", - "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.4.tgz", + "integrity": "sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==", "dev": true, "license": "MIT", "peer": true, @@ -857,20 +908,40 @@ "optional": true }, "node_modules/@mermaid-js/parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", - "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.1.tgz", + "integrity": "sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@chevrotain/types": "~11.1.1" + "@chevrotain/types": "~11.1.2" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", - "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.5.tgz", + "integrity": "sha512-jfkGfTwhQpsiSckPF8r9bU3pn3vyd72NlWaO+TgEO6WPSDnUhXzrNYCHBMOYj0ACaUgjm6eERLF+XV9a6RstoA==", "cpu": [ "arm" ], @@ -882,9 +953,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", - "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.5.tgz", + "integrity": "sha512-oGVqyQlxnrz9/ty89oHpU857VUHEl5/Xu4R2lS+aivCTrNnSsbiENzTnNaBsjxH0CNWGPhzHArOLFwo+oKXveA==", "cpu": [ "arm64" ], @@ -896,9 +967,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", - "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.5.tgz", + "integrity": "sha512-bW7B8xMEq8n99Q3ieEcPRGuphurdZAaFzQc9Efyyw3FL6DZO6pMy9xhdN+kBoD7Sy05xNXSr4OyPPnpkYriS/A==", "cpu": [ "arm64" ], @@ -910,9 +981,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", - "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.5.tgz", + "integrity": "sha512-YSwBS86QeHOGlrxJ1PSOIZSkzRL/JmKeunhc+lV6M1a6En8QuVCD/T/qIA0J4Gd2Y86RIOBYrLcOUtqGh9+/1w==", "cpu": [ "x64" ], @@ -924,9 +995,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", - "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.5.tgz", + "integrity": "sha512-2fST8lILgl7cKbme/1KDdPCmbXbG+gqoV3bHp19L0ypX/3akYMBVdOunPleRCwonoLnXOZ/0F+Mt/v8POFmfcQ==", "cpu": [ "arm64" ], @@ -938,9 +1009,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", - "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.5.tgz", + "integrity": "sha512-cpIxQCP9J+EVad0a6LO1kY3ZGODlk80VlI+2I96B8xMcdHZ4pLVhfQ49JFpYqjPF91FFkQWftf57YlDcTiw9yQ==", "cpu": [ "x64" ], @@ -952,9 +1023,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", - "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.5.tgz", + "integrity": "sha512-r9fGh3eFs3e/udWh5ZjXQtxiYK/xoFxQaYR/cELxac/Udkl5Th+IsFm0CX3Kl9hmUH/we7EoMpjJgeQNnE0+IA==", "cpu": [ "arm" ], @@ -969,9 +1040,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", - "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.5.tgz", + "integrity": "sha512-xdvFdp7OM6KLJviJT2g/YuRSUjnZgGHk4RNgwIbN7X6cPugOucV60DdHXWzsBVCUdrGb6qSXnJQrrAKMmQuj3Q==", "cpu": [ "arm" ], @@ -986,9 +1057,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", - "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.5.tgz", + "integrity": "sha512-rRqILAndyzHzP7T9NFQrq+4HFWNhqkqkKur7eiBpfLmz01PO0JKx5Vchu3YllE4YXI/Ftgq/szrDWg5GJ0mI8g==", "cpu": [ "arm64" ], @@ -1003,9 +1074,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", - "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.5.tgz", + "integrity": "sha512-Gf4X3qVMucayUvux6aXXPgXovocSFUC0rrffDuPI/S2nHhNMhjcZxsrAFYCOF350PRreW1XwzFj3CT/3bKsWCw==", "cpu": [ "arm64" ], @@ -1020,9 +1091,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", - "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.5.tgz", + "integrity": "sha512-+s5qA0TNM0qm8PK/a5gt/1Hpx+NV08uSuCncvhziIlQzT6AEV2fnUQo7eBtFTFO0nA9scauvoR2HusfXmQnO4w==", "cpu": [ "loong64" ], @@ -1037,9 +1108,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", - "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.5.tgz", + "integrity": "sha512-ybb6QvWwWJCbBWqERpc8K3pYVGIrXlG8MEQ8IIuJY6Y9KdHQxoFoNyfkAOtKn1VHu3KuLidXvwrvGR1mEjeWCw==", "cpu": [ "loong64" ], @@ -1054,9 +1125,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", - "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.5.tgz", + "integrity": "sha512-nZb1DtnOyhCmYvsC8A2CwOkopVg+IS1+fPUa7rMOAXtNw5+lLCLLPqd6XAiNrGtoQKsbvIBOwsHnBH/3wnb4HQ==", "cpu": [ "ppc64" ], @@ -1071,9 +1142,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", - "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.5.tgz", + "integrity": "sha512-yMbj63Sp89ryrXLWyz+sy+fYD2HpOnMCLGbe4Oa1smclFSUukdtD/BgdiHaAetJNb74URD8U4hM+qG5KVzMEkg==", "cpu": [ "ppc64" ], @@ -1088,9 +1159,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", - "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.5.tgz", + "integrity": "sha512-mhoan3OJw2kYV/e1jtIdmvUZgyBFeA6zGWsOswmR0Tg19TQbowZuR+JMLID6spbbBN7Zee2ejrgmy3+FxGrIdA==", "cpu": [ "riscv64" ], @@ -1105,9 +1176,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", - "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.5.tgz", + "integrity": "sha512-5ZTLmjWbb1VZdjuyhe83K/8QO0/h11midQCBP+X5OYn32ra7eOBoM0ZqtaY4nkgNsYgmdVhMYPoyVPTjUpHf3w==", "cpu": [ "riscv64" ], @@ -1122,9 +1193,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", - "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.5.tgz", + "integrity": "sha512-m53kG+br6PGxOTmgBEM2DHSDs9RVjsyEbUwjJPJGTFm1grWOG8EKJggDCTb60unD4Tjby8fi7/m9XfkEWasVWg==", "cpu": [ "s390x" ], @@ -1139,9 +1210,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", - "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.5.tgz", + "integrity": "sha512-6RHPJR1g/uvdYU8uXBnfq3nlqyZCP82Fr6NHgfGoaIeSh0YEqnX/x6uA9MmJJbnSH7swqX4F+CkGdUF+6doiQA==", "cpu": [ "x64" ], @@ -1156,9 +1227,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", - "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.5.tgz", + "integrity": "sha512-xs+OXQtEXgpXT0DmA5+U3qnRZHdCST/5HRQxS8wSPZTUZN/EMWeHuSIod32LQklTBZBV9DyfncKBQ8n5V3eFdw==", "cpu": [ "x64" ], @@ -1173,9 +1244,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", - "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.5.tgz", + "integrity": "sha512-e7hD+sl3s+mcLQDZ8pbudBVsdG6r5yN4w3LqG2TJ8sQHDpblWj5lrJs/3m01Cvlxbt4x13zu5thLjgypgtkYzw==", "cpu": [ "x64" ], @@ -1187,9 +1258,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", - "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.5.tgz", + "integrity": "sha512-GiyJaCf+WpMub/17aPcKk27QMl5W6f+KhdPTjlFOn5akH5Wa/DCM9Stdx5cDfmasyKB08MqpVQ1uJE2RkkpbXg==", "cpu": [ "arm64" ], @@ -1201,9 +1272,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", - "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.5.tgz", + "integrity": "sha512-+OQ8U2DdoEfXl8T4Fb18AjmEwbXMerKDKCL8yCPAYhKCEEKoul7rkbeGCBFCbAlaGaa7pmtRTpkAJM2LE/i5FA==", "cpu": [ "arm64" ], @@ -1215,9 +1286,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", - "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.5.tgz", + "integrity": "sha512-KanvAZrPKbDBFwrgiU9yEVpQoox9QPV1WZOXX7HudJQY+eSlu82CtWxDU8WtuRRvtN5EGkLczkd6Y6DTcvm9wA==", "cpu": [ "ia32" ], @@ -1229,9 +1300,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", - "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.5.tgz", + "integrity": "sha512-1aC3UEWTtRl3RK3VpDJ/Tqk1XI4SLTmXIthAq6wRWo8XiSXJNd+VprJM4/1P4+i6HIaFEFlVi9sTTziniD2tOQ==", "cpu": [ "x64" ], @@ -1243,9 +1314,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", - "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.5.tgz", + "integrity": "sha512-/gDJaRs4gl0NPIwqCz+6PkpmhhjRAD2j6P4rSNHBzUkO3naEx2mIU0pRle1vUNRQ7mE/+8OOeXLTv/J56FKiQg==", "cpu": [ "x64" ], @@ -1512,9 +1583,9 @@ "peer": true }, "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w==", "dev": true, "license": "MIT", "peer": true, @@ -1566,9 +1637,9 @@ "peer": true }, "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", "dev": true, "license": "MIT", "peer": true @@ -1601,9 +1672,9 @@ "peer": true }, "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", "dev": true, "license": "MIT", "peer": true, @@ -1674,9 +1745,9 @@ "peer": true }, "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", "dev": true, "license": "MIT", "dependencies": { @@ -1691,9 +1762,9 @@ "license": "MIT" }, "node_modules/@types/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-NoQ2yGlLWj4wpxMs+TYmRKk3thDrQ97agr7sFqfLsAlvoS8SNQuTrlObhFqG9iugdTtgOE9jpJ6FNM4ZGsa5xQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1742,9 +1813,9 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", - "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", "dev": true, "license": "ISC" }, @@ -1775,77 +1846,77 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", - "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz", + "integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.3", - "@vue/shared": "3.5.35", + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.41", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", - "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz", + "integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-core": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", - "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz", + "integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.3", - "@vue/compiler-core": "3.5.35", - "@vue/compiler-dom": "3.5.35", - "@vue/compiler-ssr": "3.5.35", - "@vue/shared": "3.5.35", + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.41", + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-ssr": "3.5.41", + "@vue/shared": "3.5.41", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.15", + "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", - "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz", + "integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-dom": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/devtools-api": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", - "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.10.tgz", + "integrity": "sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^7.7.9" + "@vue/devtools-kit": "^7.7.10" } }, "node_modules/@vue/devtools-kit": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", - "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz", + "integrity": "sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.7.9", + "@vue/devtools-shared": "^7.7.10", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", @@ -1855,9 +1926,9 @@ } }, "node_modules/@vue/devtools-shared": { - "version": "7.7.9", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", - "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "version": "7.7.10", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz", + "integrity": "sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1865,57 +1936,55 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", - "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz", + "integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.35" + "@vue/shared": "3.5.41" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", - "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.41.tgz", + "integrity": "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/reactivity": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", - "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz", + "integrity": "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.35", - "@vue/runtime-core": "3.5.35", - "@vue/shared": "3.5.35", + "@vue/reactivity": "3.5.41", + "@vue/runtime-core": "3.5.41", + "@vue/shared": "3.5.41", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", - "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.41.tgz", + "integrity": "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.35", - "@vue/shared": "3.5.35" - }, - "peerDependencies": { - "vue": "3.5.35" + "@vue/compiler-ssr": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/shared": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", - "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", + "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", "dev": true, "license": "MIT" }, @@ -2026,26 +2095,26 @@ } }, "node_modules/algoliasearch": { - "version": "5.53.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.53.0.tgz", - "integrity": "sha512-OGW1q6b91CRSSeiOnM8LxuR5NYJ2esvw66jUZ4IIvdv+ItNkx3pwLuyR+jaCdbGee4ov5WgUnyPryyh11xvByQ==", + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.57.0.tgz", + "integrity": "sha512-HpND7MBGctOAkd1GoQoDZCGoCpqNTS5NG1LuhElFet3RdLJkwnyTYZXZhXwtpAQPrI36fqQ3eT6KQrdKDTKu3A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/abtesting": "1.19.0", - "@algolia/client-abtesting": "5.53.0", - "@algolia/client-analytics": "5.53.0", - "@algolia/client-common": "5.53.0", - "@algolia/client-insights": "5.53.0", - "@algolia/client-personalization": "5.53.0", - "@algolia/client-query-suggestions": "5.53.0", - "@algolia/client-search": "5.53.0", - "@algolia/ingestion": "1.53.0", - "@algolia/monitoring": "1.53.0", - "@algolia/recommend": "5.53.0", - "@algolia/requester-browser-xhr": "5.53.0", - "@algolia/requester-fetch": "5.53.0", - "@algolia/requester-node-http": "5.53.0" + "@algolia/abtesting": "1.23.0", + "@algolia/client-abtesting": "5.57.0", + "@algolia/client-analytics": "5.57.0", + "@algolia/client-common": "5.57.0", + "@algolia/client-insights": "5.57.0", + "@algolia/client-personalization": "5.57.0", + "@algolia/client-query-suggestions": "5.57.0", + "@algolia/client-search": "5.57.0", + "@algolia/ingestion": "1.57.0", + "@algolia/monitoring": "1.57.0", + "@algolia/recommend": "5.57.0", + "@algolia/requester-browser-xhr": "5.57.0", + "@algolia/requester-fetch": "5.57.0", + "@algolia/requester-node-http": "5.57.0" }, "engines": { "node": ">= 14.0.0" @@ -2116,14 +2185,11 @@ } }, "node_modules/copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.1.0.tgz", + "integrity": "sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==", "dev": true, "license": "MIT", - "dependencies": { - "is-what": "^5.2.0" - }, "engines": { "node": ">=18" }, @@ -2149,9 +2215,9 @@ "license": "MIT" }, "node_modules/cytoscape": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", - "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", + "version": "3.34.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.1.tgz", + "integrity": "sha512-Lr0RvH9H75y9ar8h9Toy6u4lxRSCcxUq+hHcQ26sVWo6BnaQp1gwEZOYqwuYTZhyW7npyKnNLP8oJ2p1/3OZ7g==", "dev": true, "license": "MIT", "engines": { @@ -2696,9 +2762,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.21", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", - "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", "dev": true, "license": "MIT", "peer": true @@ -2738,9 +2804,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.8.tgz", - "integrity": "sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.14.tgz", + "integrity": "sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "peer": true, @@ -2769,21 +2835,23 @@ } }, "node_modules/es-toolkit": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.0.tgz", - "integrity": "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.51.0.tgz", + "integrity": "sha512-zC2lQGkM7QX+Gm6iM3+WIdZJzthsEd14LvRNJneSO2hzyz/zNBENR8+YXWo1cKxgPBtV6ksPYHELbcwBRzmdCw==", "dev": true, "license": "MIT", "peer": true, "workspaces": [ "docs", - "benchmarks" + "benchmarks", + "tests/types", + "tests/browser-compat" ] }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2791,32 +2859,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/estree-walker": { @@ -2826,6 +2897,35 @@ "dev": true, "license": "MIT" }, + "node_modules/fastdom": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.12.tgz", + "integrity": "sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "strictdom": "^1.0.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/focus-trap": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", @@ -2950,19 +3050,6 @@ "node": ">=12" } }, - "node_modules/is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/katex": { "version": "0.16.47", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", @@ -3079,28 +3166,29 @@ "license": "MIT" }, "node_modules/mermaid": { - "version": "11.15.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", - "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.17.0.tgz", + "integrity": "sha512-Jo9N377Wb4MSnHFPTbLi2SxFpsQl4eVHoxnW5U1Md9EazvgMp3s+4ohDxr81YNTgbn5Kj7HJ3yslrSJ52kwpbA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@braintree/sanitize-url": "^7.1.1", + "@braintree/sanitize-url": "^7.1.2", "@iconify/utils": "^3.0.2", - "@mermaid-js/parser": "^1.1.1", + "@mermaid-js/parser": "^1.2.1", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", - "cytoscape": "^3.33.1", + "cytoscape": "^3.34.0", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", - "dayjs": "^1.11.19", - "dompurify": "^3.3.1", + "dayjs": "^1.11.21", + "dompurify": "^3.3.3", "es-toolkit": "^1.45.1", - "katex": "^0.16.25", + "fastdom": "1.0.12", + "katex": "^0.16.47", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", @@ -3218,9 +3306,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -3257,9 +3345,9 @@ } }, "node_modules/package-manager-detector": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", - "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", + "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", "dev": true, "license": "MIT", "peer": true @@ -3286,6 +3374,19 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", @@ -3307,9 +3408,9 @@ } }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -3327,7 +3428,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3336,14 +3437,22 @@ } }, "node_modules/preact": { - "version": "10.29.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz", - "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==", + "version": "10.29.8", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.8.tgz", + "integrity": "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==", "dev": true, "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } } }, "node_modules/property-information": { @@ -3399,9 +3508,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", - "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "version": "4.62.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.5.tgz", + "integrity": "sha512-/tqMfgP7GPA3PHhCmuiS4vIjrSVhHLgY++i+dhbG462euyAj7FpM4D9uq1X3BgjlqRdpcOrYhcQtfiQLNc8tqw==", "dev": true, "license": "MIT", "dependencies": { @@ -3415,31 +3524,32 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.61.1", - "@rollup/rollup-android-arm64": "4.61.1", - "@rollup/rollup-darwin-arm64": "4.61.1", - "@rollup/rollup-darwin-x64": "4.61.1", - "@rollup/rollup-freebsd-arm64": "4.61.1", - "@rollup/rollup-freebsd-x64": "4.61.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", - "@rollup/rollup-linux-arm-musleabihf": "4.61.1", - "@rollup/rollup-linux-arm64-gnu": "4.61.1", - "@rollup/rollup-linux-arm64-musl": "4.61.1", - "@rollup/rollup-linux-loong64-gnu": "4.61.1", - "@rollup/rollup-linux-loong64-musl": "4.61.1", - "@rollup/rollup-linux-ppc64-gnu": "4.61.1", - "@rollup/rollup-linux-ppc64-musl": "4.61.1", - "@rollup/rollup-linux-riscv64-gnu": "4.61.1", - "@rollup/rollup-linux-riscv64-musl": "4.61.1", - "@rollup/rollup-linux-s390x-gnu": "4.61.1", - "@rollup/rollup-linux-x64-gnu": "4.61.1", - "@rollup/rollup-linux-x64-musl": "4.61.1", - "@rollup/rollup-openbsd-x64": "4.61.1", - "@rollup/rollup-openharmony-arm64": "4.61.1", - "@rollup/rollup-win32-arm64-msvc": "4.61.1", - "@rollup/rollup-win32-ia32-msvc": "4.61.1", - "@rollup/rollup-win32-x64-gnu": "4.61.1", - "@rollup/rollup-win32-x64-msvc": "4.61.1", + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.5", + "@rollup/rollup-android-arm64": "4.62.5", + "@rollup/rollup-darwin-arm64": "4.62.5", + "@rollup/rollup-darwin-x64": "4.62.5", + "@rollup/rollup-freebsd-arm64": "4.62.5", + "@rollup/rollup-freebsd-x64": "4.62.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.5", + "@rollup/rollup-linux-arm-musleabihf": "4.62.5", + "@rollup/rollup-linux-arm64-gnu": "4.62.5", + "@rollup/rollup-linux-arm64-musl": "4.62.5", + "@rollup/rollup-linux-loong64-gnu": "4.62.5", + "@rollup/rollup-linux-loong64-musl": "4.62.5", + "@rollup/rollup-linux-ppc64-gnu": "4.62.5", + "@rollup/rollup-linux-ppc64-musl": "4.62.5", + "@rollup/rollup-linux-riscv64-gnu": "4.62.5", + "@rollup/rollup-linux-riscv64-musl": "4.62.5", + "@rollup/rollup-linux-s390x-gnu": "4.62.5", + "@rollup/rollup-linux-x64-gnu": "4.62.5", + "@rollup/rollup-linux-x64-musl": "4.62.5", + "@rollup/rollup-openbsd-x64": "4.62.5", + "@rollup/rollup-openharmony-arm64": "4.62.5", + "@rollup/rollup-win32-arm64-msvc": "4.62.5", + "@rollup/rollup-win32-ia32-msvc": "4.62.5", + "@rollup/rollup-win32-x64-gnu": "4.62.5", + "@rollup/rollup-win32-x64-msvc": "4.62.5", "fsevents": "~2.3.2" } }, @@ -3527,6 +3637,14 @@ "node": ">=0.10.0" } }, + "node_modules/strictdom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strictdom/-/strictdom-1.0.1.tgz", + "integrity": "sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -3564,16 +3682,16 @@ } }, "node_modules/tabbable": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", - "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", + "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", "dev": true, "license": "MIT", "peer": true, @@ -3581,6 +3699,23 @@ "node": ">=18" } }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -3593,9 +3728,9 @@ } }, "node_modules/ts-dedent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", - "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", "dev": true, "license": "MIT", "peer": true, @@ -3677,9 +3812,9 @@ } }, "node_modules/uuid": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", - "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", + "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -3722,21 +3857,24 @@ } }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -3745,19 +3883,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -3778,6 +3922,12 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, @@ -3838,17 +3988,17 @@ } }, "node_modules/vue": { - "version": "3.5.35", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", - "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.41.tgz", + "integrity": "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.35", - "@vue/compiler-sfc": "3.5.35", - "@vue/runtime-dom": "3.5.35", - "@vue/server-renderer": "3.5.35", - "@vue/shared": "3.5.35" + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-sfc": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/server-renderer": "3.5.41", + "@vue/shared": "3.5.41" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index 8d86ebb46..9668f9e6c 100644 --- a/package.json +++ b/package.json @@ -11,5 +11,8 @@ "dependencies": { "markdown-it-footnote": "^4.0.0", "medium-zoom": "^1.1.0" + }, + "overrides": { + "vite": "6.4.3" } } diff --git a/reference/components/index.md b/reference/components/index.md index 5c0d5e5f8..7d6550e79 100644 --- a/reference/components/index.md +++ b/reference/components/index.md @@ -25,6 +25,8 @@ The components that run as part of a Platform Mesh installation. Most pages are - [Kubernetes GraphQL gateway](./kubernetes-graphql-gateway.md) - [Portal](./portal.md) + - [Portal UI library](./portal/portal-ui-lib.md) + - [Portal server library](./portal/portal-server-lib.md) - [Marketplace](./marketplace.md) - [virtual-workspaces](./virtual-workspaces.md) diff --git a/reference/components/marketplace.md b/reference/components/marketplace.md index 7a8f8ac79..832c4d3d8 100644 --- a/reference/components/marketplace.md +++ b/reference/components/marketplace.md @@ -9,7 +9,7 @@ Under the hood, installing a provider creates a Kubernetes `APIBinding` in the c The key capabilities are: - **Provider catalog** — browsable, searchable, and filterable list of all available service providers -- **Provider details** — full metadata view: description, contacts, documentation, support channels, service level, and verification status +- **Provider details** — full metadata view: description, contacts, documentation, support channels, service level - **Install** — creates an `APIBinding` in the current workspace with all required permission claims auto-accepted - **Uninstall** — deletes the `APIBinding` after a confirmation dialog - **Theme support** — renders provider icons in light or dark variants based on the active SAP Fiori theme @@ -38,21 +38,6 @@ MarketplaceEntry resources + APIBinding create/delete The active `accountId` is forwarded from the Luigi context to every GraphQL request so that `spec.installed` reflects the binding state of the current workspace. -## Technology stack - -| Component | Technology | -|---|---| -| Framework | Angular 21 | -| UI components | SAP Fundamental NGX 0.61 | -| Micro-frontend orchestration | Luigi 2.22 | -| State management | NgRx 21 | -| GraphQL client | Apollo Angular / Apollo Client 4 | -| Subscriptions transport | SSE (Server-Sent Events) | -| i18n | Angular localization (English, German) | -| Testing | Vitest 4 | -| Language | TypeScript (ES2022, strict mode) | -| Container | nginx:alpine, served on port 8080 | - ## Configuration The UI reads all runtime configuration from the Luigi node context injected by the Portal. No static environment files are required in production. The relevant context fields are: @@ -63,6 +48,14 @@ The UI reads all runtime configuration from the Luigi node context injected by t | `accountId` | Current workspace scope for install/uninstall operations | | `token` | Bearer token forwarded to every GraphQL request | | `analyticsTrackerConfig` | Optional Matomo analytics configuration | +| `uiConfig.filters` | Optional list of `{label, providerMetadataPath}` entries that define the catalog's filter facets | + +`uiConfig.filters` drives which filter dropdowns render above the provider catalog and how they behave, without requiring a UI code change: + +- Each entry renders one filter control. If the list is empty or absent, no filter row is shown. +- `label` is the filter's display name (e.g. `Category`, `Provider`). +- `providerMetadataPath` is a dot-path resolved against each provider's `ProviderMetadata`, walking through JSON-encoded sub-objects (such as `spec.data`) as needed — e.g. `spec.data.category` or `spec.data.provider`. +- The available options for a filter are the distinct values found at that path across the current catalog. Selecting one or more values narrows the catalog to providers whose resolved value matches a selection; no selection shows every provider. ## Repository diff --git a/reference/components/portal.md b/reference/components/portal.md index 281b9ba2d..5623dbe26 100644 --- a/reference/components/portal.md +++ b/reference/components/portal.md @@ -22,12 +22,33 @@ Every navigation node is scoped to a **kcp workspace path** (for example `root:o The backend derives the active workspace path from the authenticated user's context and injects it into the Luigi `globalContext`, making it available to all child microfrontends without additional round-trips. +## Architecture + +The Portal repository is a thin application. Most of its behavior comes from two layers of libraries: the generic OpenMFP portal libraries provide the shell, and the Platform Mesh portal libraries plug in the Platform Mesh–specific implementations. + +``` +Portal frontend (Angular) Portal backend (NestJS) + ↓ ↓ +@platform-mesh/portal-ui-lib @platform-mesh/portal-server-lib + ↓ ↓ +@openmfp/portal-ui-lib (Luigi shell) @openmfp/portal-server-lib (PortalModule) +``` + +| Layer | Library | Role in the Portal | +|---|---|---| +| Frontend | [Portal UI library](./portal/portal-ui-lib.md) (`@platform-mesh/portal-ui-lib`) | Provides the `portal-options` service implementations passed to `providePortal()` — navigation, header bar, node context processing, routing, and user profile — plus the generic UI web components | +| Backend | [Portal server library](./portal/portal-server-lib.md) (`@platform-mesh/portal-server-lib`) | Provides the providers passed to `PortalModule.create()` — authentication, request and portal context, account entity context, `ContentConfiguration` service providers, and the permissions proxy | + ## Repository - [github.com/platform-mesh/portal](https://github.com/platform-mesh/portal) +- [github.com/platform-mesh/portal-ui-lib](https://github.com/platform-mesh/portal-ui-lib) +- [github.com/platform-mesh/portal-server-lib](https://github.com/platform-mesh/portal-server-lib) ## Related +- [Portal UI library](./portal/portal-ui-lib.md) +- [Portal server library](./portal/portal-server-lib.md) - [Explore the example MSP](/tutorials/explore-example-msp.md) - [IAM UI](./iam-ui.md) - [Marketplace](./marketplace.md) diff --git a/reference/components/portal/portal-server-lib.md b/reference/components/portal/portal-server-lib.md new file mode 100644 index 000000000..56e654ab4 --- /dev/null +++ b/reference/components/portal/portal-server-lib.md @@ -0,0 +1,35 @@ +# Portal server library + +## Purpose + +The **Portal server library** (`@platform-mesh/portal-server-lib`) is the NestJS library the [Portal](../portal.md) backend is built with. It builds on the generic [`@openmfp/portal-server-lib`](https://www.npmjs.com/package/@openmfp/portal-server-lib), which provides the `PortalModule` that serves the frontend, handles the OAuth2 flow, and assembles the Luigi configuration. The Platform Mesh library supplies the implementations that connect that module to kcp, Keycloak, and the Platform Mesh authorization stack. + +## Provided implementations + +The library exports its providers from `@platform-mesh/portal-server-lib/portal-options`. The Portal backend passes them to `PortalModule.create()`: + +| Export | Implements | Responsibility | +|---|---|---| +| `PMAuthConfigProvider` | `AuthConfigService` | Resolves the organization from the request host, reads the OIDC client from the `IdentityProviderConfiguration` resource in kcp, and returns the authorization and token endpoints from OIDC discovery | +| `PMLogoutService` | `LogoutCallback` | Ends the session at the identity provider on logout | +| `PMRequestContextProvider` | `RequestContextProvider` | Adds the organization and whether the request targets an organization subdomain to the request context | +| `PMPortalContextService` | `PortalContextProvider` | Resolves `${org-name}` and `${org-subdomain}` placeholders in portal context URLs and adds the public kcp workspace URL | +| `AccountEntityContextProvider` | `EntityContextProvider` | Provides the context values for the `account` entity | +| `KubernetesServiceProvidersService` | `ServiceProviderService` | Lists [`ContentConfiguration`](/reference/resources/content-configuration.md) resources for the current organization and account through kcp, and returns them together with the resolved node permissions | +| `ContentConfigurationServiceProvidersService` | `ServiceProviderService` | Alternative service provider that reads `ContentConfiguration` resources through the `contentconfigurations` [virtual workspace](../virtual-workspaces.md) of the [Kubernetes GraphQL gateway](../kubernetes-graphql-gateway.md) | +| `KcpKubernetesService` | — | Kubernetes client for kcp, configured from `KUBECONFIG_KCP` | +| `PermissionsProxyService`, `AuthzWebhookService` | — | Resolve navigation node and resource instance permissions through the `/batch-authz` endpoint of the [rebac-authz-webhook](../rebac-authz-webhook.md), configured by `OPENMFP_PORTAL_CONTEXT_AUTHZ_WEBHOOK_URL`; when unset, permission checks fail open | +| `PermissionsController` | — | Exposes `POST /rest/permissions/resource-check` for instance-level permission checks from the frontend | + +Outside an organization subdomain, both service providers return the welcome node configuration instead of `ContentConfiguration` resources. + +## Repository + +- [github.com/platform-mesh/portal-server-lib](https://github.com/platform-mesh/portal-server-lib) + +## Related + +- [Portal](../portal.md) +- [Portal UI library](./portal-ui-lib.md) +- [Keycloak](../keycloak.md) +- [rebac-authz-webhook](../rebac-authz-webhook.md) diff --git a/reference/components/portal/portal-ui-lib.md b/reference/components/portal/portal-ui-lib.md new file mode 100644 index 000000000..87f628ee1 --- /dev/null +++ b/reference/components/portal/portal-ui-lib.md @@ -0,0 +1,114 @@ +# Portal UI library + +## Purpose + +The **Portal UI library** (`@platform-mesh/portal-ui-lib`) is the Angular library the [Portal](../portal.md) frontend is built with. It builds on the generic [`@openmfp/portal-ui-lib`](https://www.npmjs.com/package/@openmfp/portal-ui-lib), which provides the Luigi-based portal shell, and adds the implementations required for Platform Mesh functionality: kcp workspace-aware navigation, resource access through the [Kubernetes GraphQL gateway](../kubernetes-graphql-gateway.md), permission checks, and a set of reusable web components. + +The library ships two artifacts: + +- **Angular library** — service implementations, models, and utilities consumed by the Portal frontend at build time +- **Web component bundle** — `platform-mesh-portal-ui-wc.js`, a set of self-registering custom elements that Luigi loads at runtime + +## Package contents + +The Angular library is split into secondary entry points: + +| Entry point | Contents | +|---|---| +| `@platform-mesh/portal-ui-lib/portal-options` | `*ServiceImpl` classes passed to `providePortal()` from `@openmfp/portal-ui-lib`: custom global nodes, header bar (breadcrumbs, namespace selection), Luigi extended global context, navigation redirect strategy, node change hook, node context processing, routing, user profile, and the persistent panel listener | +| `@platform-mesh/portal-ui-lib/services` | Resource and gateway services (Apollo-based GraphQL), instance permissions, account info, logical cluster, kubeconfig Secret, and organization readiness | +| `@platform-mesh/portal-ui-lib/models` | Resource, UI definition, permissions, and account info types | +| `@platform-mesh/portal-ui-lib/utils` | Helpers for JSON paths, GraphQL query building, and resource sanitization | + +The web component bundle registers the following custom elements: + +| Element | Purpose | +|---|---| +| `generic-list-view` | Generic resource list with create and delete | +| `generic-detail-view` | Generic resource detail page | +| `organization-management` | Organization onboarding and selection | +| `welcome-view` | Welcome page shown outside an organization context | +| `error-component` | Error page | + +## Generic UI + +The generic UI lets you render list, detail, and create views for any Kubernetes or kcp resource without building a dedicated microfrontend. Instead of shipping UI code, you describe the resource and its views declaratively in the node's [`ContentConfiguration`](/reference/resources/content-configuration.md), and the generic UI web components query the resource through the Kubernetes GraphQL gateway. + +### Components + +- `generic-list-view` — displays a table of resources, and handles creation and deletion of resources +- `generic-detail-view` — displays an individual resource + +### Node configuration + +A Luigi node uses a generic UI component by pointing its `url` at the web component bundle and marking it as self-registered: + +```json +{ + "url": "/assets/platform-mesh-portal-ui-wc.js#generic-list-view", + "webcomponent": { "selfRegistered": true, "type": "module" }, + "navigationContext": "accounts" +} +``` + +A `generic-detail-view` node that is a child of a list view entity inherits its context through Luigi. An independent detail view node provides its own `context.resourceDefinition`. + +### Resource definition + +The node `context.resourceDefinition` describes the resource and how to render it: + +| Field | Purpose | +|---|---| +| `apiGroup`, `version`, `entityCollection`, `entity`, `scope`, `namespace` | Identify the resource in the GraphQL schema | +| `readyCondition` | Optional JSONPath expression and GraphQL properties that decide when a resource is ready | +| `availableWhenNotReady` | Optional; keeps a resource available for navigation and actions while it is not ready (default `false`) | +| `permissionsDefinition` | Optional instance-level and resource-level permission checks that gate the create button, list requests, live-update subscriptions, and edit or delete actions; unknown permissions fail open | +| `ui.logoUrl` | Resource type logo shown in the view header | +| `ui.listView` | Table columns (`fields`), row `actions`, title, description, and optional filter tabs | +| `ui.detailView` | Displayed `fields`, header `actions`, title, description, and `showDownloadKubeconfig` | +| `ui.createView` | Form `fields` for creating and updating resources; for namespaced resources a namespace field is added when no namespace is resolved | + +### Field definitions + +Every column, form field, and action is a `FieldDefinition`. Field definitions support: + +- **Data access** — `property` (with fallback paths), `jsonPathExpression`, and `propertyField` with text transforms +- **Grouping** — multiple values in a single column or row through `group` +- **Rendering** — `uiSettings.displayAs` as `secret`, `boolIcon`, `link`, `tooltip`, `img`, or `button`, plus copy buttons and conditional CSS rules +- **Actions** — `navigate`, `openInModal`, `delete-resource`, and `download-kubeconfig-from-secret-ref`, optionally gated by `requirePermission` +- **Form input** — `required`, static `values`, and `dynamicValuesDefinition` that loads options through a GraphQL query with `{context.}` placeholders resolved from the Luigi context +- **Arrays of objects** — `propertyCollection`, including nested collections, for fields such as `status.conditions` + +### Defaults + +When neither `listView` nor `detailView` is provided, default views are used. When `createView` is not provided, the view offers no way to create a resource. + +For the complete configuration reference and full `ContentConfiguration` examples, see the [generic UI guide](https://github.com/platform-mesh/portal-ui-lib/blob/main/docs/readme-generic-ui.md). + +## Angular configuration + +A portal application that serves the web component bundle includes the library assets in its `angular.json` build configuration: + +```json +{ + "assets": [ + { + "glob": "**", + "input": "node_modules/@platform-mesh/portal-ui-lib/assets/", + "output": "/assets/" + } + ] +} +``` + +## Repository + +- [github.com/platform-mesh/portal-ui-lib](https://github.com/platform-mesh/portal-ui-lib) +- [Generic UI guide](https://github.com/platform-mesh/portal-ui-lib/blob/main/docs/readme-generic-ui.md) + +## Related + +- [Portal](../portal.md) +- [Portal server library](./portal-server-lib.md) +- [Kubernetes GraphQL gateway](../kubernetes-graphql-gateway.md) +- [ContentConfiguration resource](/reference/resources/content-configuration.md) diff --git a/reference/components/security-operator.md b/reference/components/security-operator.md index 6df8750e1..432109fdf 100644 --- a/reference/components/security-operator.md +++ b/reference/components/security-operator.md @@ -159,6 +159,8 @@ When somebody creates an `APIBinding` to consume a provider's API, the Security This dynamic model extension means providers do not need to manually configure authorization for each consumer — the Security operator handles it automatically as APIs are bound and unbound. +By default, the generated authorization model uses standard permission mappings (e.g., `member` can `get`, `update`, `patch`, `watch`; `owner` can `delete`). Providers who need custom roles or permissions can create a [`ProviderPermissions`](#providerpermissions) resource to customize the generated model. + **Example AuthorizationModel resource:** ```yaml @@ -364,6 +366,44 @@ status: - :root:orgs:* ``` +### ProviderPermissions + +The `ProviderPermissions` resource allows API providers to customize the authorization model for their resources. While the Security operator auto-generates default permission mappings for provider APIs, `ProviderPermissions` enables providers to: + +- Define custom roles with display names and descriptions for the IAM UI +- Override default verb permissions +- Add custom permissions beyond standard CRUD operations (e.g., `scan`, `approve`, etc.) + +Providers create this resource in their workspace under `:root:providers:`, alongside the `APIExport` and other provider resources. When a consumer creates an `APIBinding`, the Security operator merges the custom relations from `ProviderPermissions` into the generated `AuthorizationModel`. + +**Example ProviderPermissions resource:** + +```yaml +apiVersion: providers.platform-mesh.io/v1alpha1 +kind: ProviderPermissions +metadata: + name: orchestrate.platform-mesh.io +spec: + apiExport: + ref: + name: orchestrate.platform-mesh.io + roles: + - groupResource: httpbin.orchestrate.platform-mesh.io + roles: + - id: codeviewer + displayName: Code Viewer + description: Can view code and related resources. + permissions: + httpbin.orchestrate.platform-mesh.io: + defaultPermissions: + get: "codeviewer or member" + delete: "owner" + additionalPermissions: + scan: "member" +``` + +For detailed field documentation and examples, see the [ProviderPermissions resource reference](/reference/resources/provider-permissions-resource.md). + ## Configuration ### OpenFGA settings diff --git a/reference/resources/index.md b/reference/resources/index.md index 67df08f7f..ed1f3b10c 100644 --- a/reference/resources/index.md +++ b/reference/resources/index.md @@ -9,4 +9,5 @@ For conceptual explanations of accounts, control planes, API sharing, identity, - [ContentConfiguration](./content-configuration.md) — register UI extensions with the Portal. - [Provider resource](./provider-resource.md) — provisions a dedicated kcp workspace and kubeconfig for a service provider. - [ManagedProvider resource](./managed-provider-resource.md) — automates end-to-end onboarding of platform-owned services. +- [ProviderPermissions resource](./provider-permissions-resource.md) — customize authorization roles and permissions for provider APIs. - [Metadata catalog](./metadata-catalog.md) — Platform Mesh API groups, labels, and finalizers. diff --git a/reference/resources/provider-permissions-resource.md b/reference/resources/provider-permissions-resource.md new file mode 100644 index 000000000..0e73490c2 --- /dev/null +++ b/reference/resources/provider-permissions-resource.md @@ -0,0 +1,225 @@ +# ProviderPermissions resource + +## Definition + +The `ProviderPermissions` custom resource allows API providers to customize authorization for their resources. It extends the auto-generated [AuthorizationModel](/reference/components/security-operator.md#authorizationmodel) with custom roles and permissions, enabling fine-grained access control beyond Platform Mesh defaults. + +The `ProviderPermissions` CR is defined in the API group `providers.platform-mesh.io/v1alpha1` and is reconciled by the [Security operator](/reference/components/security-operator.md) during `APIBinding` reconciliation. When a consumer binds to a provider's API, the Security operator merges the provider's custom relations into the generated authorization model. + +Providers create this resource in their workspace under `:root:providers:`, alongside the `APIExport`, `ContentConfiguration`, and other provider resources. + +## When to use + +Use `ProviderPermissions` when your provider needs to: + +- **Add custom permissions** beyond standard CRUD operations (e.g., `scan`, `approve`, `review`) +- **Override default verb permissions** to change which roles can perform standard actions (e.g., restrict `delete` to owners only, or allow a custom `codeviewer` role to `get` resources) +- **Introduce custom roles** with display names and descriptions for the IAM UI + +If your provider only needs the default authorization behavior (owner/member roles with standard verb mappings), you do not need a `ProviderPermissions` resource. + +## Schema + +A minimal `ProviderPermissions` looks like this: + +```yaml +apiVersion: providers.platform-mesh.io/v1alpha1 +kind: ProviderPermissions +metadata: + name: orchestrate.platform-mesh.io +spec: + apiExport: + ref: + name: orchestrate.platform-mesh.io + roles: + - groupResource: httpbin.orchestrate.platform-mesh.io + roles: + - id: codeviewer + displayName: Code Viewer + description: Can view code and related resources. + permissions: + httpbin.orchestrate.platform-mesh.io: + defaultPermissions: + get: "codeviewer or member" + additionalPermissions: + scan: "member" +``` + +| Field | Purpose | +| --- | --- | +| `spec.apiExport.ref.name` | Name of the `APIExport` this configuration applies to. The provider can only define permissions for resources exposed by this APIExport. | +| `spec.roles` | Custom roles grouped by resource type. These roles appear in the IAM UI and can be assigned to users. | +| `spec.permissions` | Per-resource permission configuration. Override default verb permissions or add custom permissions. | + +## Roles configuration + +The `roles` field defines custom roles for specific resource types. Each entry groups roles by `groupResource`: + +```yaml +roles: + - groupResource: httpbin.orchestrate.platform-mesh.io + roles: + - id: codeviewer + displayName: Code Viewer + description: Can view code and related resources. + definition: "[role#assignee] or member" +``` + +| Field | Purpose | +| --- | --- | +| `groupResource` | Resource type in format `{kind}.{group}` (e.g., `httpbin.orchestrate.platform-mesh.io`). Must match a resource in the provider's APIExport. | +| `roles[].id` | Role identifier. Becomes the relation name in OpenFGA and is used in permission expressions. | +| `roles[].displayName` | Human-readable name shown in the IAM UI. | +| `roles[].description` | Explains what the role does. Shown in the IAM UI. | +| `roles[].definition` | (Optional) OpenFGA relation definition. Defines how the role relation is computed. If omitted, defaults to `[role#assignee]`. | + +## Permissions configuration + +The `permissions` field configures authorization for specific resource types: + +```yaml +permissions: + httpbin.orchestrate.platform-mesh.io: + defaultPermissions: + get: "codeviewer or member" + update: "" + delete: "owner" + patch: "" + watch: "" + additionalPermissions: + scan: "[user:*] or member" + approve: "owner" +``` + +| Field | Purpose | +| --- | --- | +| Key (e.g., `httpbin.orchestrate.platform-mesh.io`) | Resource type in format `{kind}.{group}`. Must match a resource in the provider's APIExport. | +| `defaultPermissions` | Override the default permission expressions for standard Kubernetes verbs. | +| `additionalPermissions` | Define custom permissions beyond standard CRUD operations. | + +### Default permissions + +The `defaultPermissions` section overrides how standard Kubernetes verbs are authorized: + +| Verb | Default (if empty) | Description | +| --- | --- | --- | +| `get` | `member` | Read a single resource | +| `update` | `member` | Replace a resource | +| `delete` | `member` | Delete a resource | +| `patch` | `member` | Partially update a resource | +| `watch` | `member` | Watch for resource changes | + +Set a verb to an empty string `""` to use the default. Set it to a custom expression to override: + +```yaml +defaultPermissions: + get: "codeviewer or member" # Custom: codeviewer OR member can get + delete: "owner" # Override: only owner can delete + update: "" # Default: member can update +``` + +### Additional permissions + +The `additionalPermissions` section defines custom permissions that don't map to standard Kubernetes verbs: + +```yaml +additionalPermissions: + scan: "[user:*] or member" # Anyone or member can scan + approve: "owner" # Only owner can approve + review: "codeviewer or owner" # codeviewer OR owner can review +``` + +These permissions become relations in the OpenFGA authorization model and can be checked by application code. + +## Who creates it + +| Use case | Created by | +| --- | --- | +| Provider-specific authorization | Provider developer, in their workspace under `:root:providers:` | + +Providers create this resource alongside their `APIExport`, `ContentConfiguration`, and other provider resources. The resource name typically matches the APIExport name. + +## Who reconciles it + +The [Security operator](/reference/components/security-operator.md) reconciles `ProviderPermissions` during `APIBinding` reconciliation. When a consumer binds to a provider's API, the operator: + +1. Lists `ProviderPermissions` resources in the provider's workspace +2. Finds the one matching the bound `APIExport` +3. Merges custom relations into the generated `AuthorizationModel` + +## What happens when you apply one + +1. Provider creates `ProviderPermissions` in their workspace under `:root:providers:` +2. A consumer creates an `APIBinding` to the provider's `APIExport` +3. Security operator reconciles the `APIBinding` and discovers the `ProviderPermissions` +4. Security operator generates an `AuthorizationModel` with the custom relations merged in +5. The Store controller writes the updated model to OpenFGA +6. The [IAM service](/reference/components/iam-service.md) can now query available roles for the resource type +7. Users can be assigned the custom roles through the IAM UI or GraphQL API + +When the `ProviderPermissions` resource is updated, the Security operator regenerates affected `AuthorizationModel` resources. + +When the `ProviderPermissions` resource is deleted, the Security operator regenerates the `AuthorizationModel` without the custom relations, reverting to default behavior. + +## Example: Adding a custom role with permissions + +This example shows a provider adding a `codeviewer` role that can read resources and perform a custom `scan` operation: + +```yaml +apiVersion: providers.platform-mesh.io/v1alpha1 +kind: ProviderPermissions +metadata: + name: orchestrate.platform-mesh.io +spec: + apiExport: + ref: + name: orchestrate.platform-mesh.io + roles: + - groupResource: httpbin.orchestrate.platform-mesh.io + roles: + - id: codeviewer + displayName: Code Viewer + description: Can view code and related resources. + definition: "[role#assignee] or member" + - id: admin + displayName: Admin + description: Administrative access with elevated permissions. + definition: "[role#assignee] or owner" + permissions: + httpbin.orchestrate.platform-mesh.io: + defaultPermissions: + get: "codeviewer or member" + update: "" + delete: "owner" + patch: "" + watch: "" + additionalPermissions: + scan: "[user:*] or member" + approve: "admin or owner" +status: + conditions: + - type: Ready + status: "True" +``` + +This configuration: + +- Defines two custom roles: `codeviewer` and `admin` +- Allows `codeviewer` or `member` to perform `get` operations +- Restricts `delete` to `owner` only +- Adds a `scan` permission that anyone (`[user:*]`) or `member` can use +- Adds an `approve` permission for `admin` or `owner` + +## Constraints + +- **Resource ownership**: Providers can only define permissions for resources exposed by their `APIExport`. Attempting to define permissions for other providers' resources or system resources is rejected. +- **Relation syntax**: Permission expressions use [OpenFGA DSL syntax](https://openfga.dev/docs/configuration-language). Invalid syntax causes the `AuthorizationModel` generation to fail. +- **Parent inheritance**: The `from parent` relation has limitations when multiple providers define roles with the same name. See the RFC for details on `from` operator constraints. + +## Related + +- [Security operator](/reference/components/security-operator.md) — reconciles ProviderPermissions and generates AuthorizationModels +- [Authorization concepts](/concepts/security/authorization.md) — Platform Mesh two-tier authorization model +- [OpenFGA](/reference/components/openfga.md) — the authorization engine +- [IAM service](/reference/components/iam-service.md) — queries roles and manages user assignments +- [Provider resource](/reference/resources/provider-resource.md) — provisions provider workspaces diff --git a/tutorials/explore-example-msp.md b/tutorials/explore-example-msp.md index e30e77b8a..356120607 100644 --- a/tutorials/explore-example-msp.md +++ b/tutorials/explore-example-msp.md @@ -11,7 +11,7 @@ The local setup is under active development. Features and workflows may change. ```bash git clone https://github.com/platform-mesh/helm-charts.git cd helm-charts -git checkout 0.3.0 +git checkout 0.4.0 ``` ## Run the setup with example data