diff --git a/docs/docs/guides/05-type-system/02-concepts/01-schema.mdx b/docs/docs/guides/05-type-system/02-concepts/01-schema.mdx
new file mode 100644
index 0000000000..a5a76d78e8
--- /dev/null
+++ b/docs/docs/guides/05-type-system/02-concepts/01-schema.mdx
@@ -0,0 +1,144 @@
+---
+title: Schema
+tags:
+ - typescript
+ - type system
+ - type
+ - concepts
+---
+
+The schema is the primary data structure leveraged within the Strapi Type System, defining how content is structured and managed in the application.
+
+It serves several key functions:
+
+- **Representation**: At its core, a schema outlines and defines the structure of Strapi content. This is useful when dealing with features that need access to low level schema properties (_e.g. attributes, plugin options, etc..._).
+
+- **Inference**: The schema allows inferring and configuring numerous other types. This includes entities like `ContentType` or `Component`, among others.
+
+### Scope
+
+Schema types represent **loaded** schemas in the context of a Strapi server application and should be used accordingly.
+
+:::caution
+Database models and raw schema definitions (_aka schemas before being loaded by the Strapi server_) are **not** the same types and can't be used interchangeably.
+:::
+
+### Sub-Types
+
+Each box is a type that extends the base Schema interface.
+
+In between each box is text that represents the discriminant used to differentiate the subtype from others.
+
+```mermaid
+flowchart TB;
+ Schema -- "modelType: contentType" ---- ContentTypeSchema
+ Schema -- "modelType: component" ---- ComponentSchema
+ ContentTypeSchema -- "kind: collectionType" ---- CollectionTypeSchema
+ ContentTypeSchema -- "kind: singleType" ---- SingleTypeSchema
+```
+
+### Properties
+
+Schema types contain useful information that helps other types know how to interact with the Strapi content.
+
+This is facilitated through multiple properties.
+
+#### Options
+
+A set of properties used to configure the schema. It contains information on features activation among other things.
+
+This can be really useful to make the types adapt to a given schema.
+
+For instance, the document service uses the `options.draftAndPublish` property to determine whether it should add publication methods to the service type.
+
+#### Plugin Options
+
+These options provide the ability to alter or enhance the behaviour of the system based on specific values.
+
+If a plugin is enabled, it might bring functionality that can affect how types interact with each other.
+
+For example, it's possible to add or remove certain entity-service filters from the query type based on whether a plugin is enabled.
+
+#### Attributes
+
+Strongly typed schema attributes allows the Type System to infer actual entities types based on their properties.
+
+For instance, a string attribute will resolve to a primitive string in an entity, whereas a repeatable component attribute will resolve to an array of objects.
+
+### Usage
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+
+
+When designing public APIs (and in most other scenarios), it's advised to use the high-level schema types found in the `Schema` namespace.
+
+Schema definitions exported from the `Schema` namespace are targeting the dynamic types found in the public schema registries, and will dynamically adapt to the current context while extending the base Schema types.
+
+:::info
+If the public registries are empty (_e.g. types are not generated yet, not in the context of a Strapi application, ..._), schema types will fallback to their low-level definitions.
+:::
+
+```typescript
+import type { Schema } from '@strapi/strapi';
+
+declare const schema: Schema.Schema;
+declare const contentType: Schema.ContentType;
+declare const component: Schema.Component;
+
+declare function processAnySchema(schema: Schema.Schema): void;
+
+processAnySchema(schema); // ✅
+processAnySchema(contentType); // ✅
+processAnySchema(component); // ✅
+
+declare function processContentTypeSchema(schema: Schema.ContentType): void;
+
+processContentTypeSchema(schema); // ✅
+processContentTypeSchema(contentType); // ✅
+processContentTypeSchema(component); // ❌ Error, a component schema is not assignable to a content-type schema
+
+declare function processComponentSchema(schema: Schema.Component): void;
+
+processComponentSchema(schema); // ✅
+processComponentSchema(contentType); // ❌ Error, a content-type schema is not assignable to a component schema
+processComponentSchema(component); // ✅
+```
+
+
+
+Schema definitions exported from the `Struct` namespace defines the low level type representation of Strapi schemas.
+
+:::caution
+Those types can be useful when you want to validate other types against the base ones, but realistically, the public Schema types should almost always be preferred.
+:::
+
+```typescript
+import type { Struct } from '@strapi/strapi';
+
+declare const schema: Struct.Schema;
+declare const contentType: Struct.ContentTypeSchema;
+declare const component: Struct.ComponentSchema;
+
+declare function processAnySchema(schema: Struct.Schema): void;
+
+processAnySchema(schema); // ✅
+processAnySchema(contentType); // ✅
+processAnySchema(component); // ✅
+
+declare function processContentTypeSchema(schema: Struct.ContentTypeSchema): void;
+
+processContentTypeSchema(schema); // ✅
+processContentTypeSchema(contentType); // ✅
+processContentTypeSchema(component); // ❌ Error, a component schema is not assignable to a content-type schema
+
+declare function processComponentSchema(schema: Struct.ComponentSchema): void;
+
+processComponentSchema(schema); // ✅
+processComponentSchema(contentType); // ❌ Error, a content-type schema is not assignable to a component schema
+processComponentSchema(component); // ✅
+```
+
+
+
diff --git a/docs/docs/guides/05-type-system/02-concepts/02-uid.mdx b/docs/docs/guides/05-type-system/02-concepts/02-uid.mdx
new file mode 100644
index 0000000000..6d26d1c1ee
--- /dev/null
+++ b/docs/docs/guides/05-type-system/02-concepts/02-uid.mdx
@@ -0,0 +1,190 @@
+---
+title: UID
+tags:
+ - typescript
+ - type system
+ - type
+ - concepts
+toc_max_heading_level: 4
+---
+
+:::note
+On this page, **a resource** is considered as **anything that can be identified by a UID**.
+
+This includes (but is not limited to) controllers, schema, services, policies, middlewares, etc...
+:::
+
+In the Type System, UIDs play a crucial role in referencing various resources (such as schema and entities) by attaching a unique identifier.
+
+To put it simply, a UID is a unique (string) literal key used to identify, locate, or access a particular resource within the system.
+
+:::tip
+This makes it the perfect tool to index type registries or to use as a type parameter for resource-centric types.
+:::
+
+### Format
+
+A UID is composed of 3 different parts:
+
+1. A namespace ([link](#1-namespaces))
+2. A separator ([link](#2-separators))
+3. A name ([link](#3-names))
+
+#### 1. Namespaces
+
+There are two main families of namespaces:
+
+- Scoped (_aka parametrized_)
+- Non-scoped (_aka constants_)
+
+A third kind exists for component UIDs and is defined only by a dynamic category: ``.
+
+##### Scoped
+
+Scoped namespaces are defined by a base name, followed by a separator (`::`) and any string.
+
+In Strapi there are two of them:
+
+| Name | Definition | Description |
+| ------ | :---------------: | ---------------------------------------------------- |
+| API | `api::` | Represent a resource present in the `` API |
+| Plugin | `plugin::` | Represent a resource present in the `` plugin |
+
+##### Non-Scoped
+
+These namespaces are used as a simple prefix and define the origin of a resource.
+
+Strapi uses three of them to create UIDs
+
+| Name | Definition | Description |
+| ------ | :--------: | ----------------------------------------------------------------------------- |
+| Strapi | `strapi` | Represent a resource present in the core of strapi |
+| Admin | `admin` | Represent a resource present in Strapi admin |
+| Global | `global` | Rarely used (_e.g. policies or middlewares_), it represents a global resource |
+
+#### 2. Separators
+
+There are only two kind of separators:
+
+- `.` for scoped namespaces (`api::`, `plugin::`) and components (``)
+- `::` for others (`admin`, `strapi`, `global`)
+
+#### 3. Names
+
+UID names can be any alphanumeric string.
+
+:::caution
+A UID is unique for the kind of resource it's attached to, but **different resource can share the same UID**.
+
+For instance, it's completely possible to have both a `service` and a `schema` identified by `api::article.article`.
+
+Since **TypeScript is a structural type system**, it means that **different UIDs resolving to the same literal type can match each other**, thus making it possible to send a service UID to a method expecting a schema UID (if they share the same format).
+:::
+
+### Compatibility Table
+
+The following table shows, for each kind of UID, what resource they can be associated with.
+
+:::note
+ContentType and Component are referring to both the related schema and entity.
+:::
+
+| | ContentType | Component | Middleware | Policy | Controller | Service |
+| ------------------------ | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
+| `api::.` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| `plugin::.` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| `.` | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
+| `strapi::` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: |
+| `admin::` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| `global::` | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: |
+
+### Usage
+
+When referencing resource by their UID you'll need to use the `UID` namespace exported from `@strapi/types`.
+
+```typescript
+import type { UID } from '@strapi/types';
+```
+
+This namespace contains shortcuts to dynamic UID types built from the public registries so that they always adapt to the current context.
+
+:::danger
+The `UID` namespace is designed to be the main interface used by developers.
+
+Do not use the `Internal.UID` namespace except if you know what you're doing (low level extends clause, isolated internal code, etc...).
+:::
+
+#### Basic Example
+
+A common usage is to declare a function that takes a UID as a parameter.
+
+For our example, let's imagine we want to fetch an entity based on the provided resource UID.
+
+```typescript
+import type { UID, Data } from '@strapi/types';
+
+declare function fetch(uid: UID.ContentType): Data.ContentType;
+```
+
+:::tip
+To find an exhaustive list of available UID types, take a look at the [related API reference](http://foo)
+:::
+
+#### Parameter Type Inference
+
+Now let's say we want to adapt the return type of our function, so that it matches the given UID.
+
+```typescript
+fetch('api::article.article');
+// ^ this should return a Data.Entity<'api::article.article'>
+
+fetch('admin::user');
+// ^ this should return a Data.Entity<'admin::user'>
+```
+
+To do that, we'll need the function to be able to provide us with the current `uid` type based on usage.
+
+```typescript
+import type { UID, Data } from '@strapi/types';
+
+declare function fetch(uid: T): Data.ContentType;
+```
+
+So what's changed here?
+
+1. We've forced the `uid` type to be inferred upon usage and stored in a type variable called `T`.
+2. We've then re-used `T` to parametrize the `Data.ContentType` type.
+
+`fetch` will now always return the correct entity depending on which `UID` is sent.
+
+:::caution
+When writing actual code, avoid using `T` as a type variable, and always use meaningful names that will help other developers understand what the variable represents.
+
+For instance, in our example we could use `TContentTypeUID` instead of just `T`.
+:::
+
+#### Going Further
+
+It's completely possible to reference `T` in other generic parameters.
+
+Let's add the possibility to select which fields we want to return for our entity.
+
+```typescript
+import type { UID, Data, Schema } from '@strapi/types';
+
+declare function fetch>(
+ uid: T,
+ fields: F[]
+): Data.ContentType;
+```
+
+:::tip
+You may have noticed that we're using the inferred UID type (`T`) to reference both:
+
+- An entity (`Data.Entity`)
+- A schema (`Schema.AttributeNames`)
+
+This is because they share the same format and can be used interchangeably.
+
+For more information, take a look at the [format](#format) and [compatibility table](#compatibility-table) sections.
+:::
diff --git a/docs/docs/guides/05-type-system/02-concepts/03-public-registry.mdx b/docs/docs/guides/05-type-system/02-concepts/03-public-registry.mdx
new file mode 100644
index 0000000000..572eaaadf2
--- /dev/null
+++ b/docs/docs/guides/05-type-system/02-concepts/03-public-registry.mdx
@@ -0,0 +1,325 @@
+---
+title: Public Registries
+tags:
+ - typescript
+ - type system
+ - type
+ - concepts
+ - public
+toc_max_heading_level: 5
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+### Context
+
+#### Why?
+
+The Strapi Type System is designed to provide developers with a fully customizable experience.
+
+It's engineered to adapt and modify its type definitions automatically according to the context of each application and associated resources.
+
+This adaptability extends to various components such as schemas, services, controllers, and more.
+
+:::note
+See the [type system principles](../philosophy#key-principles) page for more information about the mission.
+:::
+
+#### How?
+
+To meet this requirement, the Type System employs "public registries".
+
+In simple terms, public registries are basic indexed interface definitions that are made publicly available by the types package.
+
+```typescript
+export interface MyRegistry {
+ [key: string]: GenericResourceDefinition;
+}
+```
+
+Every resource comes with its own registry that has a set of rules acting as the default state (the index).
+
+Because every registry can be augmented (publicly exported), developers have the freedom to inject their own definitions.
+
+Doing so allows Strapi APIs to respond in a way that aligns with the developers' custom definitions.
+
+:::info[Did you know?]
+The `Schema` and `UID` namespaces rely solely on public registries to infer their type definitions.
+
+This is why it's heavily encouraged to use them over their low level counter-parts.
+:::
+
+### How it works
+
+#### Architecture
+
+```mermaid
+flowchart TB;
+ %% Main node
+ ContentTypeRegistry("Content-Types Registry")
+
+ %% App
+ subgraph Application
+ %% Nodes
+ UserApp["User Application"]
+ UserSchema(["Application Types"])
+
+ %% Links
+ UserApp -- "generates" ---> UserSchema
+ end
+
+ %% Type System
+ subgraph TypesPackage["@strapi/types"]
+ %% Nodes
+ TypeSystem["Type System"]
+ Types{{Types}}
+ Registries{{Registries}}
+ UID{{UID}}
+ Schema{{Schema}}
+
+ %% Links
+ TypeSystem -- "exports" ---> Types & Registries
+ Types -- "exports" ---> UID & Schema -- "uses" ---> ContentTypeRegistry
+ Registries -- "exports" ----> ContentTypeRegistry
+ end
+
+ %% Strapi
+ subgraph StrapiPackage["@strapi/strapi"]
+ %% Nodes
+ Strapi["Strapi"]
+ APIs[["APIs"]]
+
+ %% Links
+ Strapi -- "exports" --> APIs
+ APIs -- "uses" --> Types
+ end
+
+ %% This link needs to be placed last to preserve the layout
+ UserSchema -- "augments" -----> ContentTypeRegistry
+```
+
+#### Usage
+
+##### 1. Registry Definition
+
+Creating a new registry is as simple as exporting an indexed interface from the right namespace.
+
+Let's declare the content-type schema registry.
+
+It should accept:
+
+- Content-type UIDs as keys
+- Content-type schemas as values
+
+```ts title="@strapi/types/public/registries.ts"
+import type { Internal, Struct } from '@strapi/types';
+
+export interface ContentTypeSchemas {
+ [key: Internal.UID.ContentType]: Struct.ContentTypeSchema;
+}
+```
+
+:::note
+We use low level types to define our index (`Internal`/`Struct`) to keep it as generic as possible.
+:::
+
+##### 2. Dynamic Type Definitions
+
+###### UID.ContentType
+
+To define `UID.ContentType`, we extract every key (`Internal.Registry.Keys`) from the public content-type registry (`Public.ContentTypeSchemas`) that matches with the base definition of a content-type UID (`Internal.UID.ContentType`).
+
+```ts title="@strapi/types/uid.ts"
+import type { Internal, Public } from '@strapi/types';
+
+export type ContentType = Internal.Registry.Keys<
+ Public.ContentTypeSchemas,
+ Internal.UID.ContentType
+>;
+```
+
+:::note
+Only selecting keys that extend `Internal.UID.ContentType` ensures we don't end up with manually added malformed keys, and tells the type-checker we're confident about what's in our union type.
+:::
+
+###### Schema.ContentType
+
+To declare `Schema.ContentType`, we simply query the content-type schema registry (`Public.ContentTypeSchemas`) with the provided content-type UID (`TUID`).
+
+:::note
+Since `UID.ContentType` (`TUID`) is [dynamically built based on actual keys](#uidcontenttype), we know for sure that there will be a valid corresponding schema in the registry.
+:::
+
+```ts title="@strapi/types/schema.ts"
+import type { UID, Public } from '@strapi/types';
+
+export type ContentType = Public.ContentTypeSchemas[TUID];
+```
+
+##### 3. API Design
+
+To create types for a dynamic API (_aka one that reacts to its context_), simply use dynamic type definitions such as `UID`, `Data` or `Schema`.
+
+```ts title="@strapi/core/document-service.ts"
+import type { Data, UID } from '@strapi/types';
+
+export type findOne(uid: TUID): Data.ContentType;
+```
+
+:::caution
+Remember to use dynamic type definitions (`UID`, `Data`, `Schema`) and not static ones (`Internal`, `Struct`).
+:::
+
+:::info[Reminder]
+Registries are **indexed**, which means that:
+
+- **When augmented** (_e.g. in users' applications_), they'll return **strongly typed values** that correspond to the defined types.
+- **When empty** (_e.g. in Strapi codebase_), they'll return **generic low level types** based on their index definition.
+
+
+
+ ```ts
+ import type { UID } from '@strapi/types';
+
+ const uid: UID.ContentType;
+ // ^ 'api::article.article' | 'admin::user'
+ ```
+
+
+
+ ```ts
+ import type { UID } from '@strapi/types';
+
+ const uid: UID.ContentType;
+ // ^ `admin::${string}` | `api::${string}.${string}` | `plugin::${string}.${string}` | `strapi::${string}`
+ ```
+
+
+
+:::
+
+##### 4. Type Augmentation
+
+###### Manual Augmentation
+
+It's possible to manually augment the public registries to create tailor-made experiences.
+
+```ts title="my-app/index.d.ts"
+import type { Struct } from '@strapi/strapi';
+
+interface ApiArticleArticle extends Struct.ContentTypeSchema {
+ // ...
+}
+
+declare module '@strapi/strapi' {
+ export module Public {
+ export interface ContentTypeSchemas {
+ 'api::article.article': ApiArticleArticle;
+ }
+ }
+}
+```
+
+This will force every type that depends on the `Public.ContentTypeSchemas` registry to recognize `'api::article.article'` as the only valid UID and `ApiArticleArticle` the only valid schema.
+
+:::note
+In the context of a Strapi application, developers are strongly encouraged to use types exported by `@strapi/strapi` and not `@strapi/types`.
+
+This is to allow having both an internal (`@strapi/types`) and a public (`@strapi/strapi`) types API.
+:::
+
+###### Automated Augmentation
+
+To ease the registries augmentation, Strapi offers an automated way of generating types and extending the registries.
+
+The process will generate type definitions based on the user application state (`schemas`), then augment the registry using the created types.
+
+
+
+ Generate the types once.
+
+```shell title="my-app/"
+yarn strapi ts:generate-types
+```
+
+
+
+ Start the application in dev mode, and generate types on every server restart.
+
+ Useful when working with the content-type builder.
+
+```shell title="my-app/"
+yarn develop
+```
+
+
+
+
+The generated types will automatically augment the corresponding registries.
+
+```ts title="my-app/types/generated/contentTypes.d.ts"
+import type { Struct } from '@strapi/strapi';
+
+interface ApiArticleArticle extends Struct.ContentTypeSchema {
+ // ...
+}
+
+interface AdminUser extends Struct.ContentTypeSchema {
+ // ...
+}
+
+declare module '@strapi/strapi' {
+ export module Public {
+ export interface ContentTypeSchemas {
+ 'api::article.article': ApiArticleArticle;
+ 'admin::user': AdminUser;
+ }
+ }
+}
+```
+
+---
+
+When coupling everything together, the end result is a TypeScript developer experience automatically adjusted to the current context.
+
+
+
+
+
+```ts title="my-app/src/index.ts"
+export default () => ({
+ bootstrap() {
+ strapi.findOne('ap');
+ // ^ TypeScript will autocomplete with "api::article.article"
+
+ strapi.findOne('ad');
+ // ^ TypeScript will autocomplete with "admin::user"
+
+ strapi.findOne('api::blog.blog');
+ // ^ Error, TypeScript will complain
+ }
+})
+```
+
+
+```ts title="@strapi/strapi/document-service.ts"
+import type { UID } from '@strapi/types';
+
+export const findOne(uid: TUID) {
+ // ...
+}
+
+findOne('admin::foo');
+// ^ Valid, matches 'admin::${string}'
+
+findOne('plugin::bar.bar');
+// ^ Valid, matches 'plugin::${string}.${string}'
+
+findOne('baz');
+// ^ Error, does not correspond to any content-type UID format
+```
+
+
+
+
diff --git a/docs/docs/guides/05-type-system/02-concepts/index.md b/docs/docs/guides/05-type-system/02-concepts/index.md
new file mode 100644
index 0000000000..72dde87a48
--- /dev/null
+++ b/docs/docs/guides/05-type-system/02-concepts/index.md
@@ -0,0 +1,15 @@
+---
+title: Concepts
+tags:
+ - typescript
+ - type system
+ - type
+ - concepts
+---
+
+```mdx-code-block
+import DocCardList from '@theme/DocCardList';
+import { useCurrentSidebarCategory } from '@docusaurus/theme-common';
+
+
+```
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index 62324be1c1..4316480810 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -17,6 +17,7 @@ const config = {
organizationName: 'strapi',
projectName: 'strapi',
trailingSlash: false,
+ themes: ['@docusaurus/theme-mermaid'],
// 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
@@ -25,6 +26,9 @@ const config = {
defaultLocale: 'en',
locales: ['en'],
},
+ markdown: {
+ mermaid: true,
+ },
plugins: [
() => ({
name: 'resolve-react',
diff --git a/docs/package.json b/docs/package.json
index d193eb1402..1fccf5746b 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -29,6 +29,7 @@
"@cmfcmf/docusaurus-search-local": "1.1.0",
"@docusaurus/core": "3.1.1",
"@docusaurus/preset-classic": "3.1.1",
+ "@docusaurus/theme-mermaid": "3.1.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^1.1.1",
"prism-react-renderer": "^2.1.0",
diff --git a/docs/yarn.lock b/docs/yarn.lock
index 87ad3776ef..e7cb43e697 100644
--- a/docs/yarn.lock
+++ b/docs/yarn.lock
@@ -2099,6 +2099,13 @@ __metadata:
languageName: node
linkType: hard
+"@braintree/sanitize-url@npm:^6.0.1":
+ version: 6.0.4
+ resolution: "@braintree/sanitize-url@npm:6.0.4"
+ checksum: 52de7e19df29039134e2f0fbe6d11dbc15423d18799dc5306fbc2c92d6a7bd0e6c3c079c09be99260647cc85c3ca910e2099d819965a1d8604d05e5d3f3bb358
+ languageName: node
+ linkType: hard
+
"@cmfcmf/docusaurus-search-local@npm:1.1.0":
version: 1.1.0
resolution: "@cmfcmf/docusaurus-search-local@npm:1.1.0"
@@ -2582,6 +2589,24 @@ __metadata:
languageName: node
linkType: hard
+"@docusaurus/theme-mermaid@npm:3.1.1":
+ version: 3.1.1
+ resolution: "@docusaurus/theme-mermaid@npm:3.1.1"
+ dependencies:
+ "@docusaurus/core": "npm:3.1.1"
+ "@docusaurus/module-type-aliases": "npm:3.1.1"
+ "@docusaurus/theme-common": "npm:3.1.1"
+ "@docusaurus/types": "npm:3.1.1"
+ "@docusaurus/utils-validation": "npm:3.1.1"
+ mermaid: "npm:^10.4.0"
+ tslib: "npm:^2.6.0"
+ peerDependencies:
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ checksum: 8af63823d953bc0335c5aae194084aaba8ce458becebad32607635769526e4aecd558bc22ba1b7bd2bb224ae160492b6ec122d037f2772edb786445c7feb2572
+ languageName: node
+ linkType: hard
+
"@docusaurus/theme-search-algolia@npm:3.1.1":
version: 3.1.1
resolution: "@docusaurus/theme-search-algolia@npm:3.1.1"
@@ -3269,6 +3294,29 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-scale-chromatic@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "@types/d3-scale-chromatic@npm:3.0.3"
+ checksum: cc5488af1136c3f9e28aa3c3ee2dc3e5e843c666f64360fb3870f0b8679cd2ee844edaa5a93504a9665deb98cb3c2ae2257d610c338fa8caa4a31ab6fdeb2f15
+ languageName: node
+ linkType: hard
+
+"@types/d3-scale@npm:^4.0.3":
+ version: 4.0.8
+ resolution: "@types/d3-scale@npm:4.0.8"
+ dependencies:
+ "@types/d3-time": "npm:*"
+ checksum: 376e4f2199ee6db70906651587a4521976920fa5eaa847a976c434e7a8171cbfeeab515cc510c5130b1f64fcf95b9750a7fd21dfc0a40fc3398641aa7dd4e7e2
+ languageName: node
+ linkType: hard
+
+"@types/d3-time@npm:*":
+ version: 3.0.3
+ resolution: "@types/d3-time@npm:3.0.3"
+ checksum: 4e6bf24ec422f0893747e5020592e107bb3d96764a43d5f0bff666202bd71f052c73f735b50ec66296a6efd5766ca40b6a4e8ce3bbc61217dbe9467340608c12
+ languageName: node
+ linkType: hard
+
"@types/debug@npm:^4.0.0":
version: 4.1.12
resolution: "@types/debug@npm:4.1.12"
@@ -3422,6 +3470,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/mdast@npm:^3.0.0":
+ version: 3.0.15
+ resolution: "@types/mdast@npm:3.0.15"
+ dependencies:
+ "@types/unist": "npm:^2"
+ checksum: 050a5c1383928b2688dd145382a22535e2af87dc3fd592c843abb7851bcc99893a1ee0f63be19fc4e89779387ec26a57486cfb425b016c0b2a98a17fc4a1e8b3
+ languageName: node
+ linkType: hard
+
"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.2":
version: 4.0.3
resolution: "@types/mdast@npm:4.0.3"
@@ -3632,6 +3689,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/unist@npm:^2":
+ version: 2.0.10
+ resolution: "@types/unist@npm:2.0.10"
+ checksum: e2924e18dedf45f68a5c6ccd6015cd62f1643b1b43baac1854efa21ae9e70505db94290434a23da1137d9e31eb58e54ca175982005698ac37300a1c889f6c4aa
+ languageName: node
+ linkType: hard
+
"@types/unist@npm:^3.0.0":
version: 3.0.2
resolution: "@types/unist@npm:3.0.2"
@@ -4835,6 +4899,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:7, commander@npm:^7.2.0":
+ version: 7.2.0
+ resolution: "commander@npm:7.2.0"
+ checksum: 9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d
+ languageName: node
+ linkType: hard
+
"commander@npm:^10.0.0":
version: 10.0.1
resolution: "commander@npm:10.0.1"
@@ -4856,13 +4927,6 @@ __metadata:
languageName: node
linkType: hard
-"commander@npm:^7.2.0":
- version: 7.2.0
- resolution: "commander@npm:7.2.0"
- checksum: 9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d
- languageName: node
- linkType: hard
-
"commander@npm:^8.3.0":
version: 8.3.0
resolution: "commander@npm:8.3.0"
@@ -5049,6 +5113,15 @@ __metadata:
languageName: node
linkType: hard
+"cose-base@npm:^1.0.0":
+ version: 1.0.3
+ resolution: "cose-base@npm:1.0.3"
+ dependencies:
+ layout-base: "npm:^1.0.0"
+ checksum: 52e1f4ae173738aebe14395e3f865dc10ce430156554bab52f4b8ef0c583375644348c2a226b83d97eebc7d35340919e7bc10d23a3e2fe51b853bf56f27b5da7
+ languageName: node
+ linkType: hard
+
"cosmiconfig@npm:^6.0.0":
version: 6.0.0
resolution: "cosmiconfig@npm:6.0.0"
@@ -5380,6 +5453,397 @@ __metadata:
languageName: node
linkType: hard
+"cytoscape-cose-bilkent@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "cytoscape-cose-bilkent@npm:4.1.0"
+ dependencies:
+ cose-base: "npm:^1.0.0"
+ peerDependencies:
+ cytoscape: ^3.2.0
+ checksum: 9ec2999159af62f1a251bf1e146a9a779085c4fdb1b8146596208f0097c0512fc4bffda53d3b00c87a1e8ae5024db3ebfb97162115216f5b4d024e314f4a03bb
+ languageName: node
+ linkType: hard
+
+"cytoscape@npm:^3.28.1":
+ version: 3.28.1
+ resolution: "cytoscape@npm:3.28.1"
+ dependencies:
+ heap: "npm:^0.2.6"
+ lodash: "npm:^4.17.21"
+ checksum: 3f7adf3675e26bf4e14dadf3932f68b7fe9a4aef2f5598251d57369dc86d94db587036dbef26954c5e92d8ec6a1c2a0af888dc18d9acd9b0a8a01c7eddf11775
+ languageName: node
+ linkType: hard
+
+"d3-array@npm:1 - 2":
+ version: 2.12.1
+ resolution: "d3-array@npm:2.12.1"
+ dependencies:
+ internmap: "npm:^1.0.0"
+ checksum: 9fdfb91f428915006e126090fe9aa9d5fcbecc78e925eceb32de9dfb989135f6ad940a8f1b086d0b569523679f85453c5335772aa9e6d5d41b480c2610857c7f
+ languageName: node
+ linkType: hard
+
+"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.2.0":
+ version: 3.2.4
+ resolution: "d3-array@npm:3.2.4"
+ dependencies:
+ internmap: "npm:1 - 2"
+ checksum: 5800c467f89634776a5977f6dae3f4e127d91be80f1d07e3e6e35303f9de93e6636d014b234838eea620f7469688d191b3f41207a30040aab750a63c97ec1d7c
+ languageName: node
+ linkType: hard
+
+"d3-axis@npm:3":
+ version: 3.0.0
+ resolution: "d3-axis@npm:3.0.0"
+ checksum: 15ec43ecbd4e7b606fcda60f67a522e45576dfd6aa83dff47f3e91ef6c8448841a09cd91f630b492250dcec67c6ea64463510ead5e632ff6b827aeefae1d42ad
+ languageName: node
+ linkType: hard
+
+"d3-brush@npm:3":
+ version: 3.0.0
+ resolution: "d3-brush@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-drag: "npm:2 - 3"
+ d3-interpolate: "npm:1 - 3"
+ d3-selection: "npm:3"
+ d3-transition: "npm:3"
+ checksum: fa3a461b62f0f0ee6fe41f5babf45535a0a8f6d4999f675fb1dce932ee02eff72dec14c7296af31ca15998dc0141ccf5d02aa6499363f8bf2941d90688a1d644
+ languageName: node
+ linkType: hard
+
+"d3-chord@npm:3":
+ version: 3.0.1
+ resolution: "d3-chord@npm:3.0.1"
+ dependencies:
+ d3-path: "npm:1 - 3"
+ checksum: 4febcdca4fdc8ba91fc4f7545f4b6321c440150dff80c1ebef887db07bb4200395dfebede63b257393259de07f914da10842da5ab3135e1e281e33ad153e0849
+ languageName: node
+ linkType: hard
+
+"d3-color@npm:1 - 3, d3-color@npm:3":
+ version: 3.1.0
+ resolution: "d3-color@npm:3.1.0"
+ checksum: 536ba05bfd9f4fcd6fa289b5974f5c846b21d186875684637e22bf6855e6aba93e24a2eb3712985c6af3f502fbbfa03708edb72f58142f626241a8a17258e545
+ languageName: node
+ linkType: hard
+
+"d3-contour@npm:4":
+ version: 4.0.2
+ resolution: "d3-contour@npm:4.0.2"
+ dependencies:
+ d3-array: "npm:^3.2.0"
+ checksum: 0b252267e0c3c5e97d7e0c720bd35654de99f981199f7240d7dd1acfd4e2d5bf1638829f6db486452eff9c38608efa4a6ab5a0d1525131735c011ee7be3cb4ba
+ languageName: node
+ linkType: hard
+
+"d3-delaunay@npm:6":
+ version: 6.0.4
+ resolution: "d3-delaunay@npm:6.0.4"
+ dependencies:
+ delaunator: "npm:5"
+ checksum: 4588e2872d4154daaf2c3f34fefe74e43b909cc460238a7b02823907ca6dd109f2c488c57c8551f1a2607fe4b44fdf24e3a190cea29bca70ef5606678dd9e2de
+ languageName: node
+ linkType: hard
+
+"d3-dispatch@npm:1 - 3, d3-dispatch@npm:3":
+ version: 3.0.1
+ resolution: "d3-dispatch@npm:3.0.1"
+ checksum: 2b82f41bf4ef88c2f9033dfe32815b67e2ef1c5754a74137a74c7d44d6f0d6ecfa934ac56ed8afe358f6c1f06462e8aa42ca0a388397b5b77a42721570e80487
+ languageName: node
+ linkType: hard
+
+"d3-drag@npm:2 - 3, d3-drag@npm:3":
+ version: 3.0.0
+ resolution: "d3-drag@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-selection: "npm:3"
+ checksum: 80bc689935e5a46ee92b2d7f71e1c792279382affed9fbcf46034bff3ff7d3f50cf61a874da4bdf331037292b9e7dca5c6401a605d4bb699fdcb4e0c87e176ec
+ languageName: node
+ linkType: hard
+
+"d3-dsv@npm:1 - 3, d3-dsv@npm:3":
+ version: 3.0.1
+ resolution: "d3-dsv@npm:3.0.1"
+ dependencies:
+ commander: "npm:7"
+ iconv-lite: "npm:0.6"
+ rw: "npm: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
+ checksum: a628ac42a272466940f713f310db2e5246690b22035121dc1230077070c9135fb7c9b4d260f093fcadf63b0528202a1953107448a4be3a860c4f42f50d09504d
+ languageName: node
+ linkType: hard
+
+"d3-ease@npm:1 - 3, d3-ease@npm:3":
+ version: 3.0.1
+ resolution: "d3-ease@npm:3.0.1"
+ checksum: 985d46e868494e9e6806fedd20bad712a50dcf98f357bf604a843a9f6bc17714a657c83dd762f183173dcde983a3570fa679b2bc40017d40b24163cdc4167796
+ languageName: node
+ linkType: hard
+
+"d3-fetch@npm:3":
+ version: 3.0.1
+ resolution: "d3-fetch@npm:3.0.1"
+ dependencies:
+ d3-dsv: "npm:1 - 3"
+ checksum: cd35d55f8fbb1ea1e37be362a575bb0161449957133aa5b45b9891889b2aca1dc0769c240a236736e33cd823e820a0e73fb3744582307a5d26d1df7bed0ccecb
+ languageName: node
+ linkType: hard
+
+"d3-force@npm:3":
+ version: 3.0.0
+ resolution: "d3-force@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-quadtree: "npm:1 - 3"
+ d3-timer: "npm:1 - 3"
+ checksum: 85945f8d444d78567009518f0ab54c0f0c8873eb8eb9a2ff0ab667b0f81b419e101a411415d4a2c752547ec7143f89675e8c33b8f111e55e5579a04cb7f4591c
+ languageName: node
+ linkType: hard
+
+"d3-format@npm:1 - 3, d3-format@npm:3":
+ version: 3.1.0
+ resolution: "d3-format@npm:3.1.0"
+ checksum: a0fe23d2575f738027a3db0ce57160e5a473ccf24808c1ed46d45ef4f3211076b34a18b585547d34e365e78dcc26dd4ab15c069731fc4b1c07a26bfced09ea31
+ languageName: node
+ linkType: hard
+
+"d3-geo@npm:3":
+ version: 3.1.1
+ resolution: "d3-geo@npm:3.1.1"
+ dependencies:
+ d3-array: "npm:2.5.0 - 3"
+ checksum: dc5e980330d891dabf92869b98871b05ca2021c64d7ef253bcfd4f2348839ad33576fba474baecc2def86ebd3d943a11d93c0af26be0a2694f5bd59824838133
+ languageName: node
+ linkType: hard
+
+"d3-hierarchy@npm:3":
+ version: 3.1.2
+ resolution: "d3-hierarchy@npm:3.1.2"
+ checksum: 497b79dc6c35e28b21e8a7b94db92876abd1d4ec082d9803a07ea8964e55b0e71c511a21489363a36f1456f069adb8ff7d33c633678730d6ae961ed350b27733
+ languageName: node
+ linkType: hard
+
+"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3":
+ version: 3.0.1
+ resolution: "d3-interpolate@npm:3.0.1"
+ dependencies:
+ d3-color: "npm:1 - 3"
+ checksum: 988d66497ef5c190cf64f8c80cd66e1e9a58c4d1f8932d776a8e3ae59330291795d5a342f5a97602782ccbef21a5df73bc7faf1f0dc46a5145ba6243a82a0f0e
+ languageName: node
+ linkType: hard
+
+"d3-path@npm:1":
+ version: 1.0.9
+ resolution: "d3-path@npm:1.0.9"
+ checksum: 6ce1747837ea2a449d9ea32e169a382978ab09a4805eb408feb6bbc12cb5f5f6ce29aefc252dd9a815d420f4813d672f75578b78b3bbaf7811f54d8c7f93fd11
+ languageName: node
+ linkType: hard
+
+"d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "d3-path@npm:3.1.0"
+ checksum: 8e97a9ab4930a05b18adda64cf4929219bac913a5506cf8585631020253b39309549632a5cbeac778c0077994442ddaaee8316ee3f380e7baf7566321b84e76a
+ languageName: node
+ linkType: hard
+
+"d3-polygon@npm:3":
+ version: 3.0.1
+ resolution: "d3-polygon@npm:3.0.1"
+ checksum: c4fa2ed19dcba13fd341815361d27e64597aa0d38d377e401e1353c4acbe8bd73c0afb3e49a1cf4119fadc3651ec8073d06aa6d0e34e664c868d071e58912cd1
+ languageName: node
+ linkType: hard
+
+"d3-quadtree@npm:1 - 3, d3-quadtree@npm:3":
+ version: 3.0.1
+ resolution: "d3-quadtree@npm:3.0.1"
+ checksum: 1915b6a7b031fc312f9af61947072db9468c5a2b03837f6a90b38fdaebcd0ea17a883bffd94d16b8a6848e81711a06222f7d39f129386ef1850297219b8d32ba
+ languageName: node
+ linkType: hard
+
+"d3-random@npm:3":
+ version: 3.0.1
+ resolution: "d3-random@npm:3.0.1"
+ checksum: 9f41d6ca3a1826cea8d88392917b5039504337d442a4d1357c870fa3031701e60209a2689a6ddae7df8fca824383d038c957eb545bc49a7428c71aaf3b11f56f
+ languageName: node
+ linkType: hard
+
+"d3-sankey@npm:^0.12.3":
+ version: 0.12.3
+ resolution: "d3-sankey@npm:0.12.3"
+ dependencies:
+ d3-array: "npm:1 - 2"
+ d3-shape: "npm:^1.2.0"
+ checksum: d5c679135a26d435e9970de3fc0778c6ef5c911f0c878b246939517b57a8daa2e2db6ef99318a0dad16e6079e4b89ef9166f1f661d8d247637875b764628094d
+ languageName: node
+ linkType: hard
+
+"d3-scale-chromatic@npm:3":
+ version: 3.1.0
+ resolution: "d3-scale-chromatic@npm:3.1.0"
+ dependencies:
+ d3-color: "npm:1 - 3"
+ d3-interpolate: "npm:1 - 3"
+ checksum: 25df6a7c621b9171df8b2225e98e41c0a6bcac4de02deb4807280b31116e8f495c5ac93301796098ee5b698cb690154e8138d90d72fd1fe36744c60e02a3d8c4
+ languageName: node
+ linkType: hard
+
+"d3-scale@npm:4":
+ version: 4.0.2
+ resolution: "d3-scale@npm:4.0.2"
+ dependencies:
+ d3-array: "npm:2.10.0 - 3"
+ d3-format: "npm:1 - 3"
+ d3-interpolate: "npm:1.2.0 - 3"
+ d3-time: "npm:2.1.1 - 3"
+ d3-time-format: "npm:2 - 4"
+ checksum: e2dc4243586eae2a0fdf91de1df1a90d51dfacb295933f0ca7e9184c31203b01436bef69906ad40f1100173a5e6197ae753cb7b8a1a8fcfda43194ea9cad6493
+ languageName: node
+ linkType: hard
+
+"d3-selection@npm:2 - 3, d3-selection@npm:3":
+ version: 3.0.0
+ resolution: "d3-selection@npm:3.0.0"
+ checksum: 0e5acfd305b31628b7be5009ba7303d84bb34817a88ed4dde9c8bd9c23528573fc5272f89fc04e5be03d2cbf5441a248d7274aaf55a8ef3dad46e16333d72298
+ languageName: node
+ linkType: hard
+
+"d3-shape@npm:3":
+ version: 3.2.0
+ resolution: "d3-shape@npm:3.2.0"
+ dependencies:
+ d3-path: "npm:^3.1.0"
+ checksum: 2e861f4d4781ee8abd85d2b435f848d667479dcf01a4e0db3a06600a5bdeddedb240f88229ec7b3bf7fa300c2b3526faeaf7e75f9a24dbf4396d3cc5358ff39d
+ languageName: node
+ linkType: hard
+
+"d3-shape@npm:^1.2.0":
+ version: 1.3.7
+ resolution: "d3-shape@npm:1.3.7"
+ dependencies:
+ d3-path: "npm:1"
+ checksum: 1e40fdcfdc8edc9c53a77a6aaea2dbf31bf06df12ebd66cc8d91f76bbde753049ad21dfee0577f7dc5d0a4468554ede4783f6df7d809e291745334dba977c09e
+ languageName: node
+ linkType: hard
+
+"d3-time-format@npm:2 - 4, d3-time-format@npm:4":
+ version: 4.1.0
+ resolution: "d3-time-format@npm:4.1.0"
+ dependencies:
+ d3-time: "npm:1 - 3"
+ checksum: ffc0959258fbb90e3890bfb31b43b764f51502b575e87d0af2c85b85ac379120d246914d07fca9f533d1bcedc27b2841d308a00fd64848c3e2cad9eff5c9a0aa
+ languageName: node
+ linkType: hard
+
+"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3":
+ version: 3.1.0
+ resolution: "d3-time@npm:3.1.0"
+ dependencies:
+ d3-array: "npm:2 - 3"
+ checksum: c110bed295ce63e8180e45b82a9b0ba114d5f33ff315871878f209c1a6d821caa505739a2b07f38d1396637155b8e7372632dacc018e11fbe8ceef58f6af806d
+ languageName: node
+ linkType: hard
+
+"d3-timer@npm:1 - 3, d3-timer@npm:3":
+ version: 3.0.1
+ resolution: "d3-timer@npm:3.0.1"
+ checksum: 004128602bb187948d72c7dc153f0f063f38ac7a584171de0b45e3a841ad2e17f1e40ad396a4af9cce5551b6ab4a838d5246d23492553843d9da4a4050a911e2
+ languageName: node
+ linkType: hard
+
+"d3-transition@npm:2 - 3, d3-transition@npm:3":
+ version: 3.0.1
+ resolution: "d3-transition@npm:3.0.1"
+ dependencies:
+ d3-color: "npm:1 - 3"
+ d3-dispatch: "npm:1 - 3"
+ d3-ease: "npm:1 - 3"
+ d3-interpolate: "npm:1 - 3"
+ d3-timer: "npm:1 - 3"
+ peerDependencies:
+ d3-selection: 2 - 3
+ checksum: 02571636acb82f5532117928a87fe25de68f088c38ab4a8b16e495f0f2d08a3fd2937eaebdefdfcf7f1461545524927d2632d795839b88d2e4c71e387aaaffac
+ languageName: node
+ linkType: hard
+
+"d3-zoom@npm:3":
+ version: 3.0.0
+ resolution: "d3-zoom@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-drag: "npm:2 - 3"
+ d3-interpolate: "npm:1 - 3"
+ d3-selection: "npm:2 - 3"
+ d3-transition: "npm:2 - 3"
+ checksum: 0e6e5c14e33c4ecdff311a900dd037dea407734f2dd2818988ed6eae342c1799e8605824523678bd404f81e37824cc588f62dbde46912444c89acc7888036c6b
+ languageName: node
+ linkType: hard
+
+"d3@npm:^7.4.0, d3@npm:^7.8.2":
+ version: 7.9.0
+ resolution: "d3@npm:7.9.0"
+ dependencies:
+ d3-array: "npm:3"
+ d3-axis: "npm:3"
+ d3-brush: "npm:3"
+ d3-chord: "npm:3"
+ d3-color: "npm:3"
+ d3-contour: "npm:4"
+ d3-delaunay: "npm:6"
+ d3-dispatch: "npm:3"
+ d3-drag: "npm:3"
+ d3-dsv: "npm:3"
+ d3-ease: "npm:3"
+ d3-fetch: "npm:3"
+ d3-force: "npm:3"
+ d3-format: "npm:3"
+ d3-geo: "npm:3"
+ d3-hierarchy: "npm:3"
+ d3-interpolate: "npm:3"
+ d3-path: "npm:3"
+ d3-polygon: "npm:3"
+ d3-quadtree: "npm:3"
+ d3-random: "npm:3"
+ d3-scale: "npm:4"
+ d3-scale-chromatic: "npm:3"
+ d3-selection: "npm:3"
+ d3-shape: "npm:3"
+ d3-time: "npm:3"
+ d3-time-format: "npm:4"
+ d3-timer: "npm:3"
+ d3-transition: "npm:3"
+ d3-zoom: "npm:3"
+ checksum: b0b418996bdf279b01f5c7a0117927f9ad3e833c9ce4657550ce6f6ace70b70cf829c4144b01df0be5a0f716d4e5f15ab0cadc5ff1ce1561d7be29ac86493d83
+ languageName: node
+ linkType: hard
+
+"dagre-d3-es@npm:7.0.10":
+ version: 7.0.10
+ resolution: "dagre-d3-es@npm:7.0.10"
+ dependencies:
+ d3: "npm:^7.8.2"
+ lodash-es: "npm:^4.17.21"
+ checksum: 09f56dd337cc7d0620d50f20913308d5e8aaffafb0b188a69b0d8ff87915599586224694be3f8d93bd8c383858d358c0140493a11a0df2508de959a4658952c2
+ languageName: node
+ linkType: hard
+
+"dayjs@npm:^1.11.7":
+ version: 1.11.10
+ resolution: "dayjs@npm:1.11.10"
+ checksum: 27e8f5bc01c0a76f36c656e62ab7f08c2e7b040b09e613cd4844abf03fb258e0350f0a83b02c887b84d771c1f11e092deda0beef8c6df2a1afbc3f6c1fade279
+ languageName: node
+ linkType: hard
+
"debounce@npm:^1.2.1":
version: 1.2.1
resolution: "debounce@npm:1.2.1"
@@ -5489,6 +5953,15 @@ __metadata:
languageName: node
linkType: hard
+"delaunator@npm:5":
+ version: 5.0.1
+ resolution: "delaunator@npm:5.0.1"
+ dependencies:
+ robust-predicates: "npm:^3.0.2"
+ checksum: c378a55138d81d471a7214635b1a2c5e74f8ee06582f558df72f0c7c82c25868599ce9a18fb25a245c6c03cab886d17fb574681c78371b539dd069818703f53a
+ languageName: node
+ linkType: hard
+
"delegates@npm:^1.0.0":
version: 1.0.0
resolution: "delegates@npm:1.0.0"
@@ -5566,6 +6039,13 @@ __metadata:
languageName: node
linkType: hard
+"diff@npm:^5.0.0":
+ version: 5.2.0
+ resolution: "diff@npm:5.2.0"
+ checksum: 01b7b440f83a997350a988e9d2f558366c0f90f15be19f4aa7f1bb3109a4e153dfc3b9fbf78e14ea725717017407eeaa2271e3896374a0181e8f52445740846d
+ languageName: node
+ linkType: hard
+
"dir-glob@npm:^3.0.1":
version: 3.0.1
resolution: "dir-glob@npm:3.0.1"
@@ -5599,6 +6079,7 @@ __metadata:
"@docusaurus/core": "npm:3.1.1"
"@docusaurus/module-type-aliases": "npm:3.1.1"
"@docusaurus/preset-classic": "npm:3.1.1"
+ "@docusaurus/theme-mermaid": "npm:3.1.1"
"@mdx-js/react": "npm:^3.0.0"
clsx: "npm:^1.1.1"
docusaurus-plugin-typedoc: "npm:0.22.0"
@@ -5677,6 +6158,13 @@ __metadata:
languageName: node
linkType: hard
+"dompurify@npm:^3.0.5":
+ version: 3.1.0
+ resolution: "dompurify@npm:3.1.0"
+ checksum: a8788d3510b0a5e26ae8f1beb3f079be63f417be0f7259918c273bd53f9b9eab50a0708e065caff9904ae97895cc4a7d4c66a1076021a9be0685389ad8ae4d2d
+ languageName: node
+ linkType: hard
+
"domutils@npm:^2.5.2, domutils@npm:^2.8.0":
version: 2.8.0
resolution: "domutils@npm:2.8.0"
@@ -5753,6 +6241,13 @@ __metadata:
languageName: node
linkType: hard
+"elkjs@npm:^0.9.0":
+ version: 0.9.2
+ resolution: "elkjs@npm:0.9.2"
+ checksum: 7b4c8f73e7dd61588ae772d6cc8fa68bc631f59ec9fbc81862d0bf1331c5242f9374bb2668f17c94db00d38d3114d418b14042b77c4755016e4598c2bd79bfac
+ languageName: node
+ linkType: hard
+
"emoji-regex@npm:^8.0.0":
version: 8.0.0
resolution: "emoji-regex@npm:8.0.0"
@@ -6887,6 +7382,13 @@ __metadata:
languageName: node
linkType: hard
+"heap@npm:^0.2.6":
+ version: 0.2.7
+ resolution: "heap@npm:0.2.7"
+ checksum: 6374f6510af79bf47f2cfcee265bf608e6ed2b2694875974d1cb5654ddc98af05347dcf3a42ee9a7de318b576022d6f4d00fe06fa65a4a65c4c60638375eabfe
+ languageName: node
+ linkType: hard
+
"history@npm:^4.9.0":
version: 4.10.1
resolution: "history@npm:4.10.1"
@@ -7167,7 +7669,7 @@ __metadata:
languageName: node
linkType: hard
-"iconv-lite@npm:^0.6.2":
+"iconv-lite@npm:0.6, iconv-lite@npm:^0.6.2":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
dependencies:
@@ -7307,6 +7809,20 @@ __metadata:
languageName: node
linkType: hard
+"internmap@npm:1 - 2":
+ version: 2.0.3
+ resolution: "internmap@npm:2.0.3"
+ checksum: 873e0e7fcfe32f999aa0997a0b648b1244508e56e3ea6b8259b5245b50b5eeb3853fba221f96692bd6d1def501da76c32d64a5cb22a0b26cdd9b445664f805e0
+ languageName: node
+ linkType: hard
+
+"internmap@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "internmap@npm:1.0.1"
+ checksum: 429cb9e28f393f10c73a826d71ba9e359711b7e42345bd684aba708f43b8139ce90f09b15abbf977a981474ac61615294854e5b9520d3f65187d0f6a2ff27665
+ languageName: node
+ linkType: hard
+
"interpret@npm:^1.0.0":
version: 1.4.0
resolution: "interpret@npm:1.4.0"
@@ -7793,6 +8309,17 @@ __metadata:
languageName: node
linkType: hard
+"katex@npm:^0.16.9":
+ version: 0.16.10
+ resolution: "katex@npm:0.16.10"
+ dependencies:
+ commander: "npm:^8.3.0"
+ bin:
+ katex: cli.js
+ checksum: 367034012311c695791de4553b3e4c7a9f36d126a0cae17b97f4e8832ced2559961f9fa6d39e0116e1374013e12ac8af159eb014678f06b4acf5e547292ea3e5
+ languageName: node
+ linkType: hard
+
"keyv@npm:^4.5.3":
version: 4.5.4
resolution: "keyv@npm:4.5.4"
@@ -7802,6 +8329,13 @@ __metadata:
languageName: node
linkType: hard
+"khroma@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "khroma@npm:2.1.0"
+ checksum: a195e317bf6f3a1cba98df2677bf9bf6d14195ee0b1c3e5bc20a542cd99652682f290c196a8963956d87aed4ad65ac0bc8a15d75cddf00801fdafd148e01a5d2
+ languageName: node
+ linkType: hard
+
"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2":
version: 6.0.3
resolution: "kind-of@npm:6.0.3"
@@ -7816,6 +8350,13 @@ __metadata:
languageName: node
linkType: hard
+"kleur@npm:^4.0.3":
+ version: 4.1.5
+ resolution: "kleur@npm:4.1.5"
+ checksum: 44d84cc4eedd4311099402ef6d4acd9b2d16e08e499d6ef3bb92389bd4692d7ef09e35248c26e27f98acac532122acb12a1bfee645994ae3af4f0a37996da7df
+ languageName: node
+ linkType: hard
+
"latest-version@npm:^7.0.0":
version: 7.0.0
resolution: "latest-version@npm:7.0.0"
@@ -7835,6 +8376,13 @@ __metadata:
languageName: node
linkType: hard
+"layout-base@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "layout-base@npm:1.0.2"
+ checksum: 34504e61e4770e563cf49d4a56c8c10f1da0fb452cff89a652118783189c642ebc86a300d97cbc247e59a9c1eb06a2d419982f7dd10e8eedcab2414bc46d32f8
+ languageName: node
+ linkType: hard
+
"leven@npm:^3.1.0":
version: 3.1.0
resolution: "leven@npm:3.1.0"
@@ -7909,6 +8457,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash-es@npm:^4.17.21":
+ version: 4.17.21
+ resolution: "lodash-es@npm:4.17.21"
+ checksum: 03f39878ea1e42b3199bd3f478150ab723f93cc8730ad86fec1f2804f4a07c6e30deaac73cad53a88e9c3db33348bb8ceeb274552390e7a75d7849021c02df43
+ languageName: node
+ linkType: hard
+
"lodash.debounce@npm:^4.0.8":
version: 4.0.8
resolution: "lodash.debounce@npm:4.0.8"
@@ -8092,6 +8647,26 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-from-markdown@npm:^1.3.0":
+ version: 1.3.1
+ resolution: "mdast-util-from-markdown@npm:1.3.1"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ "@types/unist": "npm:^2.0.0"
+ decode-named-character-reference: "npm:^1.0.0"
+ mdast-util-to-string: "npm:^3.1.0"
+ micromark: "npm:^3.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^1.0.0"
+ micromark-util-decode-string: "npm:^1.0.0"
+ micromark-util-normalize-identifier: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ unist-util-stringify-position: "npm:^3.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 1d334a54ddd6481ec4acf64c2c537b6463bc5113ba5a408f65c228dcc302d46837352814f11307af0f8b51dd7e4a0b887ce692e4d30ff31ff9d578b8ca82810b
+ languageName: node
+ linkType: hard
+
"mdast-util-from-markdown@npm:^2.0.0":
version: 2.0.0
resolution: "mdast-util-from-markdown@npm:2.0.0"
@@ -8308,6 +8883,15 @@ __metadata:
languageName: node
linkType: hard
+"mdast-util-to-string@npm:^3.1.0":
+ version: 3.2.0
+ resolution: "mdast-util-to-string@npm:3.2.0"
+ dependencies:
+ "@types/mdast": "npm:^3.0.0"
+ checksum: fafe201c12a0d412a875fe8540bf70b4360f3775fb7f0d19403ba7b59e50f74f730e3b405c72ad940bc8a3ec1ba311f76dfca61c4ce585dce1ccda2168ec244f
+ languageName: node
+ linkType: hard
+
"mdast-util-to-string@npm:^4.0.0":
version: 4.0.0
resolution: "mdast-util-to-string@npm:4.0.0"
@@ -8361,6 +8945,34 @@ __metadata:
languageName: node
linkType: hard
+"mermaid@npm:^10.4.0":
+ version: 10.9.0
+ resolution: "mermaid@npm:10.9.0"
+ dependencies:
+ "@braintree/sanitize-url": "npm:^6.0.1"
+ "@types/d3-scale": "npm:^4.0.3"
+ "@types/d3-scale-chromatic": "npm:^3.0.0"
+ cytoscape: "npm:^3.28.1"
+ cytoscape-cose-bilkent: "npm:^4.1.0"
+ d3: "npm:^7.4.0"
+ d3-sankey: "npm:^0.12.3"
+ dagre-d3-es: "npm:7.0.10"
+ dayjs: "npm:^1.11.7"
+ dompurify: "npm:^3.0.5"
+ elkjs: "npm:^0.9.0"
+ katex: "npm:^0.16.9"
+ khroma: "npm:^2.0.0"
+ lodash-es: "npm:^4.17.21"
+ mdast-util-from-markdown: "npm:^1.3.0"
+ non-layered-tidy-tree-layout: "npm:^2.0.2"
+ stylis: "npm:^4.1.3"
+ ts-dedent: "npm:^2.2.0"
+ uuid: "npm:^9.0.0"
+ web-worker: "npm:^1.2.0"
+ checksum: 458c2dec312271c1e48b6dc8ba9f8a50209e3cb633fcce2ee5d9f75a02ca0a85de28bd95d1096ac2106aecd7c33637d4084d0aca02ba9d25b3495e60d76796a2
+ languageName: node
+ linkType: hard
+
"methods@npm:~1.1.2":
version: 1.1.2
resolution: "methods@npm:1.1.2"
@@ -8368,6 +8980,30 @@ __metadata:
languageName: node
linkType: hard
+"micromark-core-commonmark@npm:^1.0.1":
+ version: 1.1.0
+ resolution: "micromark-core-commonmark@npm:1.1.0"
+ dependencies:
+ decode-named-character-reference: "npm:^1.0.0"
+ micromark-factory-destination: "npm:^1.0.0"
+ micromark-factory-label: "npm:^1.0.0"
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-factory-title: "npm:^1.0.0"
+ micromark-factory-whitespace: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-chunked: "npm:^1.0.0"
+ micromark-util-classify-character: "npm:^1.0.0"
+ micromark-util-html-tag-name: "npm:^1.0.0"
+ micromark-util-normalize-identifier: "npm:^1.0.0"
+ micromark-util-resolve-all: "npm:^1.0.0"
+ micromark-util-subtokenize: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.1"
+ uvu: "npm:^0.5.0"
+ checksum: a73694d223ac8baad8ff00597a3c39d61f5b32bfd56fe4bcf295d75b2a4e8e67fb2edbfc7cc287b362b9d7f6d24fce08b6a7e8b5b155d79bcc1e4d9b2756ffb2
+ languageName: node
+ linkType: hard
+
"micromark-core-commonmark@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-core-commonmark@npm:2.0.0"
@@ -8588,6 +9224,17 @@ __metadata:
languageName: node
linkType: hard
+"micromark-factory-destination@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-factory-destination@npm:1.1.0"
+ dependencies:
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 9e2b5fb5fedbf622b687e20d51eb3d56ae90c0e7ecc19b37bd5285ec392c1e56f6e21aa7cfcb3c01eda88df88fe528f3acb91a5f57d7f4cba310bc3cd7f824fa
+ languageName: node
+ linkType: hard
+
"micromark-factory-destination@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-factory-destination@npm:2.0.0"
@@ -8599,6 +9246,18 @@ __metadata:
languageName: node
linkType: hard
+"micromark-factory-label@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-factory-label@npm:1.1.0"
+ dependencies:
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: fcda48f1287d9b148c562c627418a2ab759cdeae9c8e017910a0cba94bb759a96611e1fc6df33182e97d28fbf191475237298983bb89ef07d5b02464b1ad28d5
+ languageName: node
+ linkType: hard
+
"micromark-factory-label@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-factory-label@npm:2.0.0"
@@ -8647,6 +9306,18 @@ __metadata:
languageName: node
linkType: hard
+"micromark-factory-title@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-factory-title@npm:1.1.0"
+ dependencies:
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 4432d3dbc828c81f483c5901b0c6591a85d65a9e33f7d96ba7c3ae821617a0b3237ff5faf53a9152d00aaf9afb3a9f185b205590f40ed754f1d9232e0e9157b1
+ languageName: node
+ linkType: hard
+
"micromark-factory-title@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-factory-title@npm:2.0.0"
@@ -8659,6 +9330,18 @@ __metadata:
languageName: node
linkType: hard
+"micromark-factory-whitespace@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-factory-whitespace@npm:1.1.0"
+ dependencies:
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: ef0fa682c7d593d85a514ee329809dee27d10bc2a2b65217d8ef81173e33b8e83c549049764b1ad851adfe0a204dec5450d9d20a4ca8598f6c94533a73f73fcd
+ languageName: node
+ linkType: hard
+
"micromark-factory-whitespace@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-factory-whitespace@npm:2.0.0"
@@ -8691,6 +9374,15 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-chunked@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-chunked@npm:1.1.0"
+ dependencies:
+ micromark-util-symbol: "npm:^1.0.0"
+ checksum: c435bde9110cb595e3c61b7f54c2dc28ee03e6a57fa0fc1e67e498ad8bac61ee5a7457a2b6a73022ddc585676ede4b912d28dcf57eb3bd6951e54015e14dc20b
+ languageName: node
+ linkType: hard
+
"micromark-util-chunked@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-chunked@npm:2.0.0"
@@ -8700,6 +9392,17 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-classify-character@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-classify-character@npm:1.1.0"
+ dependencies:
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 8499cb0bb1f7fb946f5896285fcca65cd742f66cd3e79ba7744792bd413ec46834f932a286de650349914d02e822946df3b55d03e6a8e1d245d1ddbd5102e5b0
+ languageName: node
+ linkType: hard
+
"micromark-util-classify-character@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-classify-character@npm:2.0.0"
@@ -8711,6 +9414,16 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-combine-extensions@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-combine-extensions@npm:1.1.0"
+ dependencies:
+ micromark-util-chunked: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ checksum: ee78464f5d4b61ccb437850cd2d7da4d690b260bca4ca7a79c4bb70291b84f83988159e373b167181b6716cb197e309bc6e6c96a68cc3ba9d50c13652774aba9
+ languageName: node
+ linkType: hard
+
"micromark-util-combine-extensions@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-combine-extensions@npm:2.0.0"
@@ -8721,6 +9434,15 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-decode-numeric-character-reference@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-decode-numeric-character-reference@npm:1.1.0"
+ dependencies:
+ micromark-util-symbol: "npm:^1.0.0"
+ checksum: 4733fe75146e37611243f055fc6847137b66f0cde74d080e33bd26d0408c1d6f44cabc984063eee5968b133cb46855e729d555b9ff8d744652262b7b51feec73
+ languageName: node
+ linkType: hard
+
"micromark-util-decode-numeric-character-reference@npm:^2.0.0":
version: 2.0.1
resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.1"
@@ -8730,6 +9452,18 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-decode-string@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-decode-string@npm:1.1.0"
+ dependencies:
+ decode-named-character-reference: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ checksum: f1625155db452f15aa472918499689ba086b9c49d1322a08b22bfbcabe918c61b230a3002c8bc3ea9b1f52ca7a9bb1c3dd43ccb548c7f5f8b16c24a1ae77a813
+ languageName: node
+ linkType: hard
+
"micromark-util-decode-string@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-decode-string@npm:2.0.0"
@@ -8742,6 +9476,13 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-encode@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-encode@npm:1.1.0"
+ checksum: 4ef29d02b12336918cea6782fa87c8c578c67463925221d4e42183a706bde07f4b8b5f9a5e1c7ce8c73bb5a98b261acd3238fecd152e6dd1cdfa2d1ae11b60a0
+ languageName: node
+ linkType: hard
+
"micromark-util-encode@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-encode@npm:2.0.0"
@@ -8765,6 +9506,13 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-html-tag-name@npm:^1.0.0":
+ version: 1.2.0
+ resolution: "micromark-util-html-tag-name@npm:1.2.0"
+ checksum: ccf0fa99b5c58676dc5192c74665a3bfd1b536fafaf94723bd7f31f96979d589992df6fcf2862eba290ef18e6a8efb30ec8e1e910d9f3fc74f208871e9f84750
+ languageName: node
+ linkType: hard
+
"micromark-util-html-tag-name@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-html-tag-name@npm:2.0.0"
@@ -8772,6 +9520,15 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-normalize-identifier@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-normalize-identifier@npm:1.1.0"
+ dependencies:
+ micromark-util-symbol: "npm:^1.0.0"
+ checksum: 8655bea41ffa4333e03fc22462cb42d631bbef9c3c07b625fd852b7eb442a110f9d2e5902a42e65188d85498279569502bf92f3434a1180fc06f7c37edfbaee2
+ languageName: node
+ linkType: hard
+
"micromark-util-normalize-identifier@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-normalize-identifier@npm:2.0.0"
@@ -8781,6 +9538,15 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-resolve-all@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-resolve-all@npm:1.1.0"
+ dependencies:
+ micromark-util-types: "npm:^1.0.0"
+ checksum: 1ce6c0237cd3ca061e76fae6602cf95014e764a91be1b9f10d36cb0f21ca88f9a07de8d49ab8101efd0b140a4fbfda6a1efb72027ab3f4d5b54c9543271dc52c
+ languageName: node
+ linkType: hard
+
"micromark-util-resolve-all@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-resolve-all@npm:2.0.0"
@@ -8790,6 +9556,17 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-sanitize-uri@npm:^1.0.0":
+ version: 1.2.0
+ resolution: "micromark-util-sanitize-uri@npm:1.2.0"
+ dependencies:
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-encode: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ checksum: 0d024100d95ffb88bf75f3360e305b545c1eb745430959b8633f7aa93f37ec401fc7094c90c97298409a9e30d94d53b895bae224e1bb966bea114976cfa0fd48
+ languageName: node
+ linkType: hard
+
"micromark-util-sanitize-uri@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-sanitize-uri@npm:2.0.0"
@@ -8801,6 +9578,18 @@ __metadata:
languageName: node
linkType: hard
+"micromark-util-subtokenize@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "micromark-util-subtokenize@npm:1.1.0"
+ dependencies:
+ micromark-util-chunked: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.0"
+ uvu: "npm:^0.5.0"
+ checksum: 075a1db6ea586d65827d3eead33dbfc520c4e43659c93fcd8fd82f44a7b75cfe61dcde967a3dfcc2ffd999347440ba5aa6698e65a04f3fc627e13e9f12a1a910
+ languageName: node
+ linkType: hard
+
"micromark-util-subtokenize@npm:^2.0.0":
version: 2.0.0
resolution: "micromark-util-subtokenize@npm:2.0.0"
@@ -8827,7 +9616,7 @@ __metadata:
languageName: node
linkType: hard
-"micromark-util-types@npm:^1.0.0":
+"micromark-util-types@npm:^1.0.0, micromark-util-types@npm:^1.0.1":
version: 1.1.0
resolution: "micromark-util-types@npm:1.1.0"
checksum: 287ac5de4a3802bb6f6c3842197c294997a488db1c0486e03c7a8e674d9eb7720c17dda1bcb814814b8343b338c4826fcbc0555f3e75463712a60dcdb53a028e
@@ -8841,6 +9630,31 @@ __metadata:
languageName: node
linkType: hard
+"micromark@npm:^3.0.0":
+ version: 3.2.0
+ resolution: "micromark@npm:3.2.0"
+ dependencies:
+ "@types/debug": "npm:^4.0.0"
+ debug: "npm:^4.0.0"
+ decode-named-character-reference: "npm:^1.0.0"
+ micromark-core-commonmark: "npm:^1.0.1"
+ micromark-factory-space: "npm:^1.0.0"
+ micromark-util-character: "npm:^1.0.0"
+ micromark-util-chunked: "npm:^1.0.0"
+ micromark-util-combine-extensions: "npm:^1.0.0"
+ micromark-util-decode-numeric-character-reference: "npm:^1.0.0"
+ micromark-util-encode: "npm:^1.0.0"
+ micromark-util-normalize-identifier: "npm:^1.0.0"
+ micromark-util-resolve-all: "npm:^1.0.0"
+ micromark-util-sanitize-uri: "npm:^1.0.0"
+ micromark-util-subtokenize: "npm:^1.0.0"
+ micromark-util-symbol: "npm:^1.0.0"
+ micromark-util-types: "npm:^1.0.1"
+ uvu: "npm:^0.5.0"
+ checksum: 560a4a501efc3859d622461aaa9345fb95b99a2f34d3d3f2a775ab04de1dd857cb0f642083a6b28ab01bd817f5f0741a1be9857fd702f45e04a3752927a66719
+ languageName: node
+ linkType: hard
+
"micromark@npm:^4.0.0":
version: 4.0.0
resolution: "micromark@npm:4.0.0"
@@ -9086,6 +9900,13 @@ __metadata:
languageName: node
linkType: hard
+"mri@npm:^1.1.0":
+ version: 1.2.0
+ resolution: "mri@npm:1.2.0"
+ checksum: 6775a1d2228bb9d191ead4efc220bd6be64f943ad3afd4dcb3b3ac8fc7b87034443f666e38805df38e8d047b29f910c3cc7810da0109af83e42c82c73bd3f6bc
+ languageName: node
+ linkType: hard
+
"mrmime@npm:^2.0.0":
version: 2.0.0
resolution: "mrmime@npm:2.0.0"
@@ -9212,6 +10033,13 @@ __metadata:
languageName: node
linkType: hard
+"non-layered-tidy-tree-layout@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "non-layered-tidy-tree-layout@npm:2.0.2"
+ checksum: 615b4da455a4ed761cc1563b126450c92f14d2d92c75cfd861fec495557a48768c5bf3012f080c8e58ecb093bfd2268a636515963a1e769f5a7029d057fa169a
+ languageName: node
+ linkType: hard
+
"nopt@npm:^6.0.0":
version: 6.0.0
resolution: "nopt@npm:6.0.0"
@@ -11033,6 +11861,13 @@ __metadata:
languageName: node
linkType: hard
+"robust-predicates@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "robust-predicates@npm:3.0.2"
+ checksum: 88bd7d45a6b89e88da2631d4c111aaaf0443de4d7078e9ab7f732245790a3645cf79bf91882a9740dbc959cf56ba75d5dced5bf2259410f8b6de19fd240cd08c
+ languageName: node
+ linkType: hard
+
"rtl-detect@npm:^1.0.4":
version: 1.0.4
resolution: "rtl-detect@npm:1.0.4"
@@ -11063,6 +11898,22 @@ __metadata:
languageName: node
linkType: hard
+"rw@npm:1":
+ version: 1.3.3
+ resolution: "rw@npm:1.3.3"
+ checksum: e90985d64777a00f4ab5f8c0bfea2fb5645c6bda5238840afa339c8a4f86f776e8ce83731155643a7425a0b27ce89077dab27b2f57519996ba4d2fe54cac1941
+ languageName: node
+ linkType: hard
+
+"sade@npm:^1.7.3":
+ version: 1.8.1
+ resolution: "sade@npm:1.8.1"
+ dependencies:
+ mri: "npm:^1.1.0"
+ checksum: 1c67ba03c94083e0ae307ff5564ecb86c2104c0f558042fdaa40ea0054f91a63a9783f14069870f2f784336adabb70f90f22a84dc457b5a25e859aaadefe0910
+ languageName: node
+ linkType: hard
+
"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1":
version: 5.1.2
resolution: "safe-buffer@npm:5.1.2"
@@ -11770,6 +12621,13 @@ __metadata:
languageName: node
linkType: hard
+"stylis@npm:^4.1.3":
+ version: 4.3.1
+ resolution: "stylis@npm:4.3.1"
+ checksum: 20b04044397c5c69e4b9f00b037159ba82b602c61d45f26d8def08577fd6ddc4b2853d86818548c1b404d29194a99b6495cca1733880afc845533ced843cb266
+ languageName: node
+ linkType: hard
+
"supports-color@npm:^5.3.0":
version: 5.5.0
resolution: "supports-color@npm:5.5.0"
@@ -11978,6 +12836,13 @@ __metadata:
languageName: node
linkType: hard
+"ts-dedent@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "ts-dedent@npm:2.2.0"
+ checksum: 93ed8f7878b6d5ed3c08d99b740010eede6bccfe64bce61c5a4da06a2c17d6ddbb80a8c49c2d15251de7594a4f93ffa21dd10e7be75ef66a4dc9951b4a94e2af
+ languageName: node
+ linkType: hard
+
"tslib@npm:^2.0.3":
version: 2.4.0
resolution: "tslib@npm:2.4.0"
@@ -12212,6 +13077,15 @@ __metadata:
languageName: node
linkType: hard
+"unist-util-stringify-position@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "unist-util-stringify-position@npm:3.0.3"
+ dependencies:
+ "@types/unist": "npm:^2.0.0"
+ checksum: 07913e4fd77fe57d95f8b2f771354f97a29082229c1ad14ceedce6bbc77b2d784ca8296563335471cdca97915e548204bd6f098ea5b808b822b4b54087662cfb
+ languageName: node
+ linkType: hard
+
"unist-util-stringify-position@npm:^4.0.0":
version: 4.0.0
resolution: "unist-util-stringify-position@npm:4.0.0"
@@ -12369,6 +13243,29 @@ __metadata:
languageName: node
linkType: hard
+"uuid@npm:^9.0.0":
+ version: 9.0.1
+ resolution: "uuid@npm:9.0.1"
+ bin:
+ uuid: dist/bin/uuid
+ checksum: 9d0b6adb72b736e36f2b1b53da0d559125ba3e39d913b6072f6f033e0c87835b414f0836b45bcfaf2bdf698f92297fea1c3cc19b0b258bc182c9c43cc0fab9f2
+ languageName: node
+ linkType: hard
+
+"uvu@npm:^0.5.0":
+ version: 0.5.6
+ resolution: "uvu@npm:0.5.6"
+ dependencies:
+ dequal: "npm:^2.0.0"
+ diff: "npm:^5.0.0"
+ kleur: "npm:^4.0.3"
+ sade: "npm:^1.7.3"
+ bin:
+ uvu: bin.js
+ checksum: 66ba25afc6732249877f9f4f8b6146f3aaa97538c51cf498f55825d602c33dbb903e02c7e1547cbca6bdfbb609e07eb7ea758b5156002ac2dd5072f00606f8d9
+ languageName: node
+ linkType: hard
+
"value-equal@npm:^1.0.1":
version: 1.0.1
resolution: "value-equal@npm:1.0.1"
@@ -12454,6 +13351,13 @@ __metadata:
languageName: node
linkType: hard
+"web-worker@npm:^1.2.0":
+ version: 1.3.0
+ resolution: "web-worker@npm:1.3.0"
+ checksum: 9dd89763997a7fa4c50128bed088137775c6033cc2aead24fd82e8292991bb1d3ffc672b47df16eed86c9268d2bf230d5bb3e0d06f41a7b3c0c4c36abf4c1ba7
+ languageName: node
+ linkType: hard
+
"webpack-bundle-analyzer@npm:^4.9.0":
version: 4.10.1
resolution: "webpack-bundle-analyzer@npm:4.10.1"
diff --git a/packages/core/admin/server/src/services/permission/permissions-manager/sanitize.ts b/packages/core/admin/server/src/services/permission/permissions-manager/sanitize.ts
index fa1d5a5a2e..e441d7fae0 100644
--- a/packages/core/admin/server/src/services/permission/permissions-manager/sanitize.ts
+++ b/packages/core/admin/server/src/services/permission/permissions-manager/sanitize.ts
@@ -155,7 +155,7 @@ export default ({ action, ability, model }: any) => {
traverseEntity(omitHiddenFields, ctx),
// Remove not allowed fields (RBAC)
traverseEntity(removeDisallowedFields(permittedFields), ctx),
- // Remove roles from createdBy & updateBy fields
+ // Remove roles from createdBy & updatedBy fields
omitCreatorRoles
);
};
diff --git a/packages/core/content-manager/admin/src/history/components/VersionHeader.tsx b/packages/core/content-manager/admin/src/history/components/VersionHeader.tsx
index 9830db9f7f..382bae4af1 100644
--- a/packages/core/content-manager/admin/src/history/components/VersionHeader.tsx
+++ b/packages/core/content-manager/admin/src/history/components/VersionHeader.tsx
@@ -45,18 +45,18 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
const mainFieldValue = version.data[mainField];
- const getBackLink = (): To => {
+ const getNextNavigation = (): To => {
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
if (collectionType === COLLECTION_TYPES) {
return {
- pathname: `../${collectionType}/${version.contentType}/${version.relatedDocumentId}`,
+ pathname: `/content-manager/${collectionType}/${version.contentType}/${version.relatedDocumentId}`,
search: pluginsQueryParams,
};
}
return {
- pathname: `../${collectionType}/${version.contentType}`,
+ pathname: `/content-manager/${collectionType}/${version.contentType}`,
search: pluginsQueryParams,
};
};
@@ -64,16 +64,17 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
const handleRestore = async () => {
try {
const response = await restoreVersion({
+ documentId: version.relatedDocumentId,
+ collectionType,
params: {
versionId: version.id,
- documentId: version.relatedDocumentId,
contentType: version.contentType,
},
body: { contentType: version.contentType },
});
if ('data' in response) {
- navigate(`/content-manager/${collectionType}/${slug}/${response.data.data?.documentId}`);
+ navigate(getNextNavigation());
toggleNotification({
type: 'success',
@@ -137,7 +138,7 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
startIcon={}
as={NavLink}
// @ts-expect-error - types are not inferred correctly through the as prop.
- to={getBackLink()}
+ to={getNextNavigation()}
>
{formatMessage({
id: 'global.back',
diff --git a/packages/core/content-manager/admin/src/history/components/tests/VersionHeader.test.tsx b/packages/core/content-manager/admin/src/history/components/tests/VersionHeader.test.tsx
index 2d281caa9f..8c1bce3ebb 100644
--- a/packages/core/content-manager/admin/src/history/components/tests/VersionHeader.test.tsx
+++ b/packages/core/content-manager/admin/src/history/components/tests/VersionHeader.test.tsx
@@ -80,7 +80,7 @@ describe('VersionHeader', () => {
const backLink = screen.getByRole('link', { name: 'Back' });
expect(backLink).toHaveAttribute(
'href',
- '/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr'
+ '/content-manager/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr'
);
});
@@ -111,7 +111,7 @@ describe('VersionHeader', () => {
const backLink = screen.getByRole('link', { name: 'Back' });
expect(backLink).toHaveAttribute(
'href',
- '/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr?plugins[i18n][locale]=en'
+ '/content-manager/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr?plugins[i18n][locale]=en'
);
});
@@ -158,7 +158,10 @@ describe('VersionHeader', () => {
expect(await screen.findByText('Test Title (homepage)')).toBeInTheDocument();
const backLink = screen.getByRole('link', { name: 'Back' });
- expect(backLink).toHaveAttribute('href', '/single-types/api::homepage.homepage');
+ expect(backLink).toHaveAttribute(
+ 'href',
+ '/content-manager/single-types/api::homepage.homepage'
+ );
});
it('should display the correct title and subtitle for a localized entry', async () => {
@@ -185,7 +188,7 @@ describe('VersionHeader', () => {
const backLink = screen.getByRole('link', { name: 'Back' });
expect(backLink).toHaveAttribute(
'href',
- '/single-types/api::homepage.homepage?plugins[i18n][locale]=en'
+ '/content-manager/single-types/api::homepage.homepage?plugins[i18n][locale]=en'
);
});
});
diff --git a/packages/core/content-manager/admin/src/history/services/historyVersion.ts b/packages/core/content-manager/admin/src/history/services/historyVersion.ts
index c54e7bdbb4..6c780a22bb 100644
--- a/packages/core/content-manager/admin/src/history/services/historyVersion.ts
+++ b/packages/core/content-manager/admin/src/history/services/historyVersion.ts
@@ -1,9 +1,17 @@
+import { Data } from '@strapi/types';
+
import {
GetHistoryVersions,
RestoreHistoryVersion,
} from '../../../../shared/contracts/history-versions';
+import { COLLECTION_TYPES } from '../../constants/collections';
import { contentManagerApi } from '../../services/api';
+interface RestoreVersion extends RestoreHistoryVersion.Request {
+ documentId: Data.ID;
+ collectionType?: string;
+}
+
const historyVersionsApi = contentManagerApi.injectEndpoints({
endpoints: (builder) => ({
getHistoryVersions: builder.query<
@@ -21,23 +29,27 @@ const historyVersionsApi = contentManagerApi.injectEndpoints({
},
providesTags: ['HistoryVersion'],
}),
- restoreVersion: builder.mutation(
- {
- query({ params, body }) {
- return {
- url: `/content-manager/history-versions/${params.versionId}/restore`,
- method: 'PUT',
- data: body,
- };
- },
- invalidatesTags: (_res, _error, { params }) => {
- return [
- 'HistoryVersion',
- { type: 'Document', id: `${params.contentType}_${params.documentId}` },
- ];
- },
- }
- ),
+ restoreVersion: builder.mutation({
+ query({ params, body }) {
+ return {
+ url: `/content-manager/history-versions/${params.versionId}/restore`,
+ method: 'PUT',
+ data: body,
+ };
+ },
+ invalidatesTags: (_res, _error, { documentId, collectionType, params }) => {
+ return [
+ 'HistoryVersion',
+ {
+ type: 'Document',
+ id:
+ collectionType === COLLECTION_TYPES
+ ? `${params.contentType}_${documentId}`
+ : params.contentType,
+ },
+ ];
+ },
+ }),
}),
});
diff --git a/packages/core/content-manager/server/src/history/controllers/__tests__/history-version.test.ts b/packages/core/content-manager/server/src/history/controllers/__tests__/history-version.test.ts
deleted file mode 100644
index 465f079113..0000000000
--- a/packages/core/content-manager/server/src/history/controllers/__tests__/history-version.test.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { createHistoryVersionController } from '../history-version';
-
-const mockFindVersionsPage = jest.fn();
-
-// History utils
-jest.mock('../../utils', () => ({
- getService: jest.fn((_strapi, name) => {
- if (name === 'history') {
- return {
- findVersionsPage: mockFindVersionsPage,
- };
- }
- }),
-}));
-
-// Content Manager utils
-jest.mock('../../../utils', () => ({
- getService: jest.fn((name) => {
- if (name === 'permission-checker') {
- return {
- create: jest.fn(() => ({
- cannot: {
- read: jest.fn(() => false),
- },
- sanitizeQuery: jest.fn((query) => query),
- })),
- };
- }
- }),
-}));
-
-describe('History version controller', () => {
- beforeEach(() => {
- mockFindVersionsPage.mockClear();
- });
-
- describe('findMany', () => {
- it('should require contentType and documentId for collection types', () => {
- const ctx = {
- state: {
- userAbility: {},
- },
- query: {},
- };
-
- const historyVersionController = createHistoryVersionController({
- // @ts-expect-error - we're not mocking the entire strapi object
- strapi: { getModel: jest.fn(() => ({ kind: 'collectionType' })) },
- });
-
- // @ts-expect-error partial context
- expect(historyVersionController.findMany(ctx)).rejects.toThrow(
- /contentType and documentId are required/
- );
- expect(mockFindVersionsPage).not.toHaveBeenCalled();
- });
-
- it('should require contentType for single types', () => {
- const ctx = {
- state: {
- userAbility: {},
- },
- query: {},
- };
-
- const historyVersionController = createHistoryVersionController({
- // @ts-expect-error - we're not mocking the entire strapi object
- strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
- });
-
- // @ts-expect-error partial context
- expect(historyVersionController.findMany(ctx)).rejects.toThrow(/contentType is required/);
- expect(mockFindVersionsPage).not.toHaveBeenCalled();
- });
- });
-
- it('should call findVersionsPage for collection types', async () => {
- const ctx = {
- state: {
- userAbility: {},
- },
- query: {
- documentId: 'document-id',
- contentType: 'api::test.test',
- },
- };
-
- mockFindVersionsPage.mockResolvedValueOnce({
- results: [{ id: 'history-version-id' }],
- pagination: {
- page: 1,
- pageSize: 20,
- pageCount: 1,
- total: 0,
- },
- });
-
- const historyVersionController = createHistoryVersionController({
- // @ts-expect-error - we're not mocking the entire strapi object
- strapi: { getModel: jest.fn(() => ({ kind: 'collectionType' })) },
- });
-
- // @ts-expect-error partial context
- const response = await historyVersionController.findMany(ctx);
-
- expect(mockFindVersionsPage).toHaveBeenCalled();
- expect(response.data.length).toBe(1);
- expect(response.meta.pagination).toBeDefined();
- });
-
- it('should call findVersionsPage for single types', async () => {
- const ctx = {
- state: {
- userAbility: {},
- },
- query: {
- contentType: 'api::test.test',
- },
- };
-
- mockFindVersionsPage.mockResolvedValueOnce({
- results: [{ id: 'history-version-id' }],
- pagination: {
- page: 1,
- pageSize: 20,
- pageCount: 1,
- total: 0,
- },
- });
-
- const historyVersionController = createHistoryVersionController({
- // @ts-expect-error - we're not mocking the entire strapi object
- strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
- });
-
- // @ts-expect-error partial context
- const response = await historyVersionController.findMany(ctx);
-
- expect(mockFindVersionsPage).toHaveBeenCalled();
- expect(response.data.length).toBe(1);
- expect(response.meta.pagination).toBeDefined();
- });
-
- it('applies pagination params', async () => {
- const ctx = {
- state: {
- userAbility: {},
- },
- query: {
- contentType: 'api::test.test',
- },
- };
-
- const historyVersionController = createHistoryVersionController({
- // @ts-expect-error - we're not mocking the entire strapi object
- strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
- });
-
- /**
- * Applies default pagination params
- */
- mockFindVersionsPage.mockResolvedValueOnce({
- results: [],
- pagination: {
- page: 1,
- pageSize: 20,
- },
- });
- // @ts-expect-error partial context
- const mockResponse = await historyVersionController.findMany(ctx);
- expect(mockFindVersionsPage).toHaveBeenCalledWith(
- expect.objectContaining({
- page: 1,
- pageSize: 20,
- })
- );
- expect(mockResponse.meta.pagination.page).toBe(1);
- expect(mockResponse.meta.pagination.pageSize).toBe(20);
-
- /**
- * Prevents invalid pagination params
- */
- mockFindVersionsPage.mockResolvedValueOnce({
- results: [],
- pagination: {},
- });
- // @ts-expect-error partial context
- await historyVersionController.findMany({
- ...ctx,
- query: { ...ctx.query, page: '-1', pageSize: '1000' },
- });
- expect(mockFindVersionsPage).toHaveBeenCalledWith(
- expect.objectContaining({
- page: 1,
- pageSize: 20,
- })
- );
- });
-});
diff --git a/packages/core/content-manager/server/src/history/controllers/history-version.ts b/packages/core/content-manager/server/src/history/controllers/history-version.ts
index 3bf50a5b63..4e0e6ce042 100644
--- a/packages/core/content-manager/server/src/history/controllers/history-version.ts
+++ b/packages/core/content-manager/server/src/history/controllers/history-version.ts
@@ -37,13 +37,13 @@ const createHistoryVersionController = ({ strapi }: { strapi: Core.Strapi }) =>
return {
async findMany(ctx) {
const contentTypeUid = ctx.query.contentType as UID.ContentType;
- const isSingleType = strapi.getModel(contentTypeUid).kind === 'singleType';
+ const isSingleType = strapi.getModel(contentTypeUid)?.kind === 'singleType';
if (isSingleType && !contentTypeUid) {
throw new errors.ForbiddenError('contentType is required');
}
- if (!contentTypeUid && !ctx.query.documentId) {
+ if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
throw new errors.ForbiddenError('contentType and documentId are required');
}
@@ -68,7 +68,15 @@ const createHistoryVersionController = ({ strapi }: { strapi: Core.Strapi }) =>
...getValidPagination({ page: params.page, pageSize: params.pageSize }),
});
- return { data: results, meta: { pagination } };
+ return {
+ data: await Promise.all(
+ results.map(async (result) => ({
+ ...result,
+ data: await permissionChecker.sanitizeOutput(result.data),
+ }))
+ ),
+ meta: { pagination },
+ };
},
async restoreVersion(ctx) {
diff --git a/packages/core/content-manager/server/src/history/services/history.ts b/packages/core/content-manager/server/src/history/services/history.ts
index 730a716853..75ba2cc309 100644
--- a/packages/core/content-manager/server/src/history/services/history.ts
+++ b/packages/core/content-manager/server/src/history/services/history.ts
@@ -47,6 +47,9 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
};
const localesService = strapi.plugin('i18n')?.service('locales');
+
+ const getDefaultLocale = async () => (localesService ? localesService.getDefaultLocale() : null);
+
const getLocaleDictionary = async () => {
if (!localesService) return {};
@@ -163,8 +166,9 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
? { documentId: result.documentId, locale: context.params?.locale }
: { documentId: context.params.documentId, locale: context.params?.locale };
- const defaultLocale = localesService ? await localesService.getDefaultLocale() : null;
+ const defaultLocale = await getDefaultLocale();
const locale = documentContext.locale || defaultLocale;
+
const document = await strapi.documents(contentTypeUid).findOne({
documentId: documentContext.documentId,
locale,
@@ -251,6 +255,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
results: HistoryVersions.HistoryVersionDataResponse[];
pagination: HistoryVersions.Pagination;
}> {
+ const locale = params.locale || (await getDefaultLocale());
const [{ results, pagination }, localeDictionary] = await Promise.all([
query.findPage({
...params,
@@ -258,7 +263,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
$and: [
{ contentType: params.contentType },
...(params.documentId ? [{ relatedDocumentId: params.documentId }] : []),
- ...(params.locale ? [{ locale: params.locale }] : []),
+ ...(locale ? [{ locale }] : []),
],
},
populate: ['createdBy'],
@@ -497,6 +502,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
const data = omit(['id', ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
const restoredDocument = await strapi.documents(version.contentType).update({
documentId: version.relatedDocumentId,
+ locale: version.locale,
data,
});
diff --git a/packages/core/content-manager/shared/contracts/history-versions.ts b/packages/core/content-manager/shared/contracts/history-versions.ts
index 5ce87944b2..e724e88a1c 100644
--- a/packages/core/content-manager/shared/contracts/history-versions.ts
+++ b/packages/core/content-manager/shared/contracts/history-versions.ts
@@ -16,7 +16,7 @@ export interface CreateHistoryVersion {
componentsSchemas: Record<`${string}.${string}`, Struct.SchemaAttributes>;
}
-interface Locale {
+export interface Locale {
name: string;
code: string;
}
@@ -82,7 +82,6 @@ export declare namespace RestoreHistoryVersion {
export interface Request {
params: {
versionId: Data.ID;
- documentId: Data.ID;
contentType: UID.ContentType;
};
body: {
diff --git a/packages/utils/upgrade/resources/codemods/5.0.0/entity-service-document-service.code.ts b/packages/utils/upgrade/resources/codemods/5.0.0/entity-service-document-service.code.ts
index b7fef3fda1..f940091602 100644
--- a/packages/utils/upgrade/resources/codemods/5.0.0/entity-service-document-service.code.ts
+++ b/packages/utils/upgrade/resources/codemods/5.0.0/entity-service-document-service.code.ts
@@ -142,12 +142,39 @@ const objectParam_10 = [...objectParam_10_2];
strapi.entityService.findOne(...[...objectParam_10]);
+Case: find, create, update, delete with entityId as first argument
+
+strapi.entityService.findMany(uid, {
+ fields: ["id", "name", "description"],
+ populate: ["author", "comments"],
+ publicationState: "preview",
+});
+
+strapi.entityService.create(uid, {
+ data: {
+ name: "John Doe",
+ age: 30,
+ },
+});
+
+strapi.entityService.update(uid, entityId, {
+ data: {
+ name: "John Doe",
+ age: 30,
+ },
+});
+
+strapi.entityService.delete(uid, entityId);
+strapi.entityService.findOne(uid, entityId);
+
*/
-const movedFunctions = ['findOne', 'find', 'count', 'create', 'update', 'delete'];
+const movedFunctions = ['findOne', 'findMany', 'count', 'create', 'update', 'delete'];
+
+const functionsWithEntityId = ['findOne', 'update', 'delete'];
const transformDeclaration = (path: ASTPath, name: any, j: JSCodeshift) => {
- const declaration = findClosesDeclaration(path, name, j);
+ const declaration = findClosestDeclaration(path, name, j);
if (!declaration) {
return;
@@ -222,7 +249,7 @@ const transformObjectParam = (path: ASTPath, expression: ObjectExpression,
break;
}
case j.Identifier.check(prop.value): {
- const declaration = findClosesDeclaration(path, prop.value.name, j);
+ const declaration = findClosestDeclaration(path, prop.value.name, j);
if (!declaration) {
return;
@@ -253,7 +280,7 @@ const transformObjectParam = (path: ASTPath, expression: ObjectExpression,
});
};
-const findClosesDeclaration = (path: ASTPath, name: string, j) => {
+const findClosestDeclaration = (path: ASTPath, name: string, j) => {
// find Identifier declaration
const scope = path.scope.lookup(name);
@@ -318,7 +345,7 @@ const transform: Transform = (file, api) => {
case j.Identifier.check(arg.argument): {
const identifier = arg.argument;
- const declaration = findClosesDeclaration(path, identifier.name, j);
+ const declaration = findClosestDeclaration(path, identifier.name, j);
if (!declaration) {
return arg;
@@ -351,6 +378,42 @@ const transform: Transform = (file, api) => {
const [docUID, ...rest] = resolvedArgs;
+ // function with entityId as first argument
+ if (
+ j.Identifier.check(path.value.callee.property) &&
+ functionsWithEntityId.includes(path.value.callee.property.name)
+ ) {
+ rest.splice(0, 1);
+
+ // in case no extra params are passed in the function e.g delete(uid, entityId)
+ if (rest.length === 0) {
+ rest.push(
+ j.objectExpression.from({
+ properties: [],
+ })
+ );
+ }
+
+ const params = rest[0];
+
+ const placeholder = j.objectProperty(j.identifier('documentId'), j.literal('__TODO__'));
+
+ // add documentId to params with a placeholder
+ if (j.ObjectExpression.check(params)) {
+ params.properties.unshift(placeholder);
+ } else if (j.Identifier.check(params)) {
+ const declaration = findClosestDeclaration(path, params.name, j);
+
+ if (!declaration) {
+ return;
+ }
+
+ if (j.ObjectExpression.check(declaration.init)) {
+ declaration.init.properties.unshift(placeholder);
+ }
+ }
+ }
+
path.value.arguments.forEach((arg) => {
transformElement(path, arg, j);
});
diff --git a/tests/api/core/content-manager/content-manager/history/history.test.api.ts b/tests/api/core/content-manager/content-manager/history/history.test.api.ts
new file mode 100644
index 0000000000..da4deff607
--- /dev/null
+++ b/tests/api/core/content-manager/content-manager/history/history.test.api.ts
@@ -0,0 +1,442 @@
+import { createStrapiInstance } from 'api-tests/strapi';
+import { createAuthRequest } from 'api-tests/request';
+import { createUtils, describeOnCondition } from 'api-tests/utils';
+import { createTestBuilder } from 'api-tests/builder';
+
+const edition = process.env.STRAPI_DISABLE_EE === 'true' ? 'CE' : 'EE';
+
+const collectionTypeUid = 'api::product.product';
+const collectionTypeModel = {
+ draftAndPublish: true,
+ singularName: 'product',
+ pluralName: 'products',
+ displayName: 'Product',
+ kind: 'collectionType',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ attributes: {
+ name: {
+ type: 'string',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ },
+ description: {
+ type: 'string',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ },
+ },
+};
+
+const singleTypeUid = 'api::homepage.homepage';
+const singleTypeModel = {
+ draftAndPublish: true,
+ singularName: 'homepage',
+ pluralName: 'homepages',
+ displayName: 'Homepage',
+ kind: 'singleType',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ attributes: {
+ title: {
+ type: 'string',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ },
+ subtitle: {
+ type: 'string',
+ pluginOptions: {
+ i18n: {
+ localized: true,
+ },
+ },
+ },
+ },
+};
+
+interface CreateEntryArgs {
+ uid: string;
+ data: Record;
+ isCollectionType?: boolean;
+}
+
+interface UpdateEntryArgs extends CreateEntryArgs {
+ documentId?: string;
+ locale?: string;
+}
+
+describeOnCondition(edition === 'EE')('History API', () => {
+ const builder = createTestBuilder();
+ let strapi;
+ let rq;
+ let collectionTypeDocumentId;
+ let singleTypeDocumentId;
+
+ const createEntry = async ({ uid, data, isCollectionType = true }: CreateEntryArgs) => {
+ const type = isCollectionType ? 'collection-types' : 'single-types';
+
+ const { body } = await rq({
+ method: 'POST',
+ url: `/content-manager/${type}/${uid}`,
+ body: data,
+ });
+
+ return body;
+ };
+
+ const updateEntry = async ({ uid, documentId, data, locale }: UpdateEntryArgs) => {
+ const type = documentId ? 'collection-types' : 'single-types';
+ const params = documentId ? `${type}/${uid}/${documentId}` : `${type}/${uid}`;
+
+ const { body } = await rq({
+ method: 'PUT',
+ url: `/content-manager/${params}`,
+ body: data,
+ qs: { locale },
+ });
+
+ return body;
+ };
+
+ const createUserAndReq = async (
+ userName: string,
+ permissions: { action: string; subject: string }[]
+ ) => {
+ const utils = createUtils(strapi);
+ const role = await utils.createRole({
+ name: `role-${userName}`,
+ description: `Role with restricted permissions for ${userName}`,
+ });
+
+ const rolePermissions = await utils.assignPermissionsToRole(role.id, permissions);
+ Object.assign(role, { permissions: rolePermissions });
+
+ const user = await utils.createUser({
+ firstname: userName,
+ lastname: 'User',
+ email: `${userName}.user@strapi.io`,
+ roles: [role.id],
+ });
+
+ const rq = await createAuthRequest({ strapi, userInfo: user });
+
+ return rq;
+ };
+
+ beforeAll(async () => {
+ await builder.addContentTypes([collectionTypeModel, singleTypeModel]).build();
+
+ strapi = await createStrapiInstance();
+ rq = await createAuthRequest({ strapi });
+
+ // Create another locale
+ const localeService = strapi.plugin('i18n').service('locales');
+ await localeService.create({ code: 'fr', name: 'French' });
+
+ // Create a collection type to create an initial history version
+ const collectionType = await createEntry({
+ uid: collectionTypeUid,
+ data: {
+ name: 'Product 1',
+ },
+ });
+
+ // Update the single type to create an initial history version
+ const singleType = await updateEntry({
+ uid: singleTypeUid,
+ data: {
+ title: 'Welcome',
+ },
+ isCollectionType: false,
+ });
+ // Set the documentIds to test
+ collectionTypeDocumentId = collectionType.data.documentId;
+ singleTypeDocumentId = singleType.data.documentId;
+
+ // Update to create history versions for entries in different locales
+ await Promise.all([
+ updateEntry({
+ documentId: collectionTypeDocumentId,
+ uid: collectionTypeUid,
+ data: {
+ description: 'Hello',
+ },
+ }),
+ updateEntry({
+ documentId: collectionTypeDocumentId,
+ uid: collectionTypeUid,
+ locale: 'fr',
+ data: {
+ name: 'Produit 1',
+ },
+ }),
+ updateEntry({
+ documentId: collectionTypeDocumentId,
+ uid: collectionTypeUid,
+ locale: 'fr',
+ data: {
+ description: 'Coucou',
+ },
+ }),
+ updateEntry({
+ uid: singleTypeUid,
+ data: {
+ description: 'Wow, amazing!',
+ },
+ isCollectionType: false,
+ }),
+ updateEntry({
+ uid: singleTypeUid,
+ data: {
+ title: 'Bienvenue',
+ },
+ isCollectionType: false,
+ locale: 'fr',
+ }),
+ updateEntry({
+ uid: singleTypeUid,
+ data: {
+ description: 'Super',
+ },
+ isCollectionType: false,
+ locale: 'fr',
+ }),
+ ]);
+ });
+
+ afterAll(async () => {
+ await strapi.destroy();
+ await builder.cleanup();
+ });
+
+ describe('Find many history versions', () => {
+ test('A collection type throws with invalid query params', async () => {
+ const noDocumentId = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${collectionTypeUid}`,
+ });
+
+ const noContentTypeUid = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?documentId=${collectionTypeDocumentId}`,
+ });
+
+ expect(noDocumentId.statusCode).toBe(403);
+ expect(noContentTypeUid.statusCode).toBe(403);
+ });
+
+ test('A single type throws with invalid query params', async () => {
+ const singleTypeNoContentTypeUid = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/`,
+ });
+
+ expect(singleTypeNoContentTypeUid.statusCode).toBe(403);
+ });
+
+ test('Throws without read permissions', async () => {
+ const restrictedRq = await createUserAndReq('restricted', []);
+ const res = await restrictedRq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}`,
+ });
+
+ expect(res.statusCode).toBe(403);
+ });
+
+ test('A collection type finds many versions in the default locale', async () => {
+ const collectionType = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}`,
+ });
+
+ expect(collectionType.statusCode).toBe(200);
+ expect(collectionType.body.data).toHaveLength(2);
+ expect(collectionType.body.data[0].relatedDocumentId).toBe(collectionTypeDocumentId);
+ expect(collectionType.body.data[1].relatedDocumentId).toBe(collectionTypeDocumentId);
+ expect(collectionType.body.data[0].locale.code).toBe('en');
+ expect(collectionType.body.data[1].locale.code).toBe('en');
+ expect(collectionType.body.meta.pagination).toEqual({
+ page: 1,
+ pageSize: 20,
+ pageCount: 1,
+ total: 2,
+ });
+ });
+
+ test('A collection type finds many versions in the provided locale', async () => {
+ const collectionType = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}&locale=fr`,
+ });
+
+ expect(collectionType.statusCode).toBe(200);
+ expect(collectionType.body.data).toHaveLength(2);
+ expect(collectionType.body.data[0].relatedDocumentId).toBe(collectionTypeDocumentId);
+ expect(collectionType.body.data[1].relatedDocumentId).toBe(collectionTypeDocumentId);
+ expect(collectionType.body.data[0].locale.code).toBe('fr');
+ expect(collectionType.body.data[1].locale.code).toBe('fr');
+ expect(collectionType.body.meta.pagination).toEqual({
+ page: 1,
+ pageSize: 20,
+ pageCount: 1,
+ total: 2,
+ });
+ });
+
+ test('A single type finds many versions in the default locale', async () => {
+ const singleType = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${singleTypeUid}`,
+ });
+
+ expect(singleType.statusCode).toBe(200);
+ expect(singleType.body.data).toHaveLength(2);
+ expect(singleType.body.data[0].relatedDocumentId).toBe(singleTypeDocumentId);
+ expect(singleType.body.data[1].relatedDocumentId).toBe(singleTypeDocumentId);
+ expect(singleType.body.data[0].locale.code).toBe('en');
+ expect(singleType.body.data[1].locale.code).toBe('en');
+ expect(singleType.body.meta.pagination).toEqual({
+ page: 1,
+ pageSize: 20,
+ pageCount: 1,
+ total: 2,
+ });
+ });
+
+ test('A single type finds many versions in the provided locale', async () => {
+ const singleType = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${singleTypeUid}&locale=fr`,
+ });
+
+ expect(singleType.statusCode).toBe(200);
+ expect(singleType.body.data).toHaveLength(2);
+ expect(singleType.body.data[0].relatedDocumentId).toBe(singleTypeDocumentId);
+ expect(singleType.body.data[1].relatedDocumentId).toBe(singleTypeDocumentId);
+ expect(singleType.body.data[0].locale.code).toBe('fr');
+ expect(singleType.body.data[1].locale.code).toBe('fr');
+ expect(singleType.body.meta.pagination).toEqual({
+ page: 1,
+ pageSize: 20,
+ pageCount: 1,
+ total: 2,
+ });
+ });
+
+ test('Applies pagination params', async () => {
+ const collectionType = await rq({
+ method: 'GET',
+ url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}&page=1&pageSize=1`,
+ });
+
+ expect(collectionType.body.data).toHaveLength(1);
+ expect(collectionType.body.meta.pagination).toEqual({
+ page: 1,
+ pageSize: 1,
+ pageCount: 2,
+ total: 2,
+ });
+ });
+ });
+
+ describe('Restore a history version', () => {
+ test('Throws with invalid body', async () => {
+ const res = await rq({
+ method: 'PUT',
+ url: `/content-manager/history-versions/1/restore`,
+ body: {},
+ });
+
+ expect(res.statusCode).toBe(400);
+ expect(res.body).toMatchObject({
+ data: null,
+ error: {
+ status: 400,
+ name: 'ValidationError',
+ message: 'contentType is required',
+ },
+ });
+ });
+
+ test('Throws without update permissions', async () => {
+ const restrictedRq = await createUserAndReq('read', [
+ { action: 'plugin::content-manager.explorer.read', subject: collectionTypeUid },
+ ]);
+ const res = await restrictedRq({
+ method: 'PUT',
+ url: `/content-manager/history-versions/1/restore`,
+ body: {
+ contentType: collectionTypeUid,
+ },
+ });
+
+ expect(res.statusCode).toBe(403);
+ expect(res.body).toMatchObject({
+ data: null,
+ error: {
+ status: 403,
+ name: 'ForbiddenError',
+ message: 'Forbidden',
+ },
+ });
+ });
+
+ test('Restores a history version in the default locale', async () => {
+ const currentDocument = await strapi
+ .documents(collectionTypeUid)
+ .findOne({ documentId: collectionTypeDocumentId });
+
+ await rq({
+ method: 'PUT',
+ url: `/content-manager/history-versions/1/restore`,
+ body: {
+ contentType: collectionTypeUid,
+ },
+ });
+
+ const restoredDocument = await strapi
+ .documents(collectionTypeUid)
+ .findOne({ documentId: collectionTypeDocumentId });
+
+ expect(currentDocument.description).toBe('Hello');
+ expect(restoredDocument.description).toBe(null);
+ });
+
+ test('Restores a history version in the provided locale', async () => {
+ const currentDocument = await strapi
+ .documents(collectionTypeUid)
+ .findOne({ documentId: collectionTypeDocumentId, locale: 'fr' });
+
+ await rq({
+ method: 'PUT',
+ url: `/content-manager/history-versions/4/restore`,
+ body: {
+ contentType: collectionTypeUid,
+ },
+ });
+
+ const restoredDocument = await strapi
+ .documents(collectionTypeUid)
+ .findOne({ documentId: collectionTypeDocumentId, locale: 'fr' });
+
+ expect(currentDocument.description).toBe('Coucou');
+ expect(restoredDocument.description).toBe(null);
+ });
+ });
+});