diff --git a/docs/architecture/adr/0033-adopt-mermaid-diagram-standard.md b/docs/architecture/adr/0033-adopt-mermaid-diagram-standard.md index bf5f3acfc..57be3db80 100644 --- a/docs/architecture/adr/0033-adopt-mermaid-diagram-standard.md +++ b/docs/architecture/adr/0033-adopt-mermaid-diagram-standard.md @@ -1,6 +1,6 @@ --- adr: "0033" -status: Proposed +status: Accepted date: 2026-07-16 tags: [clients, mobile, server, sdk] --- @@ -36,10 +36,10 @@ audience-specific views -- requires substantial rework per audience in practice. ## Decision outcome -Chosen option: **Mermaid with defined conventions**, published as the diagram standard on the -contributing site. The standard is the living reference. Its rules evolve by PR without superseding -this decision and this ADR is superseded only if the chosen option itself changes. A snapshot of the -rules at adoption: +Chosen option: **Mermaid with defined conventions**, published as the +[diagram standard](../../contributing/diagrams.md) on the contributing site. The standard is the +living reference and its rules evolve by PR without superseding this decision. This ADR is +superseded only if the chosen option itself changes. A snapshot of the rules at adoption: 1. Diagrams are Mermaid source text, nothing else: as Mermaid code blocks, or, if in Confluence, via Macro Pack's Mermaid diagram in text-input mode. @@ -80,12 +80,12 @@ rules at adoption: ### Plan -[PR #834](https://github.com/bitwarden/contributing-docs/pull/834) publishes the standard at -Contributing › Diagrams and converts the contributing site's existing diagrams (PlantUML/Kroki -sources, static diagram assets, and source-less images) to comply, so the site itself becomes the -reference implementation of the standard. Elsewhere, legacy diagrams convert when their docs are -next touched: images and non-Mermaid sources in repos become Mermaid code blocks, and Confluence -attachments and images become Macro Pack's Mermaid diagram in text-input mode. +The standard is published at Contributing › Diagrams, and the bulk of the contributing site's +existing diagrams (PlantUML/Kroki sources, static diagram assets, and source-less images) have been +converted to comply, so the site becomes the reference implementation of the standard, with the +exceptions noted below. Elsewhere, legacy diagrams convert when their docs are next touched: images +and non-Mermaid sources in repos become Mermaid code blocks, and Confluence attachments and images +become Macro Pack's Mermaid diagram in text-input mode. The remaining adoption work is delegated to its owners: diff --git a/docs/architecture/clients/data-model.md b/docs/architecture/clients/data-model.md index 0fa5b69ad..5541e3251 100644 --- a/docs/architecture/clients/data-model.md +++ b/docs/architecture/clients/data-model.md @@ -8,23 +8,24 @@ This document describes the internal data model used by the different client app several dedicated models to represent our data layer. With a slightly complicated data transformation pipeline. -```kroki type=plantuml -@startuml -skinparam componentStyle rectangle -component [""""] as Domain -component [""""Request] As Request -component [""""Response] as Response -component [""""View] as View -component [""""Export] as Export -component [""""Data] as Data - -[Response] -r-> [Data] -[Data] <-r-> [Domain] -[Domain] -r-> [Request] -[Domain] <--> [View] -[Domain] <--> [Export] -[Export] -r-> [View] -@enduml +```mermaid +--- +config: + layout: elk +--- +flowchart LR + Response["<Domain>Response"] + Data["<Domain>Data"] + Domain["<Domain>"] + Request["<Domain><Modifier>Request"] + Export["<Domain>Export"] + View["<Domain>View"] + Response --> Data + Data <--> Domain + Domain --> Request + Domain <--> Export + Domain <--> View + Export --> View ``` ## Domain diff --git a/docs/architecture/clients/index.md b/docs/architecture/clients/index.md index 5c41da525..7671054f4 100644 --- a/docs/architecture/clients/index.md +++ b/docs/architecture/clients/index.md @@ -33,44 +33,40 @@ For readability, ubiquitous app dependencies to `common` are hidden. ::: -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle -skinparam linetype ortho - -title Simplified Package Diagram - -component "Bitwarden License" { - component "Bit Web" -} +```mermaid +--- +title: Simplified Package Diagram +--- +flowchart TB + subgraph license ["Bitwarden License"] + BitWeb["Bit Web"] + end -component apps { - component "Web Vault" - component "Desktop" - component "Browser Extension" - component "CLI" -} + subgraph apps + WebVault["Web Vault"] + Desktop["Desktop"] + BrowserExtension["Browser Extension"] + CLI["CLI"] + end -component libs { - component "Common" - component "Angular" - component "Node" -} + subgraph libs + Common["Common"] + Angular["Angular"] + Node["Node"] + end -[Bit Web] --> [Web Vault] -[Bit Web] --[norank]> [Angular] + BitWeb --> WebVault + BitWeb --> Angular -[Web Vault] --> [Angular] + WebVault --> Angular -[Browser Extension] --> [Angular] + BrowserExtension --> Angular -[CLI] --> [Node] + CLI --> Node -[Angular] --> [Common] + Angular --> Common -[Desktop] --> [Angular] + Desktop --> Angular -[Node] --> [Common] -@enduml + Node --> Common ``` diff --git a/docs/architecture/clients/overview.md b/docs/architecture/clients/overview.md index 2bf6e0963..2d5640ef7 100644 --- a/docs/architecture/clients/overview.md +++ b/docs/architecture/clients/overview.md @@ -37,34 +37,28 @@ access the specific domain in the _State Service_. Below is an example how a _domain component_ and _domain service_ interacts with the _State Service_. -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle - -title State Service - -component "Example Domain" { - component "Components" as components - - component "Domain Service" as domain -} - -component "State Service" as state - -component "Storage Service" as storage -component "Secure Storage Service" as secure -component "Memory Storage Service" as memory +```mermaid +--- +title: State Service +--- +flowchart TB + subgraph exampleDomain ["Example Domain"] + components["Components"] + domain["Domain Service"] + end -components -d-> domain : subscribe \n observable -domain -> state : retrieve state + state["State Service"] -state --> storage -state --> secure + storage["Storage Service"] + secure["Secure Storage Service"] + memory["Memory Storage Service"] -state --> memory + components -->|"subscribe
observable"| domain + domain -->|"retrieve state"| state -@enduml + state --> storage + state --> secure + state --> memory ``` ## Services diff --git a/docs/architecture/clients/services/implementation.md b/docs/architecture/clients/services/implementation.md index ec35a3059..8b3ba45af 100644 --- a/docs/architecture/clients/services/implementation.md +++ b/docs/architecture/clients/services/implementation.md @@ -17,40 +17,42 @@ types of services, for a given domain in our [Data Model](../data-model.md): - `Internal[Domain]Service` - `[Domain]ApiService` -```kroki type=plantuml -@startuml -abstract class Internal[Domain]Service #aliceblue { - + upsert(item: [Domain]) - + replace(items: [Domain][]) -} -class [Domain]Service #aliceblue { - # subject : BehaviorSubject<[Domain][]> - + observable: Observable<[Domain][]> - - updateObservables() -} -class [Domain]ApiService #aliceblue { - + get[Domain]() - + get[Domain]by[Property]() - + put[Domain]() -} -class "UI Component" -class SyncService { - + fullSync() - - sync[Domain]() -} -class ApiService { - + send() -} - -"UI Component" *-- "[Domain]Service" : uses -"UI Component" *-- "[Domain]ApiService" : uses - -"[Domain]Service" --|> "Internal[Domain]Service" : extends -SyncService *-- "Internal[Domain]Service" : uses - -"[Domain]ApiService" *-- ApiService : uses -"[Domain]ApiService" *-- "Internal[Domain]Service" : uses -@enduml +```mermaid +classDiagram + class Internal["Internal[Domain]Service"] { + <> + +upsert(item: [Domain]) + +replace(items: [Domain][]) + } + class DomainSvc["[Domain]Service"] { + #subject : BehaviorSubject~[Domain][]~ + +observable : Observable~[Domain][]~ + -updateObservables() + } + class ApiSvc["[Domain]ApiService"] { + +get[Domain]() + +get[Domain]by[Property]() + +put[Domain]() + } + class UI["UI Component"] + class Sync["SyncService"] { + +fullSync() + -sync[Domain]() + } + class Api["ApiService"] { + +send() + } + + UI *-- DomainSvc : uses + UI *-- ApiSvc : uses + DomainSvc --|> Internal : extends + Sync *-- Internal : uses + ApiSvc *-- Api : uses + ApiSvc *-- Internal : uses + + style Internal fill:#f0f8ff + style DomainSvc fill:#f0f8ff + style ApiSvc fill:#f0f8ff ``` The classes and their responsibilities are detailed below: @@ -76,34 +78,36 @@ changes across clients. ### Server Update: Updated in the current client -```kroki type=plantuml -@startuml -abstract class Internal[Domain]Service #aliceblue { - + upsert(item: [Domain]) - + replace(items: [Domain][]) -} -class [Domain]Service #aliceblue { - # subject : BehaviorSubject<[Domain][]> - + observable: Observable<[Domain][]> - - updateObservables() -} -class [Domain]ApiService #aliceblue { - + put[Domain]() -} -together { -class "UI Component" -class "Other UI Component" -} -class ApiService { - + send() -} - -"UI Component" --> "[Domain]ApiService" -"[Domain]ApiService" --> ApiService -"[Domain]ApiService" --> "Internal[Domain]Service" -"Internal[Domain]Service" --> "[Domain]Service" -"[Domain]Service" ..> "Other UI Component" : Observable next() -@enduml +```mermaid +classDiagram + class Internal["Internal[Domain]Service"] { + <> + +upsert(item: [Domain]) + +replace(items: [Domain][]) + } + class DomainSvc["[Domain]Service"] { + #subject : BehaviorSubject~[Domain][]~ + +observable : Observable~[Domain][]~ + -updateObservables() + } + class ApiSvc["[Domain]ApiService"] { + +put[Domain]() + } + class UI["UI Component"] + class OtherUI["Other UI Component"] + class Api["ApiService"] { + +send() + } + + UI --> ApiSvc + ApiSvc --> Api + ApiSvc --> Internal + Internal --> DomainSvc + DomainSvc ..> OtherUI : Observable next() + + style Internal fill:#f0f8ff + style DomainSvc fill:#f0f8ff + style ApiSvc fill:#f0f8ff ``` In the case that the domain is updated in the client, the change will begin with the user modifying @@ -119,30 +123,30 @@ You can see those responsibilities above, where `ApiService` updates the server ### Cache-Only Update: Updated in a different client -```kroki type=plantuml -@startuml -abstract class Internal[Domain]Service #aliceblue { - + upsert(item: [Domain]) - + replace(items: [Domain][]) -} -class [Domain]Service #aliceblue { - # subject : BehaviorSubject<[Domain][]> - + observable: Observable<[Domain][]> - - updateObservables() -} -together { - class "UI Component" - class SyncService { - + fullSync() - - sync[Domain]() +```mermaid +classDiagram + class Internal["Internal[Domain]Service"] { + <> + +upsert(item: [Domain]) + +replace(items: [Domain][]) + } + class DomainSvc["[Domain]Service"] { + #subject : BehaviorSubject~[Domain][]~ + +observable : Observable~[Domain][]~ + -updateObservables() + } + class UI["UI Component"] + class Sync["SyncService"] { + +fullSync() + -sync[Domain]() } -} -SyncService --> "Internal[Domain]Service" -"Internal[Domain]Service" --> "[Domain]Service" -"[Domain]Service" ..> "UI Component" : Observable next() + Sync --> Internal + Internal --> DomainSvc + DomainSvc ..> UI : Observable next() -@enduml + style Internal fill:#f0f8ff + style DomainSvc fill:#f0f8ff ``` For domain updates from another client, the current client receives those messages through the @@ -156,25 +160,25 @@ mechanism, but that implementation is abstracted from the `SyncService` and any ## Domain reads -```kroki type=plantuml -@startuml - -class [Domain]ApiService #aliceblue { - + get[Domain]() - + get[Domain]by[Property]() -} -class "UI Component" { - load() -} -class ApiService { - + send() -} - -"UI Component" --> "[Domain]ApiService" -"[Domain]ApiService" --> ApiService -ApiService --> "[Domain]ApiService" -"[Domain]ApiService" --> "UI Component" -@enduml +```mermaid +classDiagram + class ApiSvc["[Domain]ApiService"] { + +get[Domain]() + +get[Domain]by[Property]() + } + class UI["UI Component"] { + load() + } + class Api["ApiService"] { + +send() + } + + UI --> ApiSvc + ApiSvc --> Api + Api --> ApiSvc + ApiSvc --> UI + + style ApiSvc fill:#f0f8ff ``` When it is necessary to retrieve data directly from the server rather than subscribing to the diff --git a/docs/architecture/deep-dives/autofill/collecting-page-details.md b/docs/architecture/deep-dives/autofill/collecting-page-details.md index 5b88be338..c4b3fd37d 100644 --- a/docs/architecture/deep-dives/autofill/collecting-page-details.md +++ b/docs/architecture/deep-dives/autofill/collecting-page-details.md @@ -51,48 +51,40 @@ These flows are diagrammed below: #### Autofill on Page Load -```kroki type=plantuml -@startuml -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -participant autofiller.ts as autofiller -end box - -box "Background Pages" #E5E8E8 -participant notification.background.ts as notification -participant runtime.background.ts as runtime -participant main.background.ts as main -end box - -autofiller -> runtime : bgCollectPageDetails [sender: autofiller] -runtime --> main : collectPageDetailsForContentScript() -main -> autofill : collectPageDetails [sender: autofiller] -autofill -> runtime : collectPageDetailsResponse [sender: autofiller] - -@enduml +```mermaid +sequenceDiagram + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + participant autofiller as autofiller.ts + end + box rgb(229,232,232) Background Pages + participant notification as notification.background.ts + participant runtime as runtime.background.ts + participant main as main.background.ts + end + autofiller->>runtime: bgCollectPageDetails [sender: autofiller] + runtime-->>main: collectPageDetailsForContentScript() + main->>autofill: collectPageDetails [sender: autofiller] + autofill->>runtime: collectPageDetailsResponse [sender: autofiller] ``` #### Notification Bar -```kroki type=plantuml -@startuml -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -participant notificationBar.ts as notificationBar -end box - -box "Background Pages" #E5E8E8 -participant notification.background.ts as notification -participant runtime.background.ts as runtime -participant main.background.ts as main -end box - -notificationBar -> runtime : bgCollectPageDetails [sender: notificationBar] -runtime --> main : collectPageDetailsForContentScript() -main -> autofill : collectPageDetails [sender: notificationBar] -autofill -> notificationBar: collectPageDetailsResponse [sender: notificationBar] - -@enduml +```mermaid +sequenceDiagram + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + participant notificationBar as notificationBar.ts + end + box rgb(229,232,232) Background Pages + participant notification as notification.background.ts + participant runtime as runtime.background.ts + participant main as main.background.ts + end + notificationBar->>runtime: bgCollectPageDetails [sender: notificationBar] + runtime-->>main: collectPageDetailsForContentScript() + main->>autofill: collectPageDetails [sender: notificationBar] + autofill->>notificationBar: collectPageDetailsResponse [sender: notificationBar] ``` ### Requesting page details from context menu @@ -107,27 +99,21 @@ fired. This event is handled by the `contextMenus.background.js` background page catches this request and issues a `collectPageDetailsResponse` with a sender of `contextMenus` when complete, which is handled by the `runtime.background.js` background page. -```kroki type=plantuml -@startuml - -actor User -participant "Autofill Context Menu" as autofillContext - -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -end box - -box "Background Pages" #E5E8E8 -participant contextMenus.background.ts as context -participant runtime.background.ts as runtime -end box - -User --> autofillContext -autofillContext -> context : contextMenus.onClicked() -context -> autofill : collectPageDetails [sender: contextMenu] -autofill -> runtime : collectPageDetailsResponse [sender: contextMenu] - -@enduml +```mermaid +sequenceDiagram + actor User + participant autofillContext as Autofill Context Menu + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + end + box rgb(229,232,232) Background Pages + participant context as contextMenus.background.ts + participant runtime as runtime.background.ts + end + User-->>autofillContext: + autofillContext->>context: contextMenus.onClicked() + context->>autofill: collectPageDetails [sender: contextMenu] + autofill->>runtime: collectPageDetailsResponse [sender: contextMenu] ``` ### Requesting page details on keyboard shortcut @@ -149,27 +135,21 @@ After generating the page details, the `autofill-init.ts` content script broadca `collectPageDetailsResponse` message with an `autofill_cmd` sender. The `runtime.background.js` background page is listening for this message and receives it. -```kroki type=plantuml -@startuml - -actor User - -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -end box - -box "Background Pages" #E5E8E8 -participant commands.background.ts as commands -participant runtime.background.ts as runtime -participant main.background.ts as main -end box - -User -> commands : autofill_login -commands --> main : collectPageDetailsForContentScript() -main -> autofill : collectPageDetails [sender: autofill_cmd] -autofill -> runtime : collectPageDetailsResponse [sender: autofill_cmd] - -@enduml +```mermaid +sequenceDiagram + actor User + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + end + box rgb(229,232,232) Background Pages + participant commands as commands.background.ts + participant runtime as runtime.background.ts + participant main as main.background.ts + end + User->>commands: autofill_login + commands-->>main: collectPageDetailsForContentScript() + main->>autofill: collectPageDetails [sender: autofill_cmd] + autofill->>runtime: collectPageDetailsResponse [sender: autofill_cmd] ``` #### Manifest v3 @@ -183,24 +163,18 @@ response is **not** another message broadcast through the browser command API. I `autofill-init.ts` content script performs the page details generation and returns the response asynchronously through a Promise. -```kroki type=plantuml -@startuml - -actor User - -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -end box - - -box "Listeners" #7A7A7A -participant commandListener as listener -end box - -User -> listener : autofill_login -listener -> autofill : collectPageDetailsImmediately -autofill --> listener -@enduml +```mermaid +sequenceDiagram + actor User + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + end + box rgb(122,122,122) Listeners + participant listener as commandListener + end + User->>listener: autofill_login + listener->>autofill: collectPageDetailsImmediately + autofill-->>listener: ``` ### Requesting page details from the extension UI @@ -215,34 +189,36 @@ instance's unique `BroadcasterSubscriptionId` as the `sender`. The `autofill-ini generates the page details and responds with a `collectPageDetailsResponse` message with the same `sender`, ensuring that the message is received properly by the correct sender. -```kroki type=plantuml -@startuml -actor User - -box "Content Scripts" #B8B8B8 -participant "autofill-init.ts" as autofill -end box - -box "Extension UI" #7A7A7A -participant view.component.ts as viewComponent -participant "current-tab.component.ts" as currentTab -end box - -group Autofill from Item View - User --> viewComponent : Clicks Autofill Button - viewComponent -> autofill : collectPageDetails [sender: BroadcasterSubscriptionId] - autofill --> viewComponent : collectPageDetailsResponse [sender: BroadcasterSubscriptionId] -end group - -break - -group Autofill from Current Tab View - User --> currentTab : Clicks Autofill on Cipher - currentTab -> autofill : collectPageDetails [sender: BroadcasterSubscriptionId] - autofill --> currentTab : collectPageDetailsResponse [sender: BroadcasterSubscriptionId] -end group +Autofill from the item view (`view.component.ts`): + +```mermaid +sequenceDiagram + actor User + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + end + box rgb(122,122,122) Extension UI + participant viewComponent as view.component.ts + end + User-->>viewComponent: Clicks Autofill Button + viewComponent->>autofill: collectPageDetails [sender: BroadcasterSubscriptionId] + autofill-->>viewComponent: collectPageDetailsResponse [sender: BroadcasterSubscriptionId] +``` -@enduml +Autofill from the current tab view (`current-tab.component.ts`): + +```mermaid +sequenceDiagram + actor User + box rgb(184,184,184) Content Scripts + participant autofill as autofill-init.ts + end + box rgb(122,122,122) Extension UI + participant currentTab as current-tab.component.ts + end + User-->>currentTab: Clicks Autofill on Cipher + currentTab->>autofill: collectPageDetails [sender: BroadcasterSubscriptionId] + autofill-->>currentTab: collectPageDetailsResponse [sender: BroadcasterSubscriptionId] ``` ## Performing the collection of the page details diff --git a/docs/architecture/deep-dives/autofill/index.md b/docs/architecture/deep-dives/autofill/index.md index cdfd177db..01934759c 100644 --- a/docs/architecture/deep-dives/autofill/index.md +++ b/docs/architecture/deep-dives/autofill/index.md @@ -60,23 +60,18 @@ them. The Autofill architecture leverages the in order to communicate between the extension UI, the background pages, and the content scripts that are running on each browser tab. -```kroki type=plantuml -@startuml - - package "Browser Tab" as T { - [Page Source] - [Content Scripts] - } - - node "Bitwarden Browser Extension" as E { - [Browser Extension UI] - [Background Pages] - } - - [Background Pages] --> [Content Scripts] : tabSendMessage - [Content Scripts] --> [Background Pages] : sendMessage - -@enduml +```mermaid +flowchart TB + subgraph T ["Browser Tab"] + pageSource["Page Source"] + contentScripts["Content Scripts"] + end + subgraph E ["Bitwarden Browser Extension"] + extUi["Browser Extension UI"] + backgroundPages["Background Pages"] + end + backgroundPages -->|tabSendMessage| contentScripts + contentScripts -->|sendMessage| backgroundPages ``` #### Sending a request from the content script to the extension diff --git a/docs/architecture/deep-dives/ipc.md b/docs/architecture/deep-dives/ipc.md index c57aa3777..719123343 100644 --- a/docs/architecture/deep-dives/ipc.md +++ b/docs/architecture/deep-dives/ipc.md @@ -39,34 +39,20 @@ high-level logic of the IPC communication. This includes the serialization and d messages, as well as the encryption and decryption of messages. They depend on the platform-specific parts to integrate with the underlying platform's IPC mechanisms. -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle -skinparam linetype ortho -skinparam Padding 7 -hide members - -package "Platform agnostic" <> { - struct IpcClient - - interface CommunicationBackend - interface CryptoProvider - interface SessionRepository - - IpcClient --> CommunicationBackend: owns - IpcClient --> CryptoProvider: owns - IpcClient --> SessionRepository: owns - - CryptoProvider .l.> CommunicationBackend: uses - CryptoProvider .r.> SessionRepository: uses - - struct NoEncryptionCryptoProvider - - CryptoProvider <|.. NoEncryptionCryptoProvider: implements -} - -@enduml +```mermaid +flowchart TB + IpcClient["IpcClient"] + CommunicationBackend(["CommunicationBackend"]) + CryptoProvider(["CryptoProvider"]) + SessionRepository(["SessionRepository"]) + NoEncryptionCryptoProvider["NoEncryptionCryptoProvider"] + + IpcClient -->|owns| CommunicationBackend + IpcClient -->|owns| CryptoProvider + IpcClient -->|owns| SessionRepository + CryptoProvider -.->|uses| CommunicationBackend + CryptoProvider -.->|uses| SessionRepository + NoEncryptionCryptoProvider -.->|implements| CryptoProvider ``` ### Platform-specific @@ -78,47 +64,32 @@ details of the IPC communication. Below is an illustration of the platform-speci for the WebAssembly (WASM) platform, which uses JavaScript to implement how messages are sent and received: -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle -skinparam linetype ortho -skinparam Padding 7 -hide members - -package SDK <> { - package "Platform agnostic" <> { - struct IpcClient - - interface CommunicationBackend - - IpcClient --> CommunicationBackend - } - - package "Platform specific (WASM)" <> { - struct JsCommunicationBackend - } -} - -package JavaScript <> { - class WebIpcService - class IpcBackgroundService -} - -JsCommunicationBackend -left|> CommunicationBackend - -note bottom of JsCommunicationBackend - JsCommunicationBackend converts the Rust trait into a JavaScript-compatible interface -end note - -WebIpcService .up|> JsCommunicationBackend: implements -IpcBackgroundService .up|> JsCommunicationBackend: implements - -WebIpcService -[hidden]-> IpcBackgroundService -JavaScript -down[hidden]-> SDK - -@enduml - +```mermaid +--- +config: + layout: elk +--- +flowchart TB + subgraph sdk ["SDK"] + subgraph agnostic ["Platform agnostic"] + IpcClient["IpcClient"] + CommunicationBackend(["CommunicationBackend"]) + IpcClient -->|owns| CommunicationBackend + end + subgraph wasm ["Platform specific (WASM)"] + JsCommunicationBackend["JsCommunicationBackend"] + end + end + subgraph js ["JavaScript"] + WebIpcService["WebIpcService"] + IpcBackgroundService["IpcBackgroundService"] + end + JsCommunicationBackend -.->|implements| CommunicationBackend + WebIpcService -.->|implements| JsCommunicationBackend + IpcBackgroundService -.->|implements| JsCommunicationBackend + jsNote["JsCommunicationBackend converts the Rust trait
into a JavaScript-compatible interface"] + JsCommunicationBackend -.- jsNote + style jsNote fill:#fffbe6,stroke:#e0c200 ``` ## Security @@ -181,33 +152,27 @@ implementations to define how messages are sent across the wire. This allows the flexible and adaptable to different platforms and use cases, while still providing a consistent interface for consumers. -```kroki type=plantuml -@startuml -skinparam linetype ortho -skinparam Padding 7 -skinparam componentStyle rectangle - -component OutgoingIpcMessage { - component "topic: Option" as outgoing_topic - component "destination: Endpoint" as outgoing_destination - component "payload: Vec" as outgoing_payload - - outgoing_topic -[hidden]-> outgoing_destination - outgoing_destination -[hidden]-> outgoing_payload -} - -component IncomingIpcMessage { - component "topic: Option" as incoming_topic - component "destination: Endpoint" as incoming_destination - component "source: Endpoint" as incoming_source - component "payload: Vec" as incoming_payload - - incoming_topic -[hidden]-> incoming_destination - incoming_destination -[hidden]-> incoming_source - incoming_source -[hidden]-> incoming_payload -} - -@enduml +```mermaid +--- +config: + layout: elk +--- +flowchart TB + subgraph outgoing ["OutgoingIpcMessage"] + direction TB + o_topic["topic: Option<String>"] + o_dest["destination: Endpoint"] + o_payload["payload: Vec<u8>"] + o_topic ~~~ o_dest ~~~ o_payload + end + subgraph incoming ["IncomingIpcMessage"] + direction TB + i_topic["topic: Option<String>"] + i_dest["destination: Endpoint"] + i_source["source: Endpoint"] + i_payload["payload: Vec<u8>"] + i_topic ~~~ i_dest ~~~ i_source ~~~ i_payload + end ``` ### Request / Response @@ -222,46 +187,37 @@ data being sent in the request. The framework will then serialize the response a response message will contain the request identifier, type, and payload, allowing the framework to match the response with the original request and handle it accordingly. -```kroki type=plantuml -@startuml -skinparam linetype ortho -skinparam Padding 7 -skinparam componentStyle rectangle - -component OutgoingIpcMessage { - component "topic: "RpcRequestMessage"" as outgoing_topic - component "destination: Endpoint" as outgoing_destination - component "RpcRequestMessage" <> as outgoing_payload { - component "request_id: String" as outgoing_rpc_id - component "request_type: String" as outgoing_rpc_type - component "request: Vec" as outgoing_rpc_data - - outgoing_rpc_id -[hidden]-> outgoing_rpc_type - outgoing_rpc_type -[hidden]-> outgoing_rpc_data - } - - outgoing_topic -[hidden]-> outgoing_destination - outgoing_destination -[hidden]-> outgoing_payload -} - -component IncomingIpcMessage { - component "topic: "RpcResponseMessage"" as incoming_topic - component "destination: Endpoint" as incoming_destination - component "source: Endpoint" as incoming_source - - component "RpcResponseMessage" <> as incoming_payload { - component "request_id: String" as incoming_rpc_id - component "request_type: String" as incoming_rpc_type - component "request: Vec" as incoming_rpc_data - - incoming_rpc_id -[hidden]-> incoming_rpc_type - incoming_rpc_type -[hidden]-> incoming_rpc_data - } - - incoming_topic -[hidden]-> incoming_destination - incoming_destination -[hidden]-> incoming_source - incoming_source -[hidden]-> incoming_payload -} - -@enduml +```mermaid +--- +config: + layout: elk +--- +flowchart TB + subgraph outgoing ["OutgoingIpcMessage"] + direction TB + o_topic["topic: "RpcRequestMessage""] + o_dest["destination: Endpoint"] + subgraph o_payload ["payload: RpcRequestMessage"] + direction TB + o_id["request_id: String"] + o_type["request_type: String"] + o_req["request: Vec<u8>"] + o_id ~~~ o_type ~~~ o_req + end + o_topic ~~~ o_dest ~~~ o_payload + end + subgraph incoming ["IncomingIpcMessage"] + direction TB + i_topic["topic: "RpcResponseMessage""] + i_dest["destination: Endpoint"] + i_source["source: Endpoint"] + subgraph i_payload ["payload: RpcResponseMessage"] + direction TB + i_id["request_id: String"] + i_type["request_type: String"] + i_req["request: Vec<u8>"] + i_id ~~~ i_type ~~~ i_req + end + i_topic ~~~ i_dest ~~~ i_source ~~~ i_payload + end ``` diff --git a/docs/architecture/deep-dives/passkeys/implementations/provider/browser-extension.md b/docs/architecture/deep-dives/passkeys/implementations/provider/browser-extension.md index 17a8336b7..e1050657c 100644 --- a/docs/architecture/deep-dives/passkeys/implementations/provider/browser-extension.md +++ b/docs/architecture/deep-dives/passkeys/implementations/provider/browser-extension.md @@ -33,50 +33,42 @@ See [Naming Convention](../../naming-convention) for more information. ::: -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle - -title Browser extension FIDO2 architecture overview - -component "Browser" { - component "Web page" { - component "JavaScript Application" - component "Page Script" <> { - component "Custom WebAuthn API" - component "Messenger" as pageScriptMessenger - - [Custom WebAuthn API] -> [pageScriptMessenger] - } - - component "Content Script" { - component "Messenger" as contentScriptMessenger - } - - component "User Agent WebAuthn API" <> - - [JavaScript Application] -> [Custom WebAuthn API] - [Custom WebAuthn API] --> [User Agent WebAuthn API] - } - - component "Extension" { - component "Background Script" - component "FIDO2 Client" - component "FIDO2 Authenticator" - component "FIDO2 User Interface" - database "Vault" - - [FIDO2 Client] -> [FIDO2 Authenticator] - [FIDO2 Authenticator] -> [Vault] - [FIDO2 Authenticator] --> [FIDO2 User Interface] - } - - [pageScriptMessenger] <--> [contentScriptMessenger] - [contentScriptMessenger] --> [Background Script] - [Background Script] -> [FIDO2 Client] -} -@enduml +```mermaid +--- +title: Browser extension FIDO2 architecture overview +--- +flowchart TB + subgraph browser ["Browser"] + direction TB + subgraph webPage ["Web page"] + jsApp["JavaScript Application"] + subgraph pageScript ["Page Script «Injected»"] + customWebauthn["Custom WebAuthn API"] + pageMessenger["Messenger"] + end + subgraph contentScript ["Content Script"] + contentMessenger["Messenger"] + end + uaWebauthn["User Agent WebAuthn API «Native»"] + end + subgraph extension ["Extension"] + bgScript["Background Script"] + fido2Client["FIDO2 Client"] + fido2Auth["FIDO2 Authenticator"] + fido2Ui["FIDO2 User Interface"] + vault[("Vault")] + end + end + + customWebauthn --> pageMessenger + jsApp --> customWebauthn + customWebauthn --> uaWebauthn + fido2Client --> fido2Auth + fido2Auth --> vault + fido2Auth --> fido2Ui + pageMessenger <--> contentMessenger + contentMessenger --> bgScript + bgScript --> fido2Client ``` ## Discoverability diff --git a/docs/architecture/deep-dives/passkeys/index.md b/docs/architecture/deep-dives/passkeys/index.md index 134fffe2e..498122784 100644 --- a/docs/architecture/deep-dives/passkeys/index.md +++ b/docs/architecture/deep-dives/passkeys/index.md @@ -47,64 +47,55 @@ the browser. ::: -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle - -title FIDO2 Overview - -component "Relying Party" { - component "Server Application" { - component "HTTPS API" - component "App" - component "FIDO2 Library" - - database "Database" - - - [HTTPS API] --> [App] - [App] --> [FIDO2 Library] - [App] -> [Database] - } - - component "JavaScript Application" as rp_js_app -} - -component "Client platform" { - component "Browser" { - component "JavaScript Application" as client_js_app #line.dashed - - component "User Agent" { - component "WebAuthn API" - component "WebAuthn Client" - } - - [WebAuthn API] - [WebAuthn Client] - [client_js_app] --> [WebAuthn API] - } - - component "Operating System" { - component "Platform Auth API" - component "Platform Auth Client" - component "Platform Authenticator" <<$chip{scale=0.1}>> - - [Platform Auth API] - [Platform Auth Client] - [Platform Auth Client] --> [Platform Authenticator] - } -} - -component "Roaming Authenticator" <<$usb{scale=0.1}>> - -[WebAuthn Client] --> [Roaming Authenticator] : CTAP2 -[WebAuthn Client] --> [Platform Auth API] -[Platform Auth Client] --> [Roaming Authenticator] : CTAP2 - -[rp_js_app] - [client_js_app] -[rp_js_app] --> [HTTPS API] - -sprite $chip - -sprite $usb -@enduml +```mermaid +--- +title: FIDO2 Overview +--- +flowchart TB + subgraph rp ["Relying Party"] + subgraph serverApp ["Server Application"] + httpsApi["HTTPS API"] + app["App"] + fido2Lib["FIDO2 Library"] + db[("Database")] + end + rpJsApp["JavaScript Application"] + end + subgraph clientPlatform ["Client platform"] + subgraph browser ["Browser"] + clientJsApp["JavaScript Application"] + subgraph userAgent ["User Agent"] + webauthnApi["WebAuthn API"] + webauthnClient["WebAuthn Client"] + end + end + subgraph os ["Operating System"] + platformAuthApi["Platform Auth API"] + platformAuthClient["Platform Auth Client"] + subgraph platformAuthenticator ["Platform Authenticator"] + platformAuthenticatorIcon@{ icon: "bw:chip" } + end + end + end + subgraph roamingAuth ["Roaming Authenticator"] + roamingAuthIcon@{ icon: "bw:usb" } + end + + httpsApi --> app + app --> fido2Lib + app --> db + webauthnApi --- webauthnClient + clientJsApp --> webauthnApi + platformAuthApi --- platformAuthClient + platformAuthClient --> platformAuthenticator + webauthnClient -->|CTAP2| roamingAuth + webauthnClient --> platformAuthApi + platformAuthClient -->|CTAP2| roamingAuth + rpJsApp --- clientJsApp + rpJsApp --> httpsApi + + style clientJsApp stroke-dasharray: 5 5 + classDef sgStyle fill:#ececff,stroke:#9370db,stroke-width:1px,color:#111827; + class platformAuthenticator sgStyle; + class roamingAuth sgStyle; ``` diff --git a/docs/architecture/deep-dives/push-notifications/mobile.md b/docs/architecture/deep-dives/push-notifications/mobile.md index 644ee62f2..67d54bdec 100644 --- a/docs/architecture/deep-dives/push-notifications/mobile.md +++ b/docs/architecture/deep-dives/push-notifications/mobile.md @@ -42,20 +42,20 @@ device when the appropriate user triggers them on another device. #### Cloud implementation -```kroki type=plantuml -@startuml -participant MC_LS as "Mobile Device" -participant PNS as "Platform Notification Service" -participant API as "Bitwarden Cloud API" -participant NH as "Azure Notification Hub" - -group Register for token -MC_LS->>PNS: Register -PNS->>MC_LS: Push Token -MC_LS->>API: Store Push Token with Device and User -API->>NH: Associate Push Token with Device and User -end -@enduml +```mermaid +sequenceDiagram + participant MC_LS as Mobile Device + participant PNS as Platform Notification Service + participant API as Bitwarden Cloud API + participant NH as Azure Notification Hub + + rect rgba(128,128,128,0.1) + Note over MC_LS,NH: Register for token + MC_LS->>PNS: Register + PNS->>MC_LS: Push Token + MC_LS->>API: Store Push Token with Device and User + API->>NH: Associate Push Token with Device and User + end ``` If we are running a Bitwarden cloud instance, the Bitwarden API is responsible for directly @@ -65,22 +65,22 @@ communicating with the Azure Notification Hub to register the push token. This i #### Self-hosted implementation -```kroki type=plantuml -@startuml - participant MC_LS as "Mobile Device" - participant PNS as "Platform Notification Service" - participant API as "Self-Hosted API" - participant BWAPI as "Bitwarden Cloud API" - participant NH as "Azure Notification Hub" +```mermaid +sequenceDiagram + participant MC_LS as Mobile Device + participant PNS as Platform Notification Service + participant API as Self-Hosted API + participant BWAPI as Bitwarden Cloud API + participant NH as Azure Notification Hub - group Register + rect rgba(128,128,128,0.1) + Note over MC_LS,NH: Register MC_LS->>PNS: Register PNS->>MC_LS: Push Token MC_LS->>API: Store Push Token with Device and User API->>BWAPI: RelayPushRegistration sends message to /push/register BWAPI->>NH: Associate Token with Device and User (same as Cloud) end -@enduml ``` For self-hosted instances, the self-hosted instance cannot communicate directly with Bitwarden's @@ -118,26 +118,27 @@ responsible for sending push notifications to all mobile clients to make them aw #### Cloud implementation -```kroki type=plantuml -@startuml -participant MC_LS as "Mobile Device" -participant WC as "Other Client" -participant PNS as "Platform Notification Service" -participant API as "Bitwarden Cloud API" -participant NH as "Azure Notification Hub" - -group Other client updates data -WC->>API: Update Data -API->>NH: Send Message to Hub -end - -group Mobile message distribution -NH->>PNS: Send Message to Clients by Push Token -PNS->>MC_LS: OnMessageAsync() -MC_LS->>API: Request data -API->>MC_LS: Return data requested -end -@enduml +```mermaid +sequenceDiagram + participant WC as Other Client + participant API as Bitwarden Cloud API + participant NH as Azure Notification Hub + participant PNS as Platform Notification Service + participant MC_LS as Mobile Device + + rect rgba(128,128,128,0.1) + Note over WC,MC_LS: Other client updates data + WC->>API: Update Data + API->>NH: Send Message to Hub + end + + rect rgba(128,128,128,0.1) + Note over WC,MC_LS: Mobile message distribution + NH->>PNS: Send Message to Clients by Push Token + PNS->>MC_LS: OnMessageAsync() + MC_LS->>API: Request data + API->>MC_LS: Return data requested + end ``` For notifications to mobile devices, this is handled in the @@ -154,29 +155,30 @@ device when the user _and_ device match. #### Self-hosted implementation -```kroki type=plantuml -@startuml - participant MC_LS as "Mobile Device" - participant WC as "Other Client" - participant PNS as "Platform Notification Service" - participant API as "Self-Hosted API" - participant SHN as "Self-Hosted Notification API" - participant BWAPI as "Bitwarden Cloud API" - participant NH as "Azure Notification Hub" - - Group Other client updates data +```mermaid +sequenceDiagram + participant WC as Other Client + participant API as Self-Hosted API + participant SHN as Self-Hosted Notification API + participant BWAPI as Bitwarden Cloud API + participant NH as Azure Notification Hub + participant PNS as Platform Notification Service + participant MC_LS as Mobile Device + + rect rgba(128,128,128,0.1) + Note over WC,MC_LS: Other client updates data WC->>API: Update Data API->>BWAPI: RelayPushNotification sends message to /push/send BWAPI->>NH: Send Message to Hub (same as Cloud) end - group Update clients + rect rgba(128,128,128,0.1) + Note over WC,MC_LS: Update clients NH->>PNS: Send Message to Clients PNS->>MC_LS: OnMessageAsync() MC_LS->>API: Request data API->>MC_LS: Return data requested by message end -@enduml ``` Just as with the registration of the push token, the self-hosted instance uses the diff --git a/docs/architecture/deep-dives/push-notifications/non-mobile.md b/docs/architecture/deep-dives/push-notifications/non-mobile.md index be0d02fb8..d97530f7b 100644 --- a/docs/architecture/deep-dives/push-notifications/non-mobile.md +++ b/docs/architecture/deep-dives/push-notifications/non-mobile.md @@ -15,28 +15,30 @@ self-hosted. ### Cloud implementation -```kroki type=plantuml -@startuml -participant C1 as "Initiating Client" -participant C2 as "Receiving Client" -participant API as "Bitwarden Cloud API" -participant Q as "Azure Queue" -participant NAPI as "Bitwarden Notifications API" - -group Establish SignalR connection -C2->>NAPI: Registers as SignalR client -end - -group Other client updates data -C1->>API: Updates Data -API->>Q: Sends Message to Azure Queue -end - -group Notifications API processes message -NAPI<<-Q: Reads from Azure Queue -NAPI->>C2: Sends SignalR message to registered clients -end -@enduml +```mermaid +sequenceDiagram + participant C1 as Initiating Client + participant API as Bitwarden Cloud API + participant Q as Azure Queue + participant NAPI as Bitwarden Notifications API + participant C2 as Receiving Client + + rect rgba(128,128,128,0.1) + Note over C1,C2: Establish SignalR connection + C2->>NAPI: Registers as SignalR client + end + + rect rgba(128,128,128,0.1) + Note over C1,C2: Other client updates data + C1->>API: Updates Data + API->>Q: Sends Message to Azure Queue + end + + rect rgba(128,128,128,0.1) + Note over C1,C2: Notifications API processes message + Q->>NAPI: Reads from Azure Queue + NAPI->>C2: Sends SignalR message to registered clients + end ``` For the Bitwarden Cloud implementation, the API uses the @@ -51,26 +53,28 @@ queue and sends them to all clients registered for the initiating user or organi ### Self-hosted implementation -```kroki type=plantuml -@startuml -participant C1 as "Initiating Client" -participant C2 as "Receiving Client" -participant SHAPI as "Self-Hosted API" -participant SHNAPI as "Self-Hosted Notifications API" - -group Register -C2->>SHNAPI: Registers as SignalR client -end - -Group Other client updates data -C1->>SHAPI: Updates data -SHAPI->>SHNAPI: Calls Notifications API to distribute the notification -end - -group Update clients -SHNAPI->>C2: Sends Message to registered clients -end -@enduml +```mermaid +sequenceDiagram + participant C1 as Initiating Client + participant SHAPI as Self-Hosted API + participant SHNAPI as Self-Hosted Notifications API + participant C2 as Receiving Client + + rect rgba(128,128,128,0.1) + Note over C1,C2: Register + C2->>SHNAPI: Registers as SignalR client + end + + rect rgba(128,128,128,0.1) + Note over C1,C2: Other client updates data + C1->>SHAPI: Updates data + SHAPI->>SHNAPI: Calls Notifications API to distribute the notification + end + + rect rgba(128,128,128,0.1) + Note over C1,C2: Update clients + SHNAPI->>C2: Sends Message to registered clients + end ``` For a self-hosted implementation, the push notification architecture differs because there is no diff --git a/docs/architecture/sdk/crate-structure.md b/docs/architecture/sdk/crate-structure.md index bce061765..8c6714e45 100644 --- a/docs/architecture/sdk/crate-structure.md +++ b/docs/architecture/sdk/crate-structure.md @@ -19,47 +19,48 @@ categories: From top to bottom, the dependency flow looks like this: -```kroki type=plantuml -@startuml -skinparam componentStyle rectangle - -component "Bindings (WASM & UniFFI)" as bindings #e1f5ff - -package "Application Interfaces" #fff3e0 { - component "Password Manager" as passwordMgr - component "Secrets Manager" as secretsMgr -} - -package "Features" #f3e5f5 { - component "Auth" as auth - component "Vault" as vault - component "Send" as send - component "Generators" as generators - component "Exporters" as export -} - -component "Core" as core #e8f5e9 - -bindings --> passwordMgr -bindings --> secretsMgr -bindings --> core - -passwordMgr --> auth -passwordMgr --> vault -passwordMgr --> send -passwordMgr --> generators -passwordMgr --> export -passwordMgr --> core - -secretsMgr --> core - -auth --> core -vault --> core -send --> core -generators --> core -export --> core - -@enduml +```mermaid +flowchart TB + bindings["Bindings (WASM & UniFFI)"] + + subgraph appInterfaces ["Application Interfaces"] + passwordMgr["Password Manager"] + secretsMgr["Secrets Manager"] + end + + subgraph features ["Features"] + auth["Auth"] + vault["Vault"] + send["Send"] + generators["Generators"] + export["Exporters"] + end + + core["Core"] + + bindings --> passwordMgr + bindings --> secretsMgr + bindings --> core + + passwordMgr --> auth + passwordMgr --> vault + passwordMgr --> send + passwordMgr --> generators + passwordMgr --> export + passwordMgr --> core + + secretsMgr --> core + + auth --> core + vault --> core + send --> core + generators --> core + export --> core + + style bindings fill:#e1f5ff + style core fill:#e8f5e9 + style appInterfaces fill:#fff3e0 + style features fill:#f3e5f5 ``` ## Bindings diff --git a/docs/architecture/sdk/data-models.md b/docs/architecture/sdk/data-models.md index 3df46a018..c8768f97a 100644 --- a/docs/architecture/sdk/data-models.md +++ b/docs/architecture/sdk/data-models.md @@ -71,18 +71,19 @@ The SDK also maintains internal models: - **DTO**: Data Transfer Objects are used to transfer data between layers of the SDK. They are generally used to decouple the domain models from the API models. -```kroki type=plantuml -@startuml -skinparam componentStyle rectangle -component [""""] as Domain -component [""""Requests] As Requests -component [""""Response] as Response -component [""""Views] as Views -component [""""DTOs] as DTOs - -[Response] -r-> [Domain] -[Domain] -r-> [Requests] -[Domain] <--> [Views] -[Domain] <--> [DTOs] -@enduml +```mermaid +--- +config: + layout: elk +--- +flowchart LR + Response["<API>Response"] + Domain["<Domain>"] + Requests["<API><Modifier>Requests"] + Views["<Domain>Views"] + DTOs["<Domain>DTOs"] + Response --> Domain + Domain --> Requests + Domain <--> Views + Domain <--> DTOs ``` diff --git a/docs/architecture/sdk/index.md b/docs/architecture/sdk/index.md index 963959077..249f47b2e 100644 --- a/docs/architecture/sdk/index.md +++ b/docs/architecture/sdk/index.md @@ -19,93 +19,67 @@ internal private items. ## Architecture overview -```kroki type=plantuml -@startuml -skinparam packageStyle rectangle -skinparam componentStyle rectangle -skinparam linetype ortho -skinparam shadowing false -skinparam defaultTextAlignment center - -skinparam package { - BackgroundColor<> #E3F2FD - BorderColor<> #1976D2 - BackgroundColor<> #FFF3E0 - BorderColor<> #F57C00 - BackgroundColor<> #E8F5E9 - BorderColor<> #388E3C -} - -skinparam component { - BackgroundColor<> #E8F5E9 - BorderColor<> #388E3C -} - -skinparam component { - BackgroundColor #FFFFFF - BorderColor #424242 - FontSize 12 -} - -package "Client Applications" <> { - package "TypeScript" { - [Web vault] as web - [Desktop] as desktop - [Browser extension] as browser - [CLI] as cli - } - package "Mobile" { - [iOS\n(Swift)] as ios - [Android\n(Kotlin)] as android - } - package "Rust" { - [Rust CLI] as rustcli - } -} - -package "Binding Layer" <> as bindings { - [WASM] as wasm - [UniFFI] as uniffi -} - -package "Rust SDK" <> as sdk { - package "Application Interfaces" { - [Password Manager] as pm - [Secrets Manager] as sm - } - folder "Features" { - [Vault] - [Generators] - } - folder "Utils" { - [Crypto] - [Logging] - } - [Core Runtime] as core -} - -TypeScript --> wasm -web -[hidden]> wasm -desktop -[hidden]> wasm -browser -[hidden]> wasm -cli -[hidden]> wasm -Mobile --> uniffi -ios -[hidden]> uniffi -android -[hidden]> uniffi - -bindings --> pm -bindings --> sm -uniffi --[hidden]-> pm -uniffi --[hidden]-> sm - -rustcli --> pm - -[Application Interfaces] -> [Features] -[Application Interfaces] ---> core -[Features] --> core -[Features] ---> Utils - -@enduml +```mermaid +flowchart TB + subgraph clients ["Client Applications"] + subgraph ts ["TypeScript"] + direction TB + web["Web vault"] + desktop["Desktop"] + browser["Browser extension"] + cli["CLI"] + end + subgraph mobile ["Mobile"] + direction LR + ios["iOS
(Swift)"] + android["Android
(Kotlin)"] + end + subgraph rust ["Rust"] + direction LR + rustcli["Rust CLI"] + end + end + + subgraph bindings ["Binding Layer"] + wasm["WASM"] + uniffi["UniFFI"] + end + + subgraph sdk ["Rust SDK"] + subgraph appInterfaces ["Application Interfaces"] + direction TB + pm["Password Manager"] + sm["Secrets Manager"] + end + subgraph feat ["Features"] + direction TB + vault["Vault"] + generators["Generators"] + end + subgraph utils ["Utils"] + direction TB + crypto["Crypto"] + logging["Logging"] + end + core["Core Runtime"] + end + + ts --> wasm + mobile --> uniffi + + bindings --> pm + bindings --> sm + + rustcli --> pm + + appInterfaces --> feat + appInterfaces --> core + feat --> core + feat --> utils + + style clients fill:#e3f2fd + style bindings fill:#fff3e0 + style sdk fill:#e8f5e9 ``` ## What belongs in the SDK diff --git a/docs/architecture/sdk/secrets-manager.md b/docs/architecture/sdk/secrets-manager.md index 185cb45ed..3ff54cf29 100644 --- a/docs/architecture/sdk/secrets-manager.md +++ b/docs/architecture/sdk/secrets-manager.md @@ -16,65 +16,42 @@ support all Bitwarden clients, the SM SDK exposes a curated, backward-compatible ## Architecture overview -```kroki type=plantuml -@startuml -skinparam packageStyle rectangle -skinparam componentStyle rectangle -skinparam shadowing false -skinparam defaultTextAlignment center - -skinparam package { - BackgroundColor<> #E3F2FD - BorderColor<> #1976D2 - BackgroundColor<> #FFF3E0 - BorderColor<> #F57C00 - BackgroundColor<> #E8F5E9 - BorderColor<> #388E3C -} - -skinparam component { - BackgroundColor<> #E8F5E9 - BorderColor<> #388E3C -} - -skinparam component { - BackgroundColor #FFFFFF - BorderColor #424242 - FontSize 12 -} - -package "Language Bindings" <> as bindings { - [Python] as py - [Golang] as go - [C#] as csharp - [JS] as wasm -} - -package "Secrets Manager SDK" <> as sm { - [bws] <> - [bitwarden] - [bitwarden-c] - [bitwarden-json] - [bitwarden-napi] - [bitwarden-py] -} - -["Rust SDK"] <> as sdk - -[bws] --> [bitwarden] -[bitwarden-json] --> [bitwarden] -[bitwarden-c] --> [bitwarden-json] -[bitwarden-napi] --> [bitwarden-json] -[bitwarden-py] --> [bitwarden-json] - -[bitwarden] --> sdk - -py --> [bitwarden-py] -go --> [bitwarden-c] -csharp --> [bitwarden-c] -wasm --> [bitwarden-napi] - -@enduml +```mermaid +flowchart TB + subgraph langBindings ["Language Bindings"] + py["Python"] + go["Golang"] + csharp["C#"] + js["JS"] + end + + subgraph smSdk ["Secrets Manager SDK"] + bws["bws (CLI)"] + bitwarden["bitwarden"] + bitwardenC["bitwarden-c"] + bitwardenJson["bitwarden-json"] + bitwardenNapi["bitwarden-napi"] + bitwardenPy["bitwarden-py"] + end + + rustSdk["Rust SDK"] + + bws --> bitwarden + bitwardenJson --> bitwarden + bitwardenC --> bitwardenJson + bitwardenNapi --> bitwardenJson + bitwardenPy --> bitwardenJson + + bitwarden --> rustSdk + + py --> bitwardenPy + go --> bitwardenC + csharp --> bitwardenC + js --> bitwardenNapi + + style langBindings fill:#fff3e0 + style smSdk fill:#e3f2fd + style rustSdk fill:#e8f5e9 ``` ## `bitwarden` crate diff --git a/docs/contributing/code-style/web/angular.md b/docs/contributing/code-style/web/angular.md index f97616f45..eeac4e716 100644 --- a/docs/contributing/code-style/web/angular.md +++ b/docs/contributing/code-style/web/angular.md @@ -151,65 +151,52 @@ work with, as well as a multi level inheritance tree. To avoid this, components should be broken up into logical standalone pieces. The different clients should use the the shared components by customizing the page level components. -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle - -title Login Component - -component "Web Vault" { - component "Login Page Component" as loginWeb -} - -component "Desktop" { - component "Login Page Component" as loginDesktop -} - -component "Angular" { - together { - component "Login Component" - component "Captcha Component" - component "Auth Service" - } -} - -[loginWeb] --> [Login Component]: Child component -[loginDesktop] --> [Login Component]: Child component -[Login Component] -> [Captcha Component]: Child component -[Login Component] --> [Auth Service]: Dependency -@enduml +```mermaid +--- +title: Login Component +--- +flowchart TB + subgraph webVault ["Web Vault"] + loginWeb["Login Page Component"] + end + subgraph desktop ["Desktop"] + loginDesktop["Login Page Component"] + end + subgraph angular ["Angular"] + loginComponent["Login Component"] + captcha["Captcha Component"] + authService["Auth Service"] + end + + loginWeb -->|Child component| loginComponent + loginDesktop -->|Child component| loginComponent + loginComponent -->|Child component| captcha + loginComponent -->|Dependency| authService ``` The diagram below showcases how the reports share logic by extracting the list into a shared component. Instead of the organization component directly extending the base report page component. For more details, read [the PR for the refactor](https://github.com/bitwarden/clients/pull/3204). -```kroki type=plantuml -@startuml -skinparam BackgroundColor transparent -skinparam componentStyle rectangle - -title Reports Home Page - -component "Reports Module" { - component "Reports Page" -} - -component "Reports Shared Module" { - component "Report List Component" - component "Report Component" -} - -component "Organization Reports Module" { - component "Organization Reports Page" -} - -[Reports Page] --> [Report List Component]: @Input reports[] -[Organization Reports Page] --> [Report List Component]: @Input reports[] -[Report List Component] --> [Report Component]: @Input report - -@enduml +```mermaid +--- +title: Reports Home Page +--- +flowchart TB + subgraph reportsModule ["Reports Module"] + reportsPage["Reports Page"] + end + subgraph reportsSharedModule ["Reports Shared Module"] + reportList["Report List Component"] + reportComponent["Report Component"] + end + subgraph orgReportsModule ["Organization Reports Module"] + orgReportsPage["Organization Reports Page"] + end + + reportsPage -->|"@Input reports[]"| reportList + orgReportsPage -->|"@Input reports[]"| reportList + reportList -->|"@Input report"| reportComponent ``` ## Reactivity ([ADR-0003](../../../architecture/adr/0003-observable-data-services.md) & [ADR-0029](../../../architecture/adr/0029-angular-signals.md)) diff --git a/docs/contributing/database-migrations/edd.mdx b/docs/contributing/database-migrations/edd.mdx index be590c612..081b67bab 100644 --- a/docs/contributing/database-migrations/edd.mdx +++ b/docs/contributing/database-migrations/edd.mdx @@ -55,7 +55,23 @@ three phases: _Start_, _Transition_, and _End_ as shown in the diagram below.
-![Refactoring Stages](./transitions.png) +```mermaid +flowchart LR + Start["Start"] + Transition["Transition"] + End["End"] + + Start -->|"Deploy X + 1
Initial migration"| Transition + Transition -->|"Deploy X + 2
Finalization migration"| End + Transition -->|"Transition migration"| Transition + + classDef phaseStart fill:#ff2603,color:#ffffff,stroke:#000000 + classDef phaseTransition fill:#fffc02,color:#000000,stroke:#000000 + classDef phaseEnd fill:#73fa79,color:#000000,stroke:#000000 + class Start phaseStart + class Transition phaseTransition + class End phaseEnd +```
Refactoring Phases
@@ -102,22 +118,39 @@ These migrations are run as part of the deployment of _Release X+2_. ### Example -Let's look at an example, the rename column refactor is shown in the image below. - -![Rename Column Refactor](./rename-column.gif) +Let's look at an example. Suppose we want to rename a hypothetical `username` column in the `User` +table to `email` without breaking any running code. + +```mermaid +flowchart LR + start["User
username"] + transition["User
username + email"] + ending["User
email"] + + start -->|"Initial migration
add email, sync both in the SPROC"| transition + transition -->|"Finalization migration
drop username"| ending + transition -->|"Transition migration
copy username to email"| transition + + classDef phaseStart fill:#ff2603,color:#ffffff,stroke:#000000 + classDef phaseTransition fill:#fffc02,color:#000000,stroke:#000000 + classDef phaseEnd fill:#73fa79,color:#000000,stroke:#000000 + class start phaseStart + class transition phaseTransition + class ending phaseEnd +``` -In this refactor we rename the column `Fname` in the `Customer` table to `FirstName`. This could -easily be achieved using a regular `Alter Table` statement but that would break compatibility with -existing running code. Instead let's look at how we can incrementally refactor this table. +This could easily be achieved using a regular `Alter Table` statement but that would break +compatibility with existing running code. Instead let's look at how we can incrementally refactor +this table. -We will begin by creating a migration which adds the column `FirstName` to the `Customer` Table. At -the same time we will also update the Stored Procedures to sync the content between `FName` and -`FirstName` which ensures both the old and new server releases can run at the same time. The sync -code is highlighted in the code snippet below. +We will begin by creating a migration which adds the column `email` to the `User` table. At the same +time we will also update the Stored Procedures to sync the content between `username` and `email` +which ensures both the old and new server releases can run at the same time. The sync code is +highlighted in the code snippet below. Afterwards the new server version will be deployed, once everything checks out the existing data -will be migrated using a _Data Migration_ script. Which essentially copies the `FName` to -`FirstName` columns. +will be migrated using a _Data Migration_ script. Which essentially copies the `username` to `email` +columns. Lastly the _Second Migration_ will be run which removes the old column and updates the Stored Procedure to remove the synchronization logic. @@ -138,44 +171,44 @@ Located in `util/Migrator/DbScripts`. ```sql -- Add Column -IF COL_LENGTH('[dbo].[Customer]', 'FirstName') IS NULL +IF COL_LENGTH('[dbo].[User]', 'email') IS NULL BEGIN ALTER TABLE - [dbo].[Customer] + [dbo].[User] ADD - [FirstName] NVARCHAR(MAX) NULL + [email] NVARCHAR(MAX) NULL END GO -- Drop existing SPROC -IF OBJECT_ID('[dbo].[Customer_Create]') IS NOT NULL +IF OBJECT_ID('[dbo].[User_Create]') IS NOT NULL BEGIN - DROP PROCEDURE [dbo].[Customer_Create] + DROP PROCEDURE [dbo].[User_Create] END GO -- Create the new SPROC -CREATE PROCEDURE [dbo].[Customer_Create] - @CustomerId UNIQUEIDENTIFIER OUTPUT, - @FName NVARCHAR(MAX) = NULL, -- Deprecated as of YYYY-MM-DD - @FirstName NVARCHAR(MAX) = NULL +CREATE PROCEDURE [dbo].[User_Create] + @UserId UNIQUEIDENTIFIER OUTPUT, + @username NVARCHAR(MAX) = NULL, -- Deprecated as of YYYY-MM-DD + @email NVARCHAR(MAX) = NULL AS BEGIN SET NOCOUNT ON - SET @FirstName = COALESCE(@FirstName, @FName); + SET @email = COALESCE(@email, @username); - INSERT INTO [dbo].[Customer] + INSERT INTO [dbo].[User] ( - [CustomerId], - [FName], - [FirstName] + [UserId], + [username], + [email] ) VALUES ( - @CustomerId, - @FirstName, - @FirstName + @UserId, + @email, + @email ) END ``` @@ -186,9 +219,17 @@ END Located in `util/Migrator/DbScripts_transition`. ```sql -UPDATE [dbo].Customer SET - FirstName=FName -WHERE FirstName IS NULL +DECLARE @BatchSize INT = 1000; +DECLARE @RowsAffected INT = 1; + +WHILE @RowsAffected > 0 +BEGIN + UPDATE TOP (@BatchSize) [dbo].[User] + SET email = username + WHERE email IS NULL AND username IS NOT NULL; + + SET @RowsAffected = @@ROWCOUNT; +END ``` @@ -198,39 +239,39 @@ Located in `util/Migrator/DbScripts_finalization`. ```sql -- Remove Column -IF COL_LENGTH('[dbo].[Customer]', 'FName') IS NOT NULL +IF COL_LENGTH('[dbo].[User]', 'username') IS NOT NULL BEGIN ALTER TABLE - [dbo].[Customer] + [dbo].[User] DROP COLUMN - [FName] + [username] END GO -- Drop existing SPROC -IF OBJECT_ID('[dbo].[Customer_Create]') IS NOT NULL +IF OBJECT_ID('[dbo].[User_Create]') IS NOT NULL BEGIN - DROP PROCEDURE [dbo].[Customer_Create] + DROP PROCEDURE [dbo].[User_Create] END GO -- Create the new SPROC -CREATE PROCEDURE [dbo].[Customer_Create] - @CustomerId UNIQUEIDENTIFIER OUTPUT, - @FirstName NVARCHAR(MAX) = NULL +CREATE PROCEDURE [dbo].[User_Create] + @UserId UNIQUEIDENTIFIER OUTPUT, + @email NVARCHAR(MAX) = NULL AS BEGIN SET NOCOUNT ON - INSERT INTO [dbo].[Customer] + INSERT INTO [dbo].[User] ( - [CustomerId], - [FirstName] + [UserId], + [email] ) VALUES ( - @CustomerId, - @FirstName + @UserId, + @email ) END ``` @@ -247,16 +288,32 @@ There are some important constraints to the implementation of the process: same always-on application constraint - Minimization of manual steps in the process -The process to support all of these constraints is a complex one. Below is an image of a state -machine that will hopefully help visualize the process and what it supports. It assumes that all +The process to support all of these constraints is a complex one. The state machine below tracks a +single destructive change through the phases and shows which rollbacks are safe. It assumes that all database changes follow the standards that are laid out in [Migrations](./mssql.md). ---- - -![Bitwarden EDD State Machine](./edd_state_machine.jpg) \[Open Image in a new tab for better -viewing\] - ---- +```mermaid +flowchart LR + Start["Old code
Old schema"] + Initial["Old code
New schema
(both releases supported)"] + Transition["New code
New schema
(both releases supported)"] + End["New code
Finalized schema
(only new release supported)"] + Broken["Old code
Finalized schema
= broken"] + + Start -->|"initial migration (deploy)"| Initial + Initial -->|"roll code forward"| Transition + Transition -->|"transition migration"| Transition + Transition -->|"finalization migration (next deploy)"| End + Transition -->|"roll back (safe)"| Initial + Initial -->|"roll back (safe)"| Start + End -->|"roll code back"| Broken + + classDef broken fill:#f8b4b4,stroke:#c81e1e,color:#111827 + class Broken broken + style Initial fill:#dbe4e8,stroke:#94a3b8 + style Transition fill:#fffc02,color:#000000,stroke:#000000 + style End fill:#73fa79,color:#000000,stroke:#000000 +``` ### Online environments diff --git a/docs/contributing/database-migrations/edd_state_machine.jpg b/docs/contributing/database-migrations/edd_state_machine.jpg deleted file mode 100644 index 0221f8e21..000000000 Binary files a/docs/contributing/database-migrations/edd_state_machine.jpg and /dev/null differ diff --git a/docs/contributing/database-migrations/rename-column.gif b/docs/contributing/database-migrations/rename-column.gif deleted file mode 100644 index 23ab0db5e..000000000 Binary files a/docs/contributing/database-migrations/rename-column.gif and /dev/null differ diff --git a/docs/contributing/database-migrations/transitions.drawio b/docs/contributing/database-migrations/transitions.drawio deleted file mode 100644 index 0d4e0efc2..000000000 --- a/docs/contributing/database-migrations/transitions.drawio +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/contributing/database-migrations/transitions.png b/docs/contributing/database-migrations/transitions.png deleted file mode 100644 index df0a7ff3a..000000000 Binary files a/docs/contributing/database-migrations/transitions.png and /dev/null differ diff --git a/docs/contributing/diagrams.md b/docs/contributing/diagrams.md new file mode 100644 index 000000000..84618fe1b --- /dev/null +++ b/docs/contributing/diagrams.md @@ -0,0 +1,123 @@ +--- +sidebar_position: 2 +--- + +# Diagram standard + +**Audience:** Bitwarden engineers, contributors, and AI agents authoring or reading diagrams +anywhere Bitwarden documents its systems. + +## Notation + +- The keywords MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as described in + [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119). + +## The standard + +1. **Diagrams are Mermaid source text, nothing else.** As Mermaid code blocks, or, if in Confluence, + via Macro Pack's Mermaid diagram in text-input mode. +2. **Any Mermaid diagram type that fits.** +3. **A diagram lives in the doc it illustrates,** not a separate file. +4. **Every diagram carries a perspective caption:** audience, intent, and scope. +5. **A diagram answers one question at one altitude.** Anything larger requires multiple diagrams. +6. **C4 is shared vocabulary only.** No C4 tooling is adopted. +7. **A diagram is owned by whoever owns the doc it lives in.** +8. **A diagram updates with the change it depicts.** AI instruction files carry the obligation of + establishing a standing safeguard. + +## Mermaid as text (rules 1 and 2) + +Every doc host we use (except rustdoc) can render Mermaid and images cost AI readers tokens without +adding information. Use whatever Mermaid type communicates most clearly. + +Diagrams on Confluence MUST use **Macro Pack's Mermaid diagram in text-input mode**, which stores +the source inline in the page storage format. (Test for any future replacement app: +`GET /wiki/api/v2/pages/{id}?body-format=storage` must return the raw Mermaid text.) + +:::note[Note for AI agents] + +The rendered/Markdown export of a Confluence page hides the body of Macro Pack's Mermaid diagram. +Fetch the **storage format** (`GET /wiki/api/v2/pages/{id}?body-format=storage`) and read the macro +body. Text-input mode carries the source inline. + +::: + +## Context (rules 3, 4, and 5) + +A diagram communicates only in context. Rules 3, 4, and 5 establish that context: the doc supplies +the narrative, the caption states the perspective, and the one-question scope keeps the perspective +attainable. + +A diagram lives inline in the doc it illustrates because the surrounding prose explains what the +reader is looking at and why it matters. A doc that is nothing but disparate diagrams illustrates +nothing, so a catch-all diagram page does not satisfy rule 3. + +Every diagram is also a deliberate simplification: it serves an audience, answers a question, and +omits detail to stay readable. Make that simplification obvious rather than opaque with a +**perspective caption** that sits beside the diagram. Perspectives state: + +1. **Audience:** who it is for. +2. **Intent:** the question it answers. +3. **Scope:** the altitude or boundary, naming only the omissions a reader would otherwise assume + are covered. Never an exhaustive list of what is not shown. + +The perspective attaches as an italic blockquote immediately below the diagram: + +```mermaid +flowchart TB + Client[Bitwarden client] + Server[Bitwarden self hosted server] + subgraph cloud [Bitwarden cloud] + Relay[Push relay] + end + Hub[Azure Notification Hub] + Device@{shape: st-rect, label: "Bitwarden clients"} + + Client -- "1. Saves an item" --> Server + Server -- "2. Sends the push payload" --> Relay + Relay -- "3. Forwards to the device registration" --> Hub + Hub -- "4. Delivers the notification" --> Device + Device -- "5. Syncs against its own server" --> Server +``` + +> _Perspective: Executive overview of Notification system, showing how a self-hosted instance sends +> a push notification. System context level. Omits the services obfuscated by Azure Notification Hub +> and push notifications handled by SignalR within the self host context._ + +A perspective is only statable when the diagram answers one question at one altitude, since a +diagram that answers several has no single audience, intent, or scope to name. Anything larger +splits into multiple diagrams. A single system, container, or component MAY warrant several diagrams +with different perspectives. + +## C4 as shared vocabulary (rule 6) + +For architecture diagrams, describe scope and altitude with the [C4 model](https://c4model.com/)'s +vocabulary. The example above is at context level. + +| Level | Question it answers | _Typical_ home | +| ------------------ | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| **System context** | How does a system fit among the users, Bitwarden-owned systems, and external systems around it? | contributing.bitwarden.com › Architecture | +| **Container** | What deployable/runnable pieces make up one system (server, web vault, extension, SDK), and how do they talk? | contributing.bitwarden.com › Architecture | +| **Component** | What are the major parts inside one container? | The owning scope's `docs/` or README | +| **Code** | Classes/functions | **Do not diagram.** The code and API reference cover it | + +C4 is adopted as a **mental model only**. We are explicitly **NOT** adopting any C4 tooling/DSL. + +## Ownership and currency (rules 7 and 8) + +- The owner is CODEOWNERS for in-repo docs and the page's owning team on Confluence. +- Updates land in the same PR or page edit as the change the diagram depicts. A diagram known to be + wrong is deleted or updated rather than left to mislead. +- Every repo's root `CLAUDE.md` MUST carry the base documentation obligations, which cover diagrams: + when you change code that a diagram describes, update the diagram in the same change. The + doc-currency plugin in [bitwarden/ai-plugins](https://github.com/bitwarden/ai-plugins) distributes + the obligation and enforces it across every documented scope above a change. The plugin's own + documentation owns the mechanism. +- Agent-authored diagrams follow the same rules. Generated diagrams MUST carry a perspective caption + and MUST be verified against the code they depict before merge. + +## Migration + +Legacy diagrams convert when their docs are next touched: images and non-Mermaid sources in repos +become Mermaid code blocks, and Confluence attachments and images become Macro Pack's Mermaid +diagram in text-input mode. diff --git a/docusaurus.config.js b/docusaurus.config.js index 6cdecf5d6..86605ff58 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -3,9 +3,7 @@ import { themes } from "prism-react-renderer"; -async function createConfig() { - const { remarkKroki } = await import("remark-kroki"); - +function createConfig() { /** @type {import('@docusaurus/types').Config} */ const config = { title: "Bitwarden Contributing Documentation", @@ -15,6 +13,10 @@ async function createConfig() { onBrokenMarkdownLinks: "warn", favicon: "img/favicon.png", + markdown: { + mermaid: true, + }, + // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want // to replace "en" with "zh-Hans". @@ -25,6 +27,10 @@ async function createConfig() { plugins: [require.resolve("docusaurus-lunr-search")], + themes: ["@docusaurus/theme-mermaid"], + + clientModules: [require.resolve("./src/mermaid-icons.js")], + presets: [ [ "classic", @@ -36,7 +42,6 @@ async function createConfig() { // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: "https://github.com/bitwarden/contributing-docs/tree/main/", - remarkPlugins: [[remarkKroki, { server: "https://kroki.io/" }]], }, theme: { customCss: require.resolve("./src/css/custom.css"), diff --git a/package-lock.json b/package-lock.json index 1a0ae25b4..bcf0b08be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,13 @@ "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/preset-classic": "3.10.1", + "@docusaurus/theme-mermaid": "3.10.1", "@mdx-js/react": "3.1.0", + "@mermaid-js/layout-elk": "^0.1.9", "docusaurus-lunr-search": "3.6.0", "prism-react-renderer": "2.4.1", "react": "19.2.0", - "react-dom": "19.2.0", - "remark-kroki": "0.3.7" + "react-dom": "19.2.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.10.1", @@ -266,6 +267,19 @@ "node": ">= 14.0.0" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -1984,6 +1998,18 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "license": "Apache-2.0" + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -4592,6 +4618,34 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/theme-mermaid": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.10.1.tgz", + "integrity": "sha512-2gxpmln8Pc4EN1oWzshQEx2HTs67jk14v7MmgqGs8ZU7Nm8oihg+fTouof2u4vN8DtB3Fln4cDJu4UprSX1S3Q==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "mermaid": ">=11.6.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@mermaid-js/layout-elk": "^0.1.9", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@mermaid-js/layout-elk": { + "optional": true + } + } + }, "node_modules/@docusaurus/theme-search-algolia": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz", @@ -4759,6 +4813,23 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.4.tgz", + "integrity": "sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -5312,6 +5383,28 @@ "react": ">=16" } }, + "node_modules/@mermaid-js/layout-elk": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.1.9.tgz", + "integrity": "sha512-HuvaqFZBr6yT9PpWYockvKAZPJVd89yn/UjOYPxhzbZxlybL2v+2BjVCg7MVH6vRs1irUohb/s42HEdec1CCZw==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "elkjs": "^0.9.3" + }, + "peerDependencies": { + "mermaid": "^11.0.2" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.0.tgz", + "integrity": "sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==", + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.2" + } + }, "node_modules/@noble/hashes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", @@ -5920,6 +6013,259 @@ "@types/node": "*" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -5968,6 +6314,12 @@ "@types/send": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/gtag.js": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.20.tgz", @@ -6210,6 +6562,13 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -6246,6 +6605,16 @@ "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", "license": "ISC" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -8019,6 +8388,15 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -8692,66 +9070,583 @@ "postcss": "^8.4.31" } }, - "node_modules/cssnano-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", - "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", - "license": "MIT", + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", + "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" }, - "peerDependencies": { - "postcss": "^8.4.31" + "engines": { + "node": ">=12" } }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "license": "MIT", + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { - "css-tree": "~2.2.0" + "d3-array": "2 - 3" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" + "node": ">=12" } }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "license": "MIT", + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" + "d3-time": "1 - 3" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" + "node": ">=12" } }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "license": "CC0-1.0" + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, "engines": { - "node": ">= 12" + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" } }, + "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==", + "license": "MIT" + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -8913,6 +9808,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9190,6 +10094,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", @@ -9276,6 +10189,12 @@ "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", "license": "ISC" }, + "node_modules/elkjs": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", + "license": "EPL-2.0" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -9415,6 +10334,16 @@ "node": ">= 0.4" } }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -9932,29 +10861,6 @@ "node": ">=0.4.0" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -10154,18 +11060,6 @@ "node": ">=0.4.x" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10578,6 +11472,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -11692,7 +12592,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -11748,6 +12647,15 @@ "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", "license": "MIT" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -12296,11 +13204,30 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/kebab-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-2.0.2.tgz", - "integrity": "sha512-NhIP7vecGtqJfNZ85ct0yRQfx//gCJHapJCBZP6/BBcBw/U218Jw7YX7rO6TI5/cCp5dJvlIjN3vbcRTqq7nWA==", - "license": "MIT" + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } }, "node_modules/keyv": { "version": "4.5.4", @@ -12311,6 +13238,11 @@ "json-buffer": "3.0.1" } }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -12354,6 +13286,12 @@ "shell-quote": "^1.8.4" } }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -12548,6 +13486,12 @@ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -12745,15 +13689,6 @@ "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", "license": "MIT" }, - "node_modules/markdown-code-block-meta": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/markdown-code-block-meta/-/markdown-code-block-meta-0.0.2.tgz", - "integrity": "sha512-ZHoiTBgMIEP71IN5HJo3eU/7F2A1J4on8LU0bzMe7+n09oANJMKht6/VGHQmA41OK117WZ225f7Imd4IF2bokw==", - "license": "MIT", - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, "node_modules/markdown-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", @@ -12776,6 +13711,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -13291,6 +14238,48 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.16.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz", + "integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.2", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.2.0", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.3", + "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.20", + "dompurify": "^3.3.3", + "es-toolkit": "^1.45.1", + "katex": "^0.16.45", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, + "node_modules/mermaid/node_modules/uuid": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz", + "integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -15292,26 +16281,6 @@ "tslib": "^2.0.3" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, "node_modules/node-emoji": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", @@ -15327,24 +16296,6 @@ "node": ">=18" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-releases": { "version": "2.0.48", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", @@ -15675,46 +16626,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-memoize": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/p-memoize/-/p-memoize-7.1.1.tgz", - "integrity": "sha512-DZ/bONJILHkQ721hSr/E9wMz5Am/OTJ9P6LhLFo2Tu+jL8044tgc9LwHO8g4PiaYePnlVVRAJcKmgy8J9MVFrA==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0", - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/p-memoize?sponsor=1" - } - }, - "node_modules/p-memoize/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-memoize/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-queue": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", @@ -15784,6 +16695,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-manager-detector": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", + "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", + "license": "MIT" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -15911,6 +16828,12 @@ "tslib": "^2.0.3" } }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", @@ -16009,6 +16932,22 @@ "node": ">=16.0.0" } }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/postcss": { "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", @@ -18208,23 +19147,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-kroki": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/remark-kroki/-/remark-kroki-0.3.7.tgz", - "integrity": "sha512-LlIkBZ2bE2aAnMXviZBuGyo6mnxCakNJeMOA/rw9jV6CV7YhPq27r9IUogkE+xlgoF7p7OGb4vp6AnvWIdS7RQ==", - "license": "MIT", - "dependencies": { - "is-plain-obj": "^4.1.0", - "kebab-case": "^2.0.1", - "markdown-code-block-meta": "^0.0.2", - "node-fetch": "^3.3.2", - "p-memoize": "^7.1.1", - "unist-util-visit": "^5.0.0" - }, - "engines": { - "node": ">=18.0.0 || ^16.13.0" - } - }, "node_modules/remark-mdx": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", @@ -18549,6 +19471,24 @@ "dev": true, "license": "MIT" }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/rtlcss": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", @@ -18602,6 +19542,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -19484,6 +20430,12 @@ "postcss": "^8.4.31" } }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19712,7 +20664,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -19904,6 +20855,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -20569,15 +21529,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/webpack": { "version": "5.107.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", diff --git a/package.json b/package.json index d0168b6ec..3cfce3919 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,13 @@ "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/preset-classic": "3.10.1", + "@docusaurus/theme-mermaid": "3.10.1", "@mdx-js/react": "3.1.0", + "@mermaid-js/layout-elk": "0.1.9", "docusaurus-lunr-search": "3.6.0", "prism-react-renderer": "2.4.1", "react": "19.2.0", - "react-dom": "19.2.0", - "remark-kroki": "0.3.7" + "react-dom": "19.2.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "3.10.1", diff --git a/src/mermaid-icons.js b/src/mermaid-icons.js new file mode 100644 index 000000000..0199076c2 --- /dev/null +++ b/src/mermaid-icons.js @@ -0,0 +1,31 @@ +// Registers a small custom Mermaid icon pack ("bw") so flowchart icon shapes can reference +// bw:chip and bw:usb. These are the authenticator icons from the original FIDO2 diagram, kept +// inline so no external icon-pack dependency is needed. See docs/architecture/deep-dives/passkeys. +import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment"; + +const iconPack = { + prefix: "bw", + icons: { + chip: { + body: '', + left: 0, + top: 0, + width: 426, + height: 550, + }, + usb: { + body: '', + left: 0, + top: 125, + width: 465, + height: 500, + }, + }, +}; + +if (ExecutionEnvironment.canUseDOM) { + void (async () => { + const mermaid = (await import("mermaid")).default; + mermaid.registerIconPacks([{ name: "bw", icons: iconPack }]); + })(); +} diff --git a/types/remark-kroki.d.ts b/types/remark-kroki.d.ts deleted file mode 100644 index 14faa22c6..000000000 --- a/types/remark-kroki.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -// FIXME: delete this file once `remark-kroki` ships its own type definitions -// (or once `@types/remark-kroki` is published on DefinitelyTyped). Track -// upstream at https://github.com/show-docs/remark-kroki. -declare module "remark-kroki" { - export interface RemarkKrokiOptions { - server?: string; - headers?: Record; - alias?: string[]; - output?: string; - target?: "html" | "mdx3"; - } - - export function remarkKroki(options?: RemarkKrokiOptions): (tree: unknown) => Promise; -}