@eventcatalog/core 4.3.2 → 4.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-BYH34SOZ.js → chunk-5L4FYIAY.js} +1 -1
- package/dist/{chunk-T6UEDS2J.js → chunk-CQQE7NTL.js} +1 -1
- package/dist/{chunk-W4UBACYZ.js → chunk-OPFRJOPV.js} +1 -1
- package/dist/{chunk-25RQCO2H.js → chunk-QFXV3GDK.js} +1 -1
- package/dist/{chunk-YBNWZEFQ.js → chunk-XTC5VFLE.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/docs/api/02-config.md +24 -0
- package/dist/docs/cli/governance.md +1 -1
- package/dist/docs/cli/snapshots.md +1 -1
- package/dist/docs/development/ask-your-architecture/03-mcp-server/getting-started.md +56 -7
- package/dist/docs/development/ask-your-architecture/03-mcp-server/introduction.md +8 -3
- package/dist/docs/development/deployment/build-ssr-mode.md +1 -9
- package/dist/docs/development/developer-tools/api-catalog.md +1 -1
- package/dist/docs/development/guides/98-versioning-resources.md +15 -0
- package/dist/docs/development/guides/resources/entities/03-model-entity-relationships.md +26 -6
- package/dist/docs/development/guides/resources/entities/05-entity-maps.md +2 -0
- package/dist/docs/development/guides/resources/entities/06-reference.md +25 -2
- package/dist/docs/development/guides/resources/services/07-versioning-and-lifecycle/01-version-services.md +2 -0
- package/dist/docs/plugins/asyncapi/02-plugin-configuration.md +30 -2
- package/dist/docs/plugins/asyncapi/03-features.md +39 -26
- package/dist/docs/plugins/asyncapi/03a-workflows.md +61 -2
- package/dist/docs/plugins/openapi/02-plugin-configuration.md +1 -2
- package/dist/docs/plugins/openapi/03-features.md +8 -6
- package/dist/docs/plugins/openapi/03a-workflows.md +79 -18
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/src/components/LatestVersionRedirect.astro +26 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +21 -27
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +16 -7
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.spec.ts +28 -5
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +15 -2
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +8 -24
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +148 -10
- package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +25 -0
- package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +25 -0
- package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +25 -0
- package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +25 -0
- package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +25 -0
- package/eventcatalog/src/pages/docs/services/_latest-version-route.ts +42 -0
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +9 -12
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +4 -2
- package/eventcatalog/src/stores/sidebar-store/state.ts +1 -1
- package/package.json +3 -3
- package/dist/docs/cli/import.md +0 -26
|
@@ -15,7 +15,7 @@ import TabItem from '@theme/TabItem';
|
|
|
15
15
|
| Feature | Use cases |
|
|
16
16
|
|---------|-----------|
|
|
17
17
|
| [Mapping messages events, commands or queries](#mapping-messages-events-commands-or-queries) | AsyncAPI does not distinguish between commands, events and queries, everything is a message. Using the EventCatalog custom AsyncAPI [extension](https://www.asyncapi.com/docs/concepts/asyncapi-document/extending-specification) `x-eventcatalog-message-type` you can specify if your messages are events, command or queries. |
|
|
18
|
-
| [Defining message ownership roles](#defining-message-ownership-roles) |
|
|
18
|
+
| [Defining message ownership roles](#defining-message-ownership-roles) | Decide which service owns a shared message contract. By default, `send`/`publish` operations own the contract and `receive`/`subscribe` operations reference it. Use `x-eventcatalog-role` when you need to override that behavior. |
|
|
19
19
|
| [Defining message versions](#defining-message-versions) | In EventCatalog you can version your domains, services and all your messages. This can be useful as you can specify which version of a message your service produces or consumes. |
|
|
20
20
|
| [Mapping channels into EventCatalog](#mapping-channels-into-eventcatalog) | EventCatalog supports [Channels](/docs/development/guides/resources/messages/message-channels/introduction) ([see demo](https://demo.eventcatalog.dev/docs/channels/inventory.%7Benv%7D.events/1.0.0)). This let's you document how messages or organized and transported in your event-driven architecture. |
|
|
21
21
|
| [Creating draft domains, services and messages](#creating-draft-domains-services-and-messages) | You can create draft domains, services and messages in EventCatalog from your AsyncAPI files. This will be used to mark the resources as draft in EventCatalog. |
|
|
@@ -53,47 +53,60 @@ You can see more [examples of the extension on the demo project](https://github.
|
|
|
53
53
|
|
|
54
54
|
<AddedIn version="2.4.0" pkg="@eventcatalog/generator-asyncapi" url="https://github.com/event-catalog/generators/releases/tag/v"/>
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
EventCatalog stores a message as one shared contract, even when several AsyncAPI files reference it. The generator therefore needs to decide which service can create or update that contract.
|
|
57
57
|
|
|
58
|
-
By default
|
|
58
|
+
By default, ownership follows the AsyncAPI operation direction:
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
| AsyncAPI operation | Relationship to the contract | Generator behavior |
|
|
61
|
+
|--------------------|------------------------------|--------------------|
|
|
62
|
+
| `send` or `publish` | Owner | Creates the message and may update an existing contract. |
|
|
63
|
+
| `receive` or `subscribe` | Reference | Uses the existing contract without overwriting it. If the message does not exist, the receiver creates a fallback from its own definition. |
|
|
61
64
|
|
|
62
|
-
The
|
|
65
|
+
The service relationship is recorded independently of ownership. Owners are added to the service's `sends`, while references are added to its `receives`.
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
:::info Default changed in generator v7
|
|
68
|
+
Before v7, every message without an explicit role was treated as owned by the service being generated. This meant a consumer could overwrite the producer's summary or schema.
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
messages:
|
|
70
|
-
SendOrderConfirmation:
|
|
71
|
-
description: 'Command received to ask for sending an Order confirmation notification'
|
|
72
|
-
x-eventcatalog-role: client // Define the ownership. This example shows the service is a client of the message and does not own the message.
|
|
73
|
-
```
|
|
70
|
+
To retain the previous ownership behavior for a receiving operation, set `x-eventcatalog-role: provider` explicitly.
|
|
71
|
+
:::
|
|
74
72
|
|
|
75
|
-
|
|
73
|
+
#### Receiver fallbacks
|
|
74
|
+
|
|
75
|
+
If a receiving service is generated before the message exists, EventCatalog creates a fallback beneath that service. This keeps consumer-only catalogs working.
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
When the producing service is generated later for the same message and version, its definition becomes authoritative and the fallback is moved to the producer's message location. This makes the final contract independent of whether the producer or consumer was generated first.
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
#### Override the inferred role
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Use `x-eventcatalog-role` on an operation or message when operation direction does not express the ownership you need:
|
|
82
82
|
|
|
83
|
-
The
|
|
83
|
+
- `provider`: The service owns the message contract and may create or update it.
|
|
84
|
+
- `client`: The contract is external to the service. The generator records the `sends` or `receives` relationship but does not create or modify the message documentation.
|
|
84
85
|
|
|
85
|
-
-
|
|
86
|
-
- `client`: Generator will consider the message as a sent/received message in service but will NOT generate or modify the message in EventCatalog.
|
|
86
|
+
An operation-level role takes precedence over a message-level role. This is useful when a shared message has a different role for each operation or service.
|
|
87
87
|
|
|
88
|
-
```
|
|
88
|
+
```yaml title="Receiving service that explicitly owns the contract"
|
|
89
|
+
operations:
|
|
90
|
+
receiveOrderPlaced:
|
|
91
|
+
action: receive
|
|
92
|
+
x-eventcatalog-role: provider
|
|
93
|
+
channel:
|
|
94
|
+
$ref: '#/channels/orders'
|
|
95
|
+
messages:
|
|
96
|
+
- $ref: '#/channels/orders/messages/OrderPlaced'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
You can also set the role on the message:
|
|
100
|
+
|
|
101
|
+
```yaml title="External message"
|
|
89
102
|
components:
|
|
90
103
|
messages:
|
|
91
|
-
|
|
92
|
-
description:
|
|
93
|
-
x-eventcatalog-role: client
|
|
104
|
+
PaymentProcessed:
|
|
105
|
+
description: Payment processed by an external provider
|
|
106
|
+
x-eventcatalog-role: client
|
|
94
107
|
```
|
|
95
108
|
|
|
96
|
-
|
|
109
|
+
See [Shared message contracts across producer and consumer specs](/docs/plugins/asyncapi/03a-workflows#shared-message-contracts-across-producer-and-consumer-specs) for a complete workflow.
|
|
97
110
|
|
|
98
111
|
### Defining message versions
|
|
99
112
|
|
|
@@ -16,6 +16,8 @@ Many companies have different needs, so we have provided a few different workflo
|
|
|
16
16
|
|
|
17
17
|
- [Simple mapping between AsyncAPI files and EventCatalog services](#simple-mapping-between-asyncapi-files-and-eventcatalog-services)
|
|
18
18
|
- Map a single AsyncAPI file to a single EventCatalog service
|
|
19
|
+
- [Shared message contracts across producer and consumer specs](#shared-message-contracts-across-producer-and-consumer-specs)
|
|
20
|
+
- Keep the producer's message contract authoritative when several services reference it
|
|
19
21
|
- [Independent message versions from your AsyncAPI file](#independent-message-versions-from-your-asyncapi-file)
|
|
20
22
|
- Version your messages independently of the service version
|
|
21
23
|
- [Mapping multiple AsyncAPI files to a single EventCatalog service](#mapping-multiple-asyncapi-files-to-a-single-eventcatalog-service)
|
|
@@ -48,7 +50,64 @@ generators: [
|
|
|
48
50
|
],
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
## Shared message contracts across producer and consumer specs
|
|
54
|
+
|
|
55
|
+
This workflow is useful when several AsyncAPI files describe the same message. For example, an order service may send `OrderPlaced` while notification and fulfillment services receive it.
|
|
56
|
+
|
|
57
|
+
EventCatalog stores one shared message contract for a given message ID and version. Without an explicit `x-eventcatalog-role`, the generator uses the AsyncAPI operation direction to determine how each service relates to that contract:
|
|
58
|
+
|
|
59
|
+
- `send` or `publish` operations own the message contract and may update it.
|
|
60
|
+
- `receive` or `subscribe` operations reference an existing contract without overwriting it.
|
|
61
|
+
- A receiver creates a fallback from its own AsyncAPI definition only when the message does not exist yet.
|
|
62
|
+
- If the producer is generated after a receiver fallback, the producer's definition replaces the fallback and becomes authoritative.
|
|
63
|
+
|
|
64
|
+
The services can be configured in either order:
|
|
65
|
+
|
|
66
|
+
```js title="eventcatalog.config.js"
|
|
67
|
+
generators: [
|
|
68
|
+
[
|
|
69
|
+
'@eventcatalog/generator-asyncapi',
|
|
70
|
+
{
|
|
71
|
+
services: [
|
|
72
|
+
{ path: path.join(__dirname, 'asyncapi-files', 'notification-service.yml'), id: 'notification-service' },
|
|
73
|
+
{ path: path.join(__dirname, 'asyncapi-files', 'order-service.yml'), id: 'order-service' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
],
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Given these operations, `order-service` owns `OrderPlaced` and `notification-service` references it:
|
|
81
|
+
|
|
82
|
+
```yaml title="order-service.yml"
|
|
83
|
+
operations:
|
|
84
|
+
sendOrderPlaced:
|
|
85
|
+
action: send
|
|
86
|
+
channel:
|
|
87
|
+
$ref: '#/channels/orders'
|
|
88
|
+
messages:
|
|
89
|
+
- $ref: '#/channels/orders/messages/OrderPlaced'
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```yaml title="notification-service.yml"
|
|
93
|
+
operations:
|
|
94
|
+
receiveOrderPlaced:
|
|
95
|
+
action: receive
|
|
96
|
+
channel:
|
|
97
|
+
$ref: '#/channels/orders'
|
|
98
|
+
messages:
|
|
99
|
+
- $ref: '#/channels/orders/messages/OrderPlaced'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Both services remain connected to the message: the producer has an entry in `sends` and the consumer has an entry in `receives`. Only the producer can replace the shared contract.
|
|
103
|
+
|
|
104
|
+
:::tip Explicit ownership
|
|
105
|
+
If a receiving operation should own the contract, add `x-eventcatalog-role: provider` to that operation or message. Use `x-eventcatalog-role: client` when a sending or receiving service should only record its relationship and must never create the message documentation.
|
|
106
|
+
|
|
107
|
+
Read [Defining message ownership roles](/docs/plugins/asyncapi/features#defining-message-ownership-roles) for the complete rules.
|
|
108
|
+
:::
|
|
109
|
+
|
|
110
|
+
## Independent message versions from your AsyncAPI file
|
|
52
111
|
|
|
53
112
|
This is useful if you want to version your messages separately from the AsyncAPI file.
|
|
54
113
|
|
|
@@ -150,4 +209,4 @@ generators: [
|
|
|
150
209
|
},
|
|
151
210
|
],
|
|
152
211
|
],
|
|
153
|
-
```
|
|
212
|
+
```
|
|
@@ -33,7 +33,7 @@ Each service in the `services` array requires the following properties:
|
|
|
33
33
|
|----------|------|----------|-------------|
|
|
34
34
|
| `id` | string | Yes | EventCatalog ID for the service. |
|
|
35
35
|
| `path` | string or string[] | Yes | Path/s to your OpenAPI file or remote URL to the OpenAPI file. v6.0.0 introduced the ability to map multiple OpenAPI files to a single service. |
|
|
36
|
-
| `version` | string | No | Version for the generated EventCatalog service and messages. If not provided, the version
|
|
36
|
+
| `version` | string | No | Version for the generated EventCatalog service and messages. If not provided, the OpenAPI `info.version` is used. For a `path` array, the highest `info.version` is selected using semantic version ordering and all specifications are attached to that service version. |
|
|
37
37
|
| `name` | string | No | Display name for the service. If not provided, the specification will be used. _Added in v7.4.3_|
|
|
38
38
|
| `summary` | string | No | Short summary of the service. If not provided, the specification will be used. _Added in v7.4.3_|
|
|
39
39
|
| `owners` | string[] | No | Owners of the service. You can assign EventCatalog users or teams to services. |
|
|
@@ -330,4 +330,3 @@ or refer to the [OpenAPI examples on GitHub](https://github.com/event-catalog/ge
|
|
|
330
330
|
|
|
331
331
|
|
|
332
332
|
|
|
333
|
-
|
|
@@ -294,6 +294,8 @@ This can be useful if you want to introduce a new endpoint, but warn users that
|
|
|
294
294
|
|
|
295
295
|
If your service exposes multiple APIs, you can map many OpenAPI files to a single service.
|
|
296
296
|
|
|
297
|
+
One service configuration entry represents one EventCatalog service version. Every file in the `path` array is attached to that service version.
|
|
298
|
+
|
|
297
299
|
```js title="eventcatalog.config.js"
|
|
298
300
|
// ..rest of file
|
|
299
301
|
generators: [
|
|
@@ -304,10 +306,10 @@ generators: [
|
|
|
304
306
|
// Here we map two OpenAPI files to a single service
|
|
305
307
|
{
|
|
306
308
|
path: [
|
|
307
|
-
path.join(__dirname, 'openapi-files', 'orders-
|
|
308
|
-
path.join(__dirname, 'openapi-files', 'orders-
|
|
309
|
+
path.join(__dirname, 'openapi-files', 'orders-public-api.yml'),
|
|
310
|
+
path.join(__dirname, 'openapi-files', 'orders-admin-api.yml')
|
|
309
311
|
],
|
|
310
|
-
id: 'orders-service', owners: ['dboyne', 'team-1']
|
|
312
|
+
id: 'orders-service', version: '3.0.0', owners: ['dboyne', 'team-1']
|
|
311
313
|
},
|
|
312
314
|
],
|
|
313
315
|
// You can also set owners to the domain, this does not cascade to the services or messages
|
|
@@ -323,11 +325,11 @@ generators: [
|
|
|
323
325
|
|
|
324
326
|
#### How does mapping multiple OpenAPI files to a single service work?
|
|
325
327
|
|
|
326
|
-
The OpenAPI plugin
|
|
328
|
+
The OpenAPI plugin parses every file in the `path` array and adds every specification to the same service version.
|
|
327
329
|
|
|
328
|
-
|
|
330
|
+
When `version` is configured on the service entry, it is used for the service and its generated messages. When it is omitted, the highest OpenAPI `info.version` in the array is selected using semantic version ordering.
|
|
329
331
|
|
|
330
|
-
The
|
|
332
|
+
The files in a `path` array do not create separate historical service records. To model service history, configure a separate service entry with an explicit `version` for each OpenAPI file. See [OpenAPI workflows](/docs/plugins/openapi/03a-workflows#creating-versioned-service-records) for examples.
|
|
331
333
|
|
|
332
334
|
You can try this demo out for yourself by running the [mapping-many-openapi-files-to-a-service example](https://github.com/event-catalog/generators/tree/main/examples/generator-openapi/mapping-many-openapi-files-to-a-service).
|
|
333
335
|
|
|
@@ -19,7 +19,11 @@ Many companies have different needs, so we have provided a few different workflo
|
|
|
19
19
|
- [Independent message versions from your OpenAPI file](#independent-message-versions-from-your-openapi-file)
|
|
20
20
|
- Version your messages independently of the service version
|
|
21
21
|
- [Mapping multiple OpenAPI files to a single EventCatalog service](#mapping-multiple-openapi-files-to-a-single-eventcatalog-service)
|
|
22
|
-
-
|
|
22
|
+
- Attach multiple OpenAPI specifications to one service version
|
|
23
|
+
- [Creating versioned service records](#creating-versioned-service-records)
|
|
24
|
+
- Use separate service entries when each specification represents a service version
|
|
25
|
+
- [Versioning a service on a later generator run](#versioning-a-service-on-a-later-generator-run)
|
|
26
|
+
- Preserve the current service as history when a newer version is generated
|
|
23
27
|
- [Mapping OpenAPI and AsyncAPI files to the same EventCatalog service](#mapping-openapi-and-asyncapi-files-to-the-same-eventcatalog-service)
|
|
24
28
|
- Map an OpenAPI and AsyncAPI file to the same EventCatalog service
|
|
25
29
|
|
|
@@ -29,7 +33,9 @@ _If we are missing a workflow that you think is useful, please raise an [issue o
|
|
|
29
33
|
|
|
30
34
|
This is the simplest workflow and is useful if you have a single OpenAPI file per service.
|
|
31
35
|
|
|
32
|
-
EventCatalog will parse your OpenAPI file and map
|
|
36
|
+
EventCatalog will parse your OpenAPI file and map its specification to the service you define.
|
|
37
|
+
|
|
38
|
+
If you do not configure a service `version`, the OpenAPI document's `info.version` is used.
|
|
33
39
|
|
|
34
40
|
This will document your service, and the messages it produces and consumes.
|
|
35
41
|
|
|
@@ -79,44 +85,99 @@ paths:
|
|
|
79
85
|
|
|
80
86
|
In the example above, the message `listOrders` will be versioned as `2.0.0` and all other messages will be versioned as `1.0.0`.
|
|
81
87
|
|
|
82
|
-
You can read more about message versioning in the [Features](/docs/plugins/openapi/features#
|
|
88
|
+
You can read more about message versioning in the [Features](/docs/plugins/openapi/features#custom-versioning-with-x-eventcatalog-message-version) section.
|
|
83
89
|
|
|
84
90
|
## Mapping multiple OpenAPI files to a single EventCatalog service
|
|
85
91
|
|
|
86
|
-
This is useful
|
|
92
|
+
This is useful when one version of a service exposes multiple OpenAPI contracts, for example a public API and an administration API.
|
|
93
|
+
|
|
94
|
+
Use a `path` array in one service entry. One service entry represents one EventCatalog service version, so every OpenAPI file in the array is attached to that version and rendered in the service's `specifications` list.
|
|
95
|
+
|
|
96
|
+
```js title="eventcatalog.config.js"
|
|
97
|
+
// ...rest of file
|
|
98
|
+
generators: [
|
|
99
|
+
[
|
|
100
|
+
'@eventcatalog/generator-openapi',
|
|
101
|
+
{
|
|
102
|
+
services: [
|
|
103
|
+
{
|
|
104
|
+
id: 'orders-service',
|
|
105
|
+
version: '3.0.0',
|
|
106
|
+
path: [
|
|
107
|
+
path.join(__dirname, 'openapi-files', 'orders-public-api.yml'),
|
|
108
|
+
path.join(__dirname, 'openapi-files', 'orders-admin-api.yml'),
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
],
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The generated service contains both specifications:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
id: orders-service
|
|
121
|
+
version: 3.0.0
|
|
122
|
+
specifications:
|
|
123
|
+
- type: openapi
|
|
124
|
+
path: orders-public-api.yml
|
|
125
|
+
name: Orders Public API
|
|
126
|
+
- type: openapi
|
|
127
|
+
path: orders-admin-api.yml
|
|
128
|
+
name: Orders Admin API
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
:::info Choosing the service version
|
|
132
|
+
When `version` is configured on the service entry, it takes precedence over the `info.version` values in the OpenAPI files.
|
|
87
133
|
|
|
88
|
-
|
|
134
|
+
When `version` is omitted, the generator uses the highest OpenAPI `info.version` from the `path` array. Versions are compared semantically, so `10.0.0` is considered newer than `2.0.0`. Every specification in the array is then attached to that selected service version.
|
|
135
|
+
|
|
136
|
+
A `path` array does not create historical service records. Use separate service entries if the files represent different versions of the service.
|
|
137
|
+
:::
|
|
138
|
+
|
|
139
|
+
## Creating versioned service records
|
|
140
|
+
|
|
141
|
+
Use a separate service entry for each service version when you want to keep multiple versions in EventCatalog. Set `version` explicitly to make the intended service lifecycle clear.
|
|
89
142
|
|
|
90
143
|
```js title="eventcatalog.config.js"
|
|
91
144
|
// ...rest of file
|
|
92
145
|
generators: [
|
|
93
146
|
[
|
|
94
|
-
'@eventcatalog/generator-
|
|
147
|
+
'@eventcatalog/generator-openapi',
|
|
95
148
|
{
|
|
96
149
|
services: [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
150
|
+
{
|
|
151
|
+
id: 'orders-service',
|
|
152
|
+
version: '1.0.0',
|
|
153
|
+
path: path.join(__dirname, 'openapi-files', 'orders-service-v1.yml'),
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'orders-service',
|
|
157
|
+
version: '2.0.0',
|
|
158
|
+
path: path.join(__dirname, 'openapi-files', 'orders-service-v2.yml'),
|
|
159
|
+
},
|
|
101
160
|
],
|
|
102
161
|
},
|
|
103
162
|
],
|
|
104
163
|
],
|
|
105
164
|
```
|
|
106
165
|
|
|
107
|
-
|
|
108
|
-
When you map multiple versions of an OpenAPI file to a single service, the `version` property in your OpenAPI files needs to be the same.
|
|
166
|
+
In this example, `2.0.0` becomes the current service. Version `1.0.0` and its OpenAPI specification are stored as a historical service record under `versioned/1.0.0`. Each service version references only the OpenAPI specification configured for that entry.
|
|
109
167
|
|
|
110
|
-
|
|
168
|
+
You can also use a `path` array inside either entry if that particular service version has multiple OpenAPI specifications.
|
|
111
169
|
|
|
112
|
-
|
|
170
|
+
## Versioning a service on a later generator run
|
|
113
171
|
|
|
114
|
-
|
|
172
|
+
You do not need to keep every historical version in `eventcatalog.config.js` forever. If `orders-service` is generated as `1.0.0` today and the configured OpenAPI file changes to `2.0.0` later, running the generator again will:
|
|
115
173
|
|
|
116
|
-
|
|
174
|
+
1. Move the existing `1.0.0` service and its OpenAPI specification into the service's versioned history.
|
|
175
|
+
2. Generate `2.0.0` as the current service with the new OpenAPI specification.
|
|
117
176
|
|
|
118
|
-
This
|
|
177
|
+
This works when the service version comes from OpenAPI `info.version` or from an explicit `version` in the service configuration. If you configure `version`, update it when you intend to create a new service version.
|
|
119
178
|
|
|
179
|
+
:::tip Multiple contracts versus service history
|
|
180
|
+
Use one entry with `path: []` for multiple contracts belonging to the same service version. Use separate entries, or update the version on a later run, to create service history.
|
|
120
181
|
:::
|
|
121
182
|
|
|
122
183
|
## Mapping OpenAPI and AsyncAPI files to the same EventCatalog service
|
|
@@ -150,4 +211,4 @@ generators: [
|
|
|
150
211
|
},
|
|
151
212
|
],
|
|
152
213
|
],
|
|
153
|
-
```
|
|
214
|
+
```
|
package/dist/eventcatalog.cjs
CHANGED
|
@@ -144,7 +144,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
|
|
|
144
144
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
145
145
|
|
|
146
146
|
// package.json
|
|
147
|
-
var version = "4.3.
|
|
147
|
+
var version = "4.3.4";
|
|
148
148
|
|
|
149
149
|
// src/constants.ts
|
|
150
150
|
var VERSION = version;
|
package/dist/eventcatalog.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QFXV3GDK.js";
|
|
4
4
|
import "./chunk-K2XIENVT.js";
|
|
5
5
|
import {
|
|
6
6
|
runMigrations
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
} from "./chunk-B7HCX5HM.js";
|
|
15
15
|
import {
|
|
16
16
|
generate
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XTC5VFLE.js";
|
|
18
18
|
import {
|
|
19
19
|
logger
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-CQQE7NTL.js";
|
|
21
21
|
import {
|
|
22
22
|
resolve_catalog_dependencies_default
|
|
23
23
|
} from "./chunk-LHR4G2UO.js";
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import {
|
|
28
28
|
watch
|
|
29
29
|
} from "./chunk-CAJUIMDJ.js";
|
|
30
|
-
import "./chunk-
|
|
30
|
+
import "./chunk-5L4FYIAY.js";
|
|
31
31
|
import {
|
|
32
32
|
createAstroDevLineFilter,
|
|
33
33
|
createAstroLineFilter
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
import "./chunk-W5JQON7Z.js";
|
|
39
39
|
import {
|
|
40
40
|
VERSION
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-OPFRJOPV.js";
|
|
42
42
|
import {
|
|
43
43
|
linkCoreNodeModules,
|
|
44
44
|
resolveInstalledCoreNodeModules
|
package/dist/generate.cjs
CHANGED
|
@@ -108,7 +108,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
|
|
|
108
108
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
109
109
|
|
|
110
110
|
// package.json
|
|
111
|
-
var version = "4.3.
|
|
111
|
+
var version = "4.3.4";
|
|
112
112
|
|
|
113
113
|
// src/constants.ts
|
|
114
114
|
var VERSION = version;
|
package/dist/generate.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generate
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-XTC5VFLE.js";
|
|
4
|
+
import "./chunk-CQQE7NTL.js";
|
|
5
|
+
import "./chunk-OPFRJOPV.js";
|
|
6
6
|
import "./chunk-6QENHZZP.js";
|
|
7
7
|
export {
|
|
8
8
|
generate
|
package/dist/utils/cli-logger.js
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Seo from '@components/Seo.astro';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
redirectUrl: string;
|
|
6
|
+
title: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { redirectUrl, title } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!doctype html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<Seo title={title} />
|
|
16
|
+
<meta http-equiv="refresh" content={`0;url=${redirectUrl}`} />
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<p>You are being redirected to <a href={redirectUrl}>{redirectUrl}</a></p>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
22
|
+
|
|
23
|
+
<script define:vars={{ redirectUrl }}>
|
|
24
|
+
const fullRedirectUrl = redirectUrl + window.location.search + window.location.hash;
|
|
25
|
+
window.location.replace(fullRedirectUrl);
|
|
26
|
+
</script>
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
removeFavorite as removeFavoriteAction,
|
|
14
14
|
type FavoriteItem,
|
|
15
15
|
} from '@stores/favorites-store';
|
|
16
|
-
import { getBadgeClasses, isGroupCollapsed } from './utils';
|
|
16
|
+
import { canCollapseGroup, getBadgeClasses, getGroupLabel, isGroupCollapsed } from './utils';
|
|
17
17
|
import { resolveIconUrl } from '@utils/icon';
|
|
18
18
|
|
|
19
19
|
const cn = (...classes: (string | false | undefined)[]) => classes.filter(Boolean).join(' ');
|
|
@@ -57,7 +57,7 @@ export default function NestedSideBar() {
|
|
|
57
57
|
const [slideDirection, setSlideDirection] = useState<'forward' | 'backward' | null>(null);
|
|
58
58
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
59
59
|
const [currentPath, setCurrentPath] = useState<string>('');
|
|
60
|
-
const [
|
|
60
|
+
const [sectionCollapsePreferences, setSectionCollapsePreferences] = useState(loadCollapsedSections);
|
|
61
61
|
const [showPathPreview, setShowPathPreview] = useState(false);
|
|
62
62
|
const [showFullPath, setShowFullPath] = useState(false);
|
|
63
63
|
|
|
@@ -95,29 +95,23 @@ export default function NestedSideBar() {
|
|
|
95
95
|
* Toggle section collapse state
|
|
96
96
|
*/
|
|
97
97
|
const toggleSectionCollapse = (sectionId: string) => {
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
setSectionCollapsePreferences((previousPreferences) => {
|
|
99
|
+
const nextPreferences = {
|
|
100
|
+
expanded: new Set(previousPreferences.expanded),
|
|
101
|
+
};
|
|
102
|
+
const isCurrentlyCollapsed = isGroupCollapsed(true, sectionId, previousPreferences);
|
|
103
|
+
|
|
104
|
+
if (isCurrentlyCollapsed) {
|
|
105
|
+
nextPreferences.expanded.add(sectionId);
|
|
102
106
|
} else {
|
|
103
|
-
|
|
107
|
+
nextPreferences.expanded.delete(sectionId);
|
|
104
108
|
}
|
|
105
|
-
|
|
106
|
-
saveCollapsedSections(
|
|
107
|
-
return
|
|
109
|
+
|
|
110
|
+
saveCollapsedSections(nextPreferences);
|
|
111
|
+
return nextPreferences;
|
|
108
112
|
});
|
|
109
113
|
};
|
|
110
114
|
|
|
111
|
-
/**
|
|
112
|
-
* Load collapsed sections from localStorage on mount
|
|
113
|
-
*/
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
const saved = loadCollapsedSections();
|
|
116
|
-
if (saved.size > 0) {
|
|
117
|
-
setCollapsedSections(saved);
|
|
118
|
-
}
|
|
119
|
-
}, []);
|
|
120
|
-
|
|
121
115
|
/**
|
|
122
116
|
* Update navigation stack when roots become available
|
|
123
117
|
*/
|
|
@@ -521,7 +515,7 @@ export default function NestedSideBar() {
|
|
|
521
515
|
// Show loading state if no data yet
|
|
522
516
|
if (!data || roots.length === 0) {
|
|
523
517
|
return (
|
|
524
|
-
<aside className="
|
|
518
|
+
<aside className="flex h-full min-h-0 w-full flex-1 flex-col bg-[rgb(var(--ec-rail-bg))] font-sans">
|
|
525
519
|
{/* Search skeleton */}
|
|
526
520
|
<div className="px-4 py-3 border-b border-[rgb(var(--ec-content-border))] bg-[rgb(var(--ec-rail-bg))]">
|
|
527
521
|
<div className="h-10 bg-[rgb(var(--ec-content-hover))] rounded-xl animate-pulse" />
|
|
@@ -754,9 +748,9 @@ export default function NestedSideBar() {
|
|
|
754
748
|
return child && isVisible(child);
|
|
755
749
|
}) ?? [];
|
|
756
750
|
|
|
757
|
-
const groupId = groupKey || group.collapseKey ||
|
|
758
|
-
const canCollapse = visibleChildren.length
|
|
759
|
-
const isCollapsed = isGroupCollapsed(canCollapse, groupId,
|
|
751
|
+
const groupId = groupKey || group.collapseKey || `${currentLevel.key ?? 'root'}:group:${group.title}`;
|
|
752
|
+
const canCollapse = canCollapseGroup(visibleChildren.length);
|
|
753
|
+
const isCollapsed = isGroupCollapsed(canCollapse, groupId, sectionCollapsePreferences);
|
|
760
754
|
|
|
761
755
|
// When a group's children are subtle subgroups (e.g. Resources > Services/Flows/Data Stores),
|
|
762
756
|
// they render flush under the parent icon instead of inside the indented border guide.
|
|
@@ -787,7 +781,7 @@ export default function NestedSideBar() {
|
|
|
787
781
|
: 'text-[12px] font-semibold tracking-tight text-[rgb(var(--ec-content-text))]'
|
|
788
782
|
)}
|
|
789
783
|
>
|
|
790
|
-
{group.title}
|
|
784
|
+
{getGroupLabel(group.title, visibleChildren.length)}
|
|
791
785
|
</span>
|
|
792
786
|
</div>
|
|
793
787
|
{canCollapse && (
|
|
@@ -973,7 +967,7 @@ export default function NestedSideBar() {
|
|
|
973
967
|
};
|
|
974
968
|
|
|
975
969
|
return (
|
|
976
|
-
<aside className="
|
|
970
|
+
<aside className="flex h-full min-h-0 w-full flex-1 flex-col bg-[rgb(var(--ec-rail-bg))] font-sans">
|
|
977
971
|
{isTopLevel && (
|
|
978
972
|
<div className="flex h-[60px] items-center px-6 bg-[rgb(var(--ec-rail-bg)/0.98)] backdrop-blur-sm border-b border-[rgb(var(--ec-content-border))] sticky top-0 z-10">
|
|
979
973
|
<span className="text-[0.65rem] font-semibold uppercase tracking-[0.18em] text-[rgb(var(--ec-sidebar-text)/0.5)] truncate">
|
|
@@ -1128,7 +1122,7 @@ export default function NestedSideBar() {
|
|
|
1128
1122
|
{/* Navigation Content */}
|
|
1129
1123
|
<nav
|
|
1130
1124
|
key={animationKey}
|
|
1131
|
-
className={cn('flex-1 overflow-y-auto overflow-x-hidden p-4 px-2', getAnimationClass())}
|
|
1125
|
+
className={cn('min-h-0 flex-1 overflow-y-auto overflow-x-hidden p-4 px-2', getAnimationClass())}
|
|
1132
1126
|
style={{
|
|
1133
1127
|
scrollbarWidth: 'thin',
|
|
1134
1128
|
scrollbarColor: 'rgb(var(--ec-content-border)) transparent',
|