@eventcatalog/core 5.5.2 → 5.6.0

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.
Files changed (55) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +5 -5
  5. package/dist/{chunk-CNN747RO.js → chunk-7TTNTHHN.js} +10 -10
  6. package/dist/{chunk-7ZEKF2LA.js → chunk-DEO4QEGO.js} +1 -1
  7. package/dist/{chunk-WG6ZK6L3.js → chunk-ETS4G6RR.js} +1 -1
  8. package/dist/{chunk-5HSYALWK.js → chunk-T3U27UXC.js} +1 -1
  9. package/dist/{chunk-MC4F3VVM.js → chunk-XBRKEQ66.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
  13. package/dist/docs/development/guides/domains/09-reference.md +5 -1
  14. package/dist/docs/development/guides/resources/schemas/03-add-specifications-to-services/04-add-generic-specifications.md +139 -0
  15. package/dist/docs/development/guides/resources/schemas/03-add-specifications-to-services/_category_.json +1 -1
  16. package/dist/docs/development/guides/resources/services/08-reference.md +6 -1
  17. package/dist/eventcatalog.cjs +1 -1
  18. package/dist/eventcatalog.js +16 -16
  19. package/dist/federation/federate.js +3 -3
  20. package/dist/generate.cjs +1 -1
  21. package/dist/generate.js +3 -3
  22. package/dist/utils/cli-logger.cjs +1 -1
  23. package/dist/utils/cli-logger.js +2 -2
  24. package/eventcatalog/public/icons/specification.svg +1 -0
  25. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +38 -20
  26. package/eventcatalog/src/components/Grids/specification-utils.ts +7 -1
  27. package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +1 -1
  28. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeBlock.tsx +58 -0
  29. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -1
  30. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +38 -76
  31. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +15 -11
  32. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +171 -142
  33. package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +5 -8
  34. package/eventcatalog/src/components/SchemaExplorer/types.ts +2 -0
  35. package/eventcatalog/src/components/SchemaExplorer/utils.ts +70 -1
  36. package/eventcatalog/src/content.config.ts +3 -1
  37. package/eventcatalog/src/features/ai/chat-api.ts +6 -1
  38. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +1 -1
  39. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +1 -1
  40. package/eventcatalog/src/features/tools/catalog-tools.ts +8 -3
  41. package/eventcatalog/src/pages/.well-known/api-catalog.ts +1 -11
  42. package/eventcatalog/src/pages/api-catalog/specifications/[collection]/[id]/[version]/[specification].ts +1 -11
  43. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/generic/[filename].astro +137 -0
  44. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/generic/_SpecificationSource.tsx +44 -0
  45. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/generic/_[filename].data.ts +75 -0
  46. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +14 -1
  47. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +10 -1
  48. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +8 -1
  49. package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +3 -1
  50. package/eventcatalog/src/utils/collections/util.ts +38 -1
  51. package/eventcatalog/src/utils/icon.ts +8 -0
  52. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +5 -2
  53. package/eventcatalog/src/utils/schema-explorer.ts +7 -2
  54. package/package.json +6 -6
  55. package/dist/{chunk-QJ7KKN2D.js → chunk-NCEZDQSW.js} +7 -7
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(analytics_exports);
36
36
  var import_os = __toESM(require("os"), 1);
37
37
 
38
38
  // package.json
39
- var version = "5.5.2";
39
+ var version = "5.6.0";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-5HSYALWK.js";
3
+ } from "../chunk-T3U27UXC.js";
4
4
  import "../chunk-CPW6G62V.js";
5
- import "../chunk-WG6ZK6L3.js";
5
+ import "../chunk-ETS4G6RR.js";
6
6
  export {
7
7
  raiseEvent
8
8
  };
@@ -169,7 +169,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
169
169
  var import_os = __toESM(require("os"), 1);
170
170
 
171
171
  // package.json
172
- var version = "5.5.2";
172
+ var version = "5.6.0";
173
173
 
174
174
  // src/constants.ts
175
175
  var VERSION = version;
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-CNN747RO.js";
4
- import "../chunk-AD7CL772.js";
5
- import "../chunk-5HSYALWK.js";
6
- import "../chunk-YRZK7HKX.js";
3
+ } from "../chunk-7TTNTHHN.js";
7
4
  import "../chunk-CA6WCQ2T.js";
5
+ import "../chunk-AD7CL772.js";
6
+ import "../chunk-T3U27UXC.js";
8
7
  import "../chunk-CPW6G62V.js";
9
- import "../chunk-WG6ZK6L3.js";
8
+ import "../chunk-YRZK7HKX.js";
9
+ import "../chunk-ETS4G6RR.js";
10
10
  import "../chunk-4G7FSRPN.js";
11
11
  export {
12
12
  log_build_default as default
@@ -1,23 +1,23 @@
1
+ import {
2
+ getStorageType,
3
+ getStudioMode,
4
+ serializeStudioUsage
5
+ } from "./chunk-CA6WCQ2T.js";
1
6
  import {
2
7
  getLicenseAnalytics
3
8
  } from "./chunk-AD7CL772.js";
4
9
  import {
5
10
  raiseEvent
6
- } from "./chunk-5HSYALWK.js";
11
+ } from "./chunk-T3U27UXC.js";
12
+ import {
13
+ TELEMETRY_REQUEST_TIMEOUT_MS,
14
+ isTelemetryDisabled
15
+ } from "./chunk-CPW6G62V.js";
7
16
  import {
8
17
  countResources,
9
18
  hashCatalogContent,
10
19
  serializeCounts
11
20
  } from "./chunk-YRZK7HKX.js";
12
- import {
13
- getStorageType,
14
- getStudioMode,
15
- serializeStudioUsage
16
- } from "./chunk-CA6WCQ2T.js";
17
- import {
18
- TELEMETRY_REQUEST_TIMEOUT_MS,
19
- isTelemetryDisabled
20
- } from "./chunk-CPW6G62V.js";
21
21
  import {
22
22
  getEventCatalogConfigFile,
23
23
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-MC4F3VVM.js";
3
+ } from "./chunk-XBRKEQ66.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "5.5.2";
2
+ var version = "5.6.0";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-CPW6G62V.js";
5
5
  import {
6
6
  VERSION
7
- } from "./chunk-WG6ZK6L3.js";
7
+ } from "./chunk-ETS4G6RR.js";
8
8
 
9
9
  // src/analytics/analytics.js
10
10
  import os from "os";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-WG6ZK6L3.js";
3
+ } from "./chunk-ETS4G6RR.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "5.5.2";
28
+ var version = "5.6.0";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-WG6ZK6L3.js";
3
+ } from "./chunk-ETS4G6RR.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -89,7 +89,7 @@ Inside a custom group, each entry in `pages` is one of:
89
89
  | Section token | `"$inbound-messages"` | The **items** of a predefined section, spliced into your group — this is how you extend a generated section with your own pages |
90
90
  | Resource reference | `"[[service\|payment-api]]"` | The resource, with its own expandable nested sidebar, at its latest version. Messages can pin a version: `"[[event\|payment-captured@1.0.0]]"` — other types always reference the latest |
91
91
  | Documentation reference | `"[[doc\|guides/onboarding]]"` | One of this resource's [documentation pages](/docs/development/bring-your-own-documentation/resource-docs/adding-resource-docs), addressed as `<type>/<id>` |
92
- | Specification reference | `"[[spec\|openapi.yml]]"` | A specification page, with the OpenAPI/AsyncAPI/GraphQL logo and the spec's name |
92
+ | Specification reference | `"[[spec\|openapi.yml]]"` | A specification page, with the OpenAPI/AsyncAPI/GraphQL logo (or a generic specification's icon) and the spec's name |
93
93
  | Schema reference | `"[[schema\|payment-captured]]"` | A message's schema page |
94
94
  | Link | `{ "title": "Runbook", "href": "https://..." }` | A plain link. External links (any protocol) open in a new tab and show an external-link icon |
95
95
  | Nested group | `{ "title": "Internal", "collapsed": true, "pages": [...] }` | A subsection. Groups nest to any depth |
@@ -425,14 +425,18 @@ specifications:
425
425
  - type: graphql
426
426
  path: graphql.yml
427
427
  name: GraphQL Specification
428
+ - type: generic
429
+ path: carrier-sla.yaml
430
+ name: Carrier Service Levels
428
431
  ---
429
432
  ```
430
433
 
431
434
  | Property | Type | Required | Description |
432
435
  | -------- | ---- | -------- | ----------- |
433
- | `type` | `string` | Yes | The type of specification. |
436
+ | `type` | `string` | Yes | The type of specification: `openapi`, `asyncapi`, `graphql` or `generic` ([any other file](/docs/development/guides/resources/schemas/add-specifications-to-services/add-generic-specifications), such as a WSDL, an XML Schema, or a JSON or YAML contract). |
434
437
  | `path` | `string` | Yes | The path to the specification file. |
435
438
  | `name` | `string` | No | Optional friendly name of the specification, rendered in the UI. |
439
+ | `icon` | `string` | No | Icon for a `generic` specification: a path in your `public` folder or a URL. |
436
440
 
437
441
  **Older versions of EventCatalog (< 2.39.0)**
438
442
 
@@ -0,0 +1,139 @@
1
+ ---
2
+ keywords:
3
+ - EventCatalog schemas
4
+ - WSDL
5
+ - XML Schema
6
+ - XSD
7
+ - generic specifications
8
+ sidebar_position: 4
9
+ sidebar_label: Other formats (XML, JSON, YAML)
10
+ title: Add other specifications (XML, JSON, YAML)
11
+ description: Attach any specification file, such as a WSDL, an XML Schema, or a JSON or YAML contract, to a service or domain
12
+ ---
13
+
14
+ import AddedIn from '@site/src/components/MDX/AddedIn';
15
+ import ProjectTree from '@site/src/components/MDX/ProjectTree';
16
+
17
+ <AddedIn version="5.6.0" />
18
+
19
+ Not every API is described with OpenAPI, AsyncAPI or GraphQL. A SOAP service has a WSDL, a partner integration may share an XML Schema, and a team may keep its contract in its own JSON or YAML format.
20
+
21
+ Use `type: generic` to attach any of these files to a service or domain. EventCatalog adds a page for the file and lists it with your other specifications.
22
+
23
+ Generic specifications are shown as source code. EventCatalog doesn't parse them, so any file works. These files get syntax highlighting:
24
+
25
+ | Format | File extensions |
26
+ | ------ | --------------- |
27
+ | XML | `.xml`, `.xsd`, `.wsdl`, `.xsl`, `.xslt` |
28
+ | JSON | `.json` |
29
+ | YAML | `.yaml`, `.yml` |
30
+
31
+ Other files are shown as plain text.
32
+
33
+ ## Add a generic specification
34
+
35
+ Put the file inside the service (or domain) folder.
36
+
37
+ <ProjectTree
38
+ items={[
39
+ {
40
+ name: 'services',
41
+ type: 'folder',
42
+ defaultOpen: true,
43
+ children: [
44
+ {
45
+ name: 'CarrierAdapter',
46
+ type: 'folder',
47
+ defaultOpen: true,
48
+ children: [
49
+ { name: 'index.mdx' },
50
+ {
51
+ name: 'specs',
52
+ type: 'folder',
53
+ defaultOpen: true,
54
+ children: [
55
+ { name: 'carrier-shipping.wsdl', highlight: true },
56
+ { name: 'shipment.xsd', highlight: true },
57
+ ],
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ },
63
+ ]}
64
+ />
65
+
66
+ Then reference the file in the frontmatter.
67
+
68
+ ```md title="example: /services/CarrierAdapter/index.mdx"
69
+ ---
70
+ specifications:
71
+ - type: generic
72
+ # Path to the file, relative to the service folder
73
+ path: specs/carrier-shipping.wsdl
74
+ # Friendly name for the specification (defaults to "Specification")
75
+ name: Carrier Shipping API (WSDL)
76
+ - type: generic
77
+ path: specs/shipment.xsd
78
+ name: Shipment XML Schema
79
+ ---
80
+ ```
81
+
82
+ Each generic specification gets a page at `/docs/services/{id}/{version}/generic/{filename}`, where `{filename}` is the file name without its extension. It is also listed:
83
+
84
+ - under **API & Contracts** in the sidebar
85
+ - in the badges on the service or domain page
86
+ - in the [Schema Explorer](/docs/development/guides/resources/schemas/explore-schemas/schema-explorer), where you can filter by the **Specs** type and by format (XML, JSON, YAML)
87
+ - in the node's menu in the visualiser
88
+
89
+ :::info
90
+ The page URL uses the file name without its extension, so give each specification on a resource its own file name (for example, don't use both `contract.json` and `contract.yaml`).
91
+ :::
92
+
93
+ ## Use a custom icon
94
+
95
+ Generic specifications use a default specification icon. Use `icon` to set your own. It can be a path to a file in your catalog's `public` folder, or a URL.
96
+
97
+ ```md title="example: /services/CarrierAdapter/index.mdx"
98
+ ---
99
+ specifications:
100
+ - type: generic
101
+ path: specs/carrier-shipping.wsdl
102
+ name: Carrier Shipping API (WSDL)
103
+ # /public/icons/soap.svg in your catalog
104
+ icon: /icons/soap.svg
105
+ ---
106
+ ```
107
+
108
+ The icon shows on the specification page, in the sidebar, on the resource page and in the Schema Explorer. `icon` only applies to generic specifications.
109
+
110
+ ## Reference a file from a remote URL
111
+
112
+ You can also use a URL as the `path`. EventCatalog fetches the file when it builds your catalog, so the URL must be reachable from the build machine. Rebuild your catalog to show changes to the file.
113
+
114
+ ```md title="example: /services/CarrierAdapter/index.mdx"
115
+ ---
116
+ specifications:
117
+ - type: generic
118
+ path: https://raw.githubusercontent.com/acme/carrier-contracts/main/carrier-shipping.wsdl
119
+ name: Carrier Shipping API (WSDL)
120
+ # Optional: headers for private files. Only variables that start with EVENTCATALOG_ or EC_ are used.
121
+ headers:
122
+ Authorization: 'Bearer ${EC_GITHUB_TOKEN}'
123
+ ---
124
+ ```
125
+
126
+ Remote files are shown on their specification page. The Schema Explorer only lists files in your catalog.
127
+
128
+ ## Add generic specifications to a domain
129
+
130
+ Domains support generic specifications in the same way. Put the file in the domain folder and add it to the domain's `specifications`.
131
+
132
+ ```md title="example: /domains/Fulfilment/index.mdx"
133
+ ---
134
+ specifications:
135
+ - type: generic
136
+ path: carrier-sla.yaml
137
+ name: Carrier Service Levels
138
+ ---
139
+ ```
@@ -6,6 +6,6 @@
6
6
  "link": {
7
7
  "type": "generated-index",
8
8
  "slug": "/schemas/add-specifications-to-services",
9
- "description": "Attach OpenAPI, AsyncAPI, and GraphQL specifications to services."
9
+ "description": "Attach OpenAPI, AsyncAPI, GraphQL and other specifications (XML, JSON, YAML) to services."
10
10
  }
11
11
  }
@@ -213,7 +213,7 @@ externalSystem: true
213
213
 
214
214
  - Type: `object` or `array`
215
215
 
216
- OpenAPI, AsyncAPI, or GraphQL specifications for the service.
216
+ OpenAPI, AsyncAPI, or GraphQL specifications for the service. Use `type: generic` for any other specification file, such as a WSDL, an XML Schema, or a JSON or YAML contract ([read more](/docs/development/guides/resources/schemas/add-specifications-to-services/add-generic-specifications)).
217
217
 
218
218
  ```md title="Example"
219
219
  ---
@@ -223,6 +223,11 @@ specifications:
223
223
  name: Public API
224
224
  - type: asyncapi
225
225
  path: asyncapi.yml
226
+ - type: generic
227
+ path: carrier-shipping.wsdl
228
+ name: Carrier Shipping API (WSDL)
229
+ # Optional, generic specifications only
230
+ icon: /icons/soap.svg
226
231
  ---
227
232
  ```
228
233
 
@@ -174,7 +174,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
174
174
  var import_picocolors = __toESM(require("picocolors"), 1);
175
175
 
176
176
  // package.json
177
- var version = "5.5.2";
177
+ var version = "5.6.0";
178
178
 
179
179
  // src/constants.ts
180
180
  var VERSION = version;
@@ -1,36 +1,36 @@
1
1
  import {
2
- stopChildWithParent
3
- } from "./chunk-S5GWAUG5.js";
2
+ log_build_default
3
+ } from "./chunk-7TTNTHHN.js";
4
+ import "./chunk-CA6WCQ2T.js";
4
5
  import {
5
6
  runMigrations
6
7
  } from "./chunk-XUAF2H54.js";
7
8
  import "./chunk-CA4U2JP7.js";
8
9
  import {
9
- log_build_default
10
- } from "./chunk-CNN747RO.js";
10
+ stopChildWithParent
11
+ } from "./chunk-S5GWAUG5.js";
11
12
  import {
12
13
  getLicenseStatus,
13
14
  printLicenseStatus
14
15
  } from "./chunk-AD7CL772.js";
15
- import "./chunk-5HSYALWK.js";
16
- import "./chunk-YRZK7HKX.js";
17
- import "./chunk-CA6WCQ2T.js";
16
+ import "./chunk-T3U27UXC.js";
18
17
  import "./chunk-CPW6G62V.js";
18
+ import "./chunk-YRZK7HKX.js";
19
19
  import {
20
20
  FederationConflictError,
21
21
  FederationDiagnosticError,
22
22
  federateCatalog
23
- } from "./chunk-QJ7KKN2D.js";
24
- import "./chunk-WRNH5C3U.js";
25
- import "./chunk-5EPNFDT5.js";
26
- import "./chunk-A2RZR3U4.js";
27
- import "./chunk-SDZQJTJW.js";
28
- import "./chunk-352FGP6W.js";
23
+ } from "./chunk-NCEZDQSW.js";
29
24
  import "./chunk-R7Z5ALYI.js";
30
25
  import {
31
26
  getFederationDiagnosticCounts,
32
27
  getVisibleFederationDiagnostics
33
28
  } from "./chunk-JJPB6EOZ.js";
29
+ import "./chunk-WRNH5C3U.js";
30
+ import "./chunk-5EPNFDT5.js";
31
+ import "./chunk-A2RZR3U4.js";
32
+ import "./chunk-SDZQJTJW.js";
33
+ import "./chunk-352FGP6W.js";
34
34
  import {
35
35
  getProjectOutDir,
36
36
  isAuthEnabled,
@@ -39,10 +39,10 @@ import {
39
39
  } from "./chunk-NKNOXQ62.js";
40
40
  import {
41
41
  generate
42
- } from "./chunk-7ZEKF2LA.js";
42
+ } from "./chunk-DEO4QEGO.js";
43
43
  import {
44
44
  logger
45
- } from "./chunk-MC4F3VVM.js";
45
+ } from "./chunk-XBRKEQ66.js";
46
46
  import {
47
47
  resolve_catalog_dependencies_default
48
48
  } from "./chunk-PD7KTSYN.js";
@@ -79,7 +79,7 @@ import {
79
79
  } from "./chunk-LFQJXLHG.js";
80
80
  import {
81
81
  VERSION
82
- } from "./chunk-WG6ZK6L3.js";
82
+ } from "./chunk-ETS4G6RR.js";
83
83
  import {
84
84
  getEventCatalogConfigFile,
85
85
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -2,14 +2,14 @@ import {
2
2
  FederationConflictError,
3
3
  FederationDiagnosticError,
4
4
  federateCatalog
5
- } from "../chunk-QJ7KKN2D.js";
5
+ } from "../chunk-NCEZDQSW.js";
6
+ import "../chunk-R7Z5ALYI.js";
7
+ import "../chunk-JJPB6EOZ.js";
6
8
  import "../chunk-WRNH5C3U.js";
7
9
  import "../chunk-5EPNFDT5.js";
8
10
  import "../chunk-A2RZR3U4.js";
9
11
  import "../chunk-SDZQJTJW.js";
10
12
  import "../chunk-352FGP6W.js";
11
- import "../chunk-R7Z5ALYI.js";
12
- import "../chunk-JJPB6EOZ.js";
13
13
  import "../chunk-4G7FSRPN.js";
14
14
  export {
15
15
  FederationConflictError,
package/dist/generate.cjs CHANGED
@@ -105,7 +105,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
105
105
  var import_picocolors = __toESM(require("picocolors"), 1);
106
106
 
107
107
  // package.json
108
- var version = "5.5.2";
108
+ var version = "5.6.0";
109
109
 
110
110
  // src/constants.ts
111
111
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-7ZEKF2LA.js";
4
- import "./chunk-MC4F3VVM.js";
5
- import "./chunk-WG6ZK6L3.js";
3
+ } from "./chunk-DEO4QEGO.js";
4
+ import "./chunk-XBRKEQ66.js";
5
+ import "./chunk-ETS4G6RR.js";
6
6
  import "./chunk-4G7FSRPN.js";
7
7
  export {
8
8
  generate
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(cli_logger_exports);
36
36
  var import_picocolors = __toESM(require("picocolors"), 1);
37
37
 
38
38
  // package.json
39
- var version = "5.5.2";
39
+ var version = "5.6.0";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "../chunk-MC4F3VVM.js";
4
- import "../chunk-WG6ZK6L3.js";
3
+ } from "../chunk-XBRKEQ66.js";
4
+ import "../chunk-ETS4G6RR.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="m10 13-2 2 2 2"/><path d="m14 17 2-2-2-2"/></svg>
@@ -408,10 +408,16 @@ const fadeInStyles = {
408
408
  };
409
409
 
410
410
  // Preprocess markdown to fix common formatting issues
411
- const preprocessMarkdown = (text: string): string => {
412
- // Add newlines before headings if they're directly after text (no newline)
413
- // This fixes cases like "some text.## Heading" → "some text.\n\n## Heading"
414
- return text.replace(/([^\n])(#{1,6}\s)/g, '$1\n\n$2');
411
+ export const preprocessMarkdown = (text: string): string => {
412
+ return (
413
+ text
414
+ // Add newlines before headings if they're directly after text (no newline)
415
+ // This fixes cases like "some text.## Heading" → "some text.\n\n## Heading"
416
+ .replace(/([^\n])(#{1,6}\s)/g, '$1\n\n$2')
417
+ // Show a link still streaming in ("[Order Service](/docs/serv") as its text: shown raw, its URL wraps onto more
418
+ // lines until the closing bracket arrives, then the answer jumps back as it collapses into a link
419
+ .replace(/\[([^\]\n]*)\]\([^)\s]*$/, '$1')
420
+ );
415
421
  };
416
422
 
417
423
  // Helper to extract text content from message parts
@@ -564,9 +570,12 @@ const modalMarkdownComponents = {
564
570
  const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
565
571
  const inputRef = useRef<HTMLTextAreaElement>(null);
566
572
  const modalInputRef = useRef<HTMLTextAreaElement>(null);
567
- const messagesEndRef = useRef<HTMLDivElement>(null);
568
- const modalMessagesEndRef = useRef<HTMLDivElement>(null);
569
573
  const messagesContainerRef = useRef<HTMLDivElement>(null);
574
+ const modalMessagesContainerRef = useRef<HTMLDivElement>(null);
575
+ // Follow the answer as it streams, until the person scrolls up to read: sending a message or the scroll button
576
+ // follows it again
577
+ const followLatest = useRef(true);
578
+ const lastScrollTop = useRef(new WeakMap<HTMLElement, number>());
570
579
  const [inputValue, setInputValue] = useState('');
571
580
  const [isSetupThinking, setIsSetupThinking] = useState(false);
572
581
  const setupReplyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -647,10 +656,14 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
647
656
  return null;
648
657
  }, [pathname]);
649
658
 
650
- // Handle scroll to detect if user scrolled up
659
+ // Stop following the answer when the person scrolls up, and follow it again when they're back at the bottom.
660
+ // Only a move up stops it: content growing below doesn't scroll, and a scroll down is heading for the latest.
651
661
  const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
652
- const target = e.target as HTMLDivElement;
662
+ const target = e.currentTarget;
653
663
  const isNearBottom = target.scrollHeight - target.scrollTop - target.clientHeight < 100;
664
+ if (isNearBottom) followLatest.current = true;
665
+ else if (target.scrollTop < (lastScrollTop.current.get(target) ?? 0)) followLatest.current = false;
666
+ lastScrollTop.current.set(target, target.scrollTop);
654
667
  setShowScrollButton(!isNearBottom);
655
668
  }, []);
656
669
 
@@ -685,16 +698,24 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
685
698
  // Get currently running tools from the last assistant message
686
699
  const runningTools = useMemo(() => (lastAssistantMessage ? getRunningTools(lastAssistantMessage) : []), [lastAssistantMessage]);
687
700
 
688
- // Scroll to bottom when new messages arrive
689
- const scrollToBottom = useCallback(() => {
690
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
701
+ // Jump the messages (in the panel and the fullscreen modal) to the latest. Instantly: a smooth scroll restarted on
702
+ // every streamed token lands short of the growing answer and scrolls back and forth.
703
+ const scrollToLatest = useCallback(() => {
704
+ for (const container of [messagesContainerRef.current, modalMessagesContainerRef.current]) {
705
+ if (!container) continue;
706
+ container.scrollTop = container.scrollHeight;
707
+ lastScrollTop.current.set(container, container.scrollTop);
708
+ }
691
709
  }, []);
692
710
 
711
+ const scrollToBottom = useCallback(() => {
712
+ followLatest.current = true;
713
+ scrollToLatest();
714
+ }, [scrollToLatest]);
715
+
693
716
  useEffect(() => {
694
- scrollToBottom();
695
- // Also scroll modal messages
696
- modalMessagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
697
- }, [messages, scrollToBottom]);
717
+ if (followLatest.current) scrollToLatest();
718
+ }, [messages, scrollToLatest]);
698
719
 
699
720
  // Focus modal input when fullscreen opens
700
721
  useEffect(() => {
@@ -771,6 +792,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
771
792
  (text: string) => {
772
793
  if (!text.trim() || isLoading) return;
773
794
  setInputValue('');
795
+ followLatest.current = true;
774
796
  if (!configured) {
775
797
  setMessages((previous) => [...previous, { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text }] }]);
776
798
  setIsSetupThinking(true);
@@ -1075,8 +1097,6 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1075
1097
  </div>
1076
1098
  </div>
1077
1099
  ))}
1078
-
1079
- <div ref={messagesEndRef} />
1080
1100
  </div>
1081
1101
  )}
1082
1102
  </div>
@@ -1265,7 +1285,7 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1265
1285
  </div>
1266
1286
 
1267
1287
  {/* Modal Content */}
1268
- <div className="flex-1 overflow-y-auto px-6 py-6">
1288
+ <div ref={modalMessagesContainerRef} onScroll={handleScroll} className="flex-1 overflow-y-auto px-6 py-6">
1269
1289
  {!hasMessages ? (
1270
1290
  /* Welcome area - Clean design */
1271
1291
  <div className="flex flex-col h-full max-w-2xl mx-auto">
@@ -1383,8 +1403,6 @@ const ChatPanel = ({ isOpen, onClose, configured = false }: ChatPanelProps) => {
1383
1403
  </div>
1384
1404
  </div>
1385
1405
  ))}
1386
-
1387
- <div ref={modalMessagesEndRef} />
1388
1406
  </div>
1389
1407
  )}
1390
1408
  </div>
@@ -1,6 +1,6 @@
1
1
  import { buildUrl } from '@utils/url-builder';
2
2
 
3
- export type SpecificationType = 'openapi' | 'asyncapi' | 'graphql';
3
+ export type SpecificationType = 'openapi' | 'asyncapi' | 'graphql' | 'generic';
4
4
 
5
5
  export interface Specification {
6
6
  type: SpecificationType;
@@ -18,6 +18,8 @@ export const getSpecUrl = (spec: Specification, serviceId: string, serviceVersio
18
18
  return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/asyncapi/${spec.filenameWithoutExtension}`);
19
19
  case 'graphql':
20
20
  return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/graphql/${spec.filenameWithoutExtension}`);
21
+ case 'generic':
22
+ return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/generic/${spec.filenameWithoutExtension}`);
21
23
  default:
22
24
  return '#';
23
25
  }
@@ -31,6 +33,8 @@ export const getSpecIcon = (type: string): string => {
31
33
  return 'asyncapi';
32
34
  case 'graphql':
33
35
  return 'graphql';
36
+ case 'generic':
37
+ return 'specification';
34
38
  default:
35
39
  return 'json-schema';
36
40
  }
@@ -44,6 +48,8 @@ export const getSpecLabel = (type: string): string => {
44
48
  return 'AsyncAPI';
45
49
  case 'graphql':
46
50
  return 'GraphQL';
51
+ case 'generic':
52
+ return 'Specification';
47
53
  default:
48
54
  return type;
49
55
  }
@@ -390,7 +390,7 @@ const tooltipId = `ref-tooltip-${Math.random().toString(36).slice(2, 9)}`;
390
390
  href={getSpecUrl(spec, resourceId, resource?.data?.version)}
391
391
  class="hover:underline hover:text-[rgb(var(--ec-accent))]"
392
392
  >
393
- {getSpecLabel(spec.type)}
393
+ {spec.type === 'generic' && spec.name ? spec.name : getSpecLabel(spec.type)}
394
394
  </a>
395
395
  {idx < specifications.length - 1 && ', '}
396
396
  </>