@eventcatalog/core 3.0.0-beta.13 → 3.0.0-beta.15

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 (30) 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 +3 -3
  5. package/dist/{chunk-TTSVZOOO.js → chunk-2OAZAOST.js} +1 -1
  6. package/dist/{chunk-GDNZSDL4.js → chunk-DOIHDKWQ.js} +1 -1
  7. package/dist/{chunk-SXOMOZU7.js → chunk-PUAOIG2V.js} +1 -1
  8. package/dist/{chunk-URNXOM2X.js → chunk-QCA2JO24.js} +1 -1
  9. package/dist/{chunk-HVITNJND.js → chunk-XD34X2CH.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +2 -1
  13. package/dist/eventcatalog.js +6 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/src/components/Header.astro +18 -2
  19. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +5 -2
  20. package/eventcatalog/src/layouts/Footer.astro +8 -5
  21. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +30 -11
  22. package/eventcatalog/src/pages/_index.astro +3 -2
  23. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +15 -3
  24. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +7 -7
  25. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
  26. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +5 -5
  27. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +178 -0
  28. package/eventcatalog/src/pages/schemas/explorer/index.astro +5 -155
  29. package/eventcatalog/src/utils/resource-files.ts +86 -0
  30. package/package.json +2 -1
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "3.0.0-beta.13";
40
+ var version = "3.0.0-beta.15";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-TTSVZOOO.js";
4
- import "../chunk-SXOMOZU7.js";
3
+ } from "../chunk-2OAZAOST.js";
4
+ import "../chunk-PUAOIG2V.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "3.0.0-beta.13";
109
+ var version = "3.0.0-beta.15";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-URNXOM2X.js";
4
- import "../chunk-TTSVZOOO.js";
5
- import "../chunk-SXOMOZU7.js";
3
+ } from "../chunk-QCA2JO24.js";
4
+ import "../chunk-2OAZAOST.js";
5
+ import "../chunk-PUAOIG2V.js";
6
6
  import "../chunk-UPONRQSN.js";
7
7
  export {
8
8
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-SXOMOZU7.js";
3
+ } from "./chunk-PUAOIG2V.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-SXOMOZU7.js";
3
+ } from "./chunk-PUAOIG2V.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.0.0-beta.13";
2
+ var version = "3.0.0-beta.15";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-TTSVZOOO.js";
3
+ } from "./chunk-2OAZAOST.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-GDNZSDL4.js";
3
+ } from "./chunk-DOIHDKWQ.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "3.0.0-beta.13";
28
+ var version = "3.0.0-beta.15";
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-SXOMOZU7.js";
3
+ } from "./chunk-PUAOIG2V.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -109,7 +109,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
109
109
  var import_picocolors = __toESM(require("picocolors"), 1);
110
110
 
111
111
  // package.json
112
- var version = "3.0.0-beta.13";
112
+ var version = "3.0.0-beta.15";
113
113
 
114
114
  // src/constants.ts
115
115
  var VERSION = version;
@@ -921,6 +921,7 @@ program.command("start").description("Serves the contents of your eventcatalog b
921
921
  );
922
922
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
923
923
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
924
+ await copyServerFiles();
924
925
  const isServerOutput = await isOutputServer();
925
926
  if (isServerOutput) {
926
927
  startServerCatalog({
@@ -6,8 +6,8 @@ import {
6
6
  } from "./chunk-PLNJC7NZ.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-URNXOM2X.js";
10
- import "./chunk-TTSVZOOO.js";
9
+ } from "./chunk-QCA2JO24.js";
10
+ import "./chunk-2OAZAOST.js";
11
11
  import {
12
12
  runMigrations
13
13
  } from "./chunk-BH3JMNAV.js";
@@ -23,13 +23,13 @@ import {
23
23
  } from "./chunk-5VBIXL6C.js";
24
24
  import {
25
25
  generate
26
- } from "./chunk-HVITNJND.js";
26
+ } from "./chunk-XD34X2CH.js";
27
27
  import {
28
28
  logger
29
- } from "./chunk-GDNZSDL4.js";
29
+ } from "./chunk-DOIHDKWQ.js";
30
30
  import {
31
31
  VERSION
32
- } from "./chunk-SXOMOZU7.js";
32
+ } from "./chunk-PUAOIG2V.js";
33
33
  import "./chunk-UPONRQSN.js";
34
34
 
35
35
  // src/eventcatalog.ts
@@ -295,6 +295,7 @@ program.command("start").description("Serves the contents of your eventcatalog b
295
295
  );
296
296
  const isEventCatalogStarter = await isEventCatalogStarterEnabled();
297
297
  const isEventCatalogScale = await isEventCatalogScaleEnabled();
298
+ await copyServerFiles();
298
299
  const isServerOutput = await isOutputServer();
299
300
  if (isServerOutput) {
300
301
  startServerCatalog({
package/dist/generate.cjs CHANGED
@@ -73,7 +73,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
73
73
  var import_picocolors = __toESM(require("picocolors"), 1);
74
74
 
75
75
  // package.json
76
- var version = "3.0.0-beta.13";
76
+ var version = "3.0.0-beta.15";
77
77
 
78
78
  // src/constants.ts
79
79
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-HVITNJND.js";
4
- import "./chunk-GDNZSDL4.js";
5
- import "./chunk-SXOMOZU7.js";
3
+ } from "./chunk-XD34X2CH.js";
4
+ import "./chunk-DOIHDKWQ.js";
5
+ import "./chunk-PUAOIG2V.js";
6
6
  import "./chunk-UPONRQSN.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 = "3.0.0-beta.13";
39
+ var version = "3.0.0-beta.15";
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-GDNZSDL4.js";
4
- import "../chunk-SXOMOZU7.js";
3
+ } from "../chunk-DOIHDKWQ.js";
4
+ import "../chunk-PUAOIG2V.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -60,6 +60,7 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
60
60
  class="flex items-center focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400 rounded-full"
61
61
  aria-expanded="false"
62
62
  aria-haspopup="true"
63
+ aria-label="User menu"
63
64
  >
64
65
  {session.user?.image && !session.user?.image?.includes('googleusercontent.com') ? (
65
66
  <img
@@ -117,16 +118,28 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
117
118
  <a
118
119
  href="https://discord.com/invite/3rjaZMmrAm"
119
120
  class="block p-1.5 rounded-lg hover:bg-gray-100 transition-colors"
121
+ aria-label="Join our Discord community"
120
122
  >
121
- <img src={buildUrl('/icons/discord.svg', true)} class="h-6 w-6 hover:opacity-100 transition-opacity" />
123
+ <img
124
+ src={buildUrl('/icons/discord.svg', true)}
125
+ alt=""
126
+ class="h-6 w-6 hover:opacity-100 transition-opacity"
127
+ aria-hidden="true"
128
+ />
122
129
  </a>
123
130
  </li>
124
131
  <li>
125
132
  <a
126
133
  href="https://github.com/event-catalog/eventcatalog"
127
134
  class="block p-1.5 rounded-lg hover:bg-gray-100 transition-colors"
135
+ aria-label="View EventCatalog on GitHub"
128
136
  >
129
- <img src={buildUrl('/icons/github.svg', true)} class="h-6 w-6 hover:opacity-100 transition-opacity" />
137
+ <img
138
+ src={buildUrl('/icons/github.svg', true)}
139
+ alt=""
140
+ class="h-6 w-6 hover:opacity-100 transition-opacity"
141
+ aria-hidden="true"
142
+ />
130
143
  </a>
131
144
  </li>
132
145
  </ul>
@@ -137,10 +150,13 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
137
150
  <a
138
151
  href={repositoryUrl}
139
152
  class="block p-1.5 rounded-lg hover:bg-gray-100 transition-colors focus:outline-none"
153
+ aria-label="View repository on GitHub"
140
154
  >
141
155
  <img
142
156
  src={buildUrl('/icons/github.svg', true)}
157
+ alt=""
143
158
  class="h-6 w-6 opacity-70 hover:opacity-100 transition-opacity"
159
+ aria-hidden="true"
144
160
  />
145
161
  </a>
146
162
  </li>
@@ -178,8 +178,9 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
178
178
  <button
179
179
  onClick={clearSearch}
180
180
  className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
181
+ aria-label="Clear search"
181
182
  >
182
- <X className="w-4 h-4" />
183
+ <X className="w-4 h-4" aria-hidden="true" />
183
184
  </button>
184
185
  )}
185
186
  </div>
@@ -193,8 +194,10 @@ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Pro
193
194
  ? 'bg-purple-50 border-purple-200 text-purple-600'
194
195
  : 'bg-gray-50 border-gray-200 text-gray-400 hover:text-gray-600 hover:bg-gray-100'
195
196
  )}
197
+ aria-label="Filter search results"
198
+ aria-expanded={showFilterDropdown}
196
199
  >
197
- <SlidersHorizontal className="w-4 h-4" />
200
+ <SlidersHorizontal className="w-4 h-4" aria-hidden="true" />
198
201
  {searchFilters.size > 0 && (
199
202
  <span className="absolute -top-1 -right-1 w-4 h-4 bg-purple-600 text-white text-[10px] font-bold rounded-full flex items-center justify-center">
200
203
  {searchFilters.size}
@@ -9,24 +9,27 @@ const { className } = Astro.props;
9
9
  showEventCatalogBranding() && (
10
10
  <div class="flex justify-between items-center py-8 text-gray-500 text-sm font-light">
11
11
  <div class="flex space-x-5">
12
- <a href="https://github.com/event-catalog/eventcatalog" target="_blank">
12
+ <a href="https://github.com/event-catalog/eventcatalog" target="_blank" aria-label="View EventCatalog on GitHub">
13
13
  <svg
14
14
  class="w-5 h-5 bg-gray-400 hover:bg-primary dark:hover:bg-gray-400"
15
15
  style={`mask-image: url("${buildUrl('/icons/github.svg', true)}"); mask-repeat: no-repeat; mask-position: center center;`}
16
+ aria-hidden="true"
16
17
  />
17
18
  </a>
18
- <a href="https://x.com/event_catalog" target="_blank">
19
- <span class="sr-only">x</span>
19
+ <a href="https://x.com/event_catalog" target="_blank" aria-label="Follow EventCatalog on X (Twitter)">
20
+ <span class="sr-only">X (Twitter)</span>
20
21
  <svg
21
22
  class="w-5 h-5 bg-gray-400 hover:bg-primary dark:hover:bg-gray-400"
22
23
  style={`mask-image: url("${buildUrl('/icons/x-twitter.svg', true)}"); mask-repeat: no-repeat; mask-position: center center;`}
24
+ aria-hidden="true"
23
25
  />
24
26
  </a>
25
- <a href="https://www.youtube.com/@event-catalog" target="_blank">
26
- <span class="sr-only">x</span>
27
+ <a href="https://www.youtube.com/@event-catalog" target="_blank" aria-label="Watch EventCatalog on YouTube">
28
+ <span class="sr-only">YouTube</span>
27
29
  <svg
28
30
  class="w-5 h-5 bg-gray-400 hover:bg-primary dark:hover:bg-gray-400"
29
31
  style={`mask-image: url("${buildUrl('/icons/youtube.svg', true)}"); mask-repeat: no-repeat; mask-position: center center;`}
32
+ aria-hidden="true"
30
33
  />
31
34
  </a>
32
35
  </div>
@@ -248,15 +248,19 @@ const canPageBeEmbedded = isEmbedEnabled();
248
248
  id={item.id}
249
249
  data-role="nav-item"
250
250
  href={item.href}
251
+ aria-label={item.label}
251
252
  class={`p-1.5 inline-block transition-colors duration-200 rounded-lg ${
252
253
  item.current ? 'text-white bg-gray-900' : 'hover:bg-gray-800 hover:text-white text-gray-700'
253
254
  }`}
254
255
  >
255
256
  <div class="has-tooltip">
256
- <span class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap">
257
+ <span
258
+ class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap"
259
+ aria-hidden="true"
260
+ >
257
261
  {item.label}
258
262
  </span>
259
- <item.icon className="h-6 w-6" />
263
+ <item.icon className="h-6 w-6" aria-hidden="true" />
260
264
  </div>
261
265
  </a>
262
266
  );
@@ -271,13 +275,17 @@ const canPageBeEmbedded = isEmbedEnabled();
271
275
  id={studioNavigationItem[0].id}
272
276
  data-role="nav-item"
273
277
  href={studioNavigationItem[0].href}
278
+ aria-label={studioNavigationItem[0].label}
274
279
  class={`p-1.5 inline-block pt-1 pb-1 mt-0 mb-0 transition-colors duration-200 rounded-lg relative ${studioNavigationItem[0].current ? 'text-white bg-gray-900' : 'hover:bg-gray-800 hover:text-white text-gray-700'}`}
275
280
  >
276
281
  <div class="has-tooltip">
277
- <span class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap">
282
+ <span
283
+ class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap"
284
+ aria-hidden="true"
285
+ >
278
286
  {studioNavigationItem[0].label}
279
287
  </span>
280
- <SquareDashedMousePointerIcon className="h-6 w-6" />
288
+ <SquareDashedMousePointerIcon className="h-6 w-6" aria-hidden="true" />
281
289
  </div>
282
290
  </a>
283
291
  )
@@ -291,17 +299,24 @@ const canPageBeEmbedded = isEmbedEnabled();
291
299
  id={item.id}
292
300
  data-role="nav-item"
293
301
  href={item.href}
302
+ aria-label={item.label}
294
303
  class={`p-1.5 inline-block transition-colors duration-200 rounded-lg mb-8 relative ${
295
304
  item.current ? 'text-white bg-gray-900' : 'hover:bg-gray-800 hover:text-white text-gray-700'
296
305
  }`}
297
306
  >
298
307
  <div class="has-tooltip">
299
- <span class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 flex items-center gap-1 whitespace-nowrap">
300
- <Sparkles className="h-3 w-3" /> {item.label}
308
+ <span
309
+ class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 flex items-center gap-1 whitespace-nowrap"
310
+ aria-hidden="true"
311
+ >
312
+ <Sparkles className="h-3 w-3" aria-hidden="true" /> {item.label}
301
313
  </span>
302
- <item.icon className="h-6 w-6" />
303
- <div class="absolute -top-1 -right-1 bg-gradient-to-r from-amber-400 to-amber-500 rounded-full p-0.5 shadow-lg">
304
- <Sparkles className="h-2 w-2 text-white" />
314
+ <item.icon className="h-6 w-6" aria-hidden="true" />
315
+ <div
316
+ class="absolute -top-1 -right-1 bg-gradient-to-r from-amber-400 to-amber-500 rounded-full p-0.5 shadow-lg"
317
+ aria-hidden="true"
318
+ >
319
+ <Sparkles className="h-2 w-2 text-white" aria-hidden="true" />
305
320
  </div>
306
321
  </div>
307
322
  </a>
@@ -316,13 +331,17 @@ const canPageBeEmbedded = isEmbedEnabled();
316
331
  id="/pro"
317
332
  data-role="nav-item"
318
333
  href={buildUrl('/plans')}
334
+ aria-label="Upgrade EventCatalog"
319
335
  class={`p-1.5 inline-block transition-colors duration-200 rounded-lg ${currentPath.includes('/pro') ? 'text-white bg-gray-900' : 'bg-gray-200 hover:bg-gray-800 hover:text-white text-gray-700'}`}
320
336
  >
321
337
  <div class="has-tooltip">
322
- <span class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap">
338
+ <span
339
+ class="tooltip rounded shadow-lg p-1 text-xs bg-gray-900 text-white ml-10 whitespace-nowrap"
340
+ aria-hidden="true"
341
+ >
323
342
  Upgrade EventCatalog
324
343
  </span>
325
- <Rocket className="h-6 w-6" />
344
+ <Rocket className="h-6 w-6" aria-hidden="true" />
326
345
  </div>
327
346
  </a>
328
347
  </div>
@@ -304,6 +304,7 @@ const quickActions = [
304
304
  <button
305
305
  data-search-trigger
306
306
  class="group flex items-center gap-3 w-full px-4 py-3 bg-white border-2 border-gray-200 rounded-lg hover:border-blue-400 hover:shadow-md transition-all cursor-pointer"
307
+ aria-label="Search events, services, and domains"
307
308
  >
308
309
  <svg
309
310
  class="w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors"
@@ -625,7 +626,7 @@ const quickActions = [
625
626
  target="_blank"
626
627
  class="group inline-flex items-center gap-2 px-5 py-2.5 bg-gray-900 text-white rounded-lg font-medium hover:bg-gray-800 transition-all shadow-sm"
627
628
  >
628
- <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
629
+ <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
629
630
  <path
630
631
  d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"
631
632
  ></path>
@@ -637,7 +638,7 @@ const quickActions = [
637
638
  target="_blank"
638
639
  class="group inline-flex items-center gap-2 px-5 py-2.5 bg-white text-gray-900 border border-gray-300 rounded-lg font-medium hover:border-gray-400 hover:bg-gray-50 transition-all"
639
640
  >
640
- <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
641
+ <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
641
642
  <path
642
643
  fill-rule="evenodd"
643
644
  d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
@@ -69,9 +69,21 @@ const pagefindAttributes =
69
69
  </VerticalSideBarLayout>
70
70
 
71
71
  <script is:inline src={js}></script>
72
- <script define:vars={{ schema: stringified, config }}>
73
- const root = document.getElementById('asyncapi');
74
- AsyncApiStandalone.hydrate({ schema, config }, root);
72
+ <script is:inline define:vars={{ schema: stringified, config }}>
73
+ function initAsyncApi() {
74
+ const root = document.getElementById('asyncapi');
75
+ if (!root || root.dataset.initialized) return;
76
+
77
+ if (typeof AsyncApiStandalone !== 'undefined') {
78
+ AsyncApiStandalone.render({ schema, config }, root);
79
+ root.dataset.initialized = 'true';
80
+ } else {
81
+ setTimeout(initAsyncApi, 50);
82
+ }
83
+ }
84
+
85
+ document.addEventListener('astro:page-load', initAsyncApi);
86
+ initAsyncApi();
75
87
  </script>
76
88
 
77
89
  <style>
@@ -73,16 +73,16 @@ const logList = await Promise.all(logListPromise);
73
73
 
74
74
  const getBadge = () => {
75
75
  if (props.collection === 'services') {
76
- return { backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-400' };
76
+ return { backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-600' };
77
77
  }
78
78
  if (props.collection === 'events') {
79
- return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-400' };
79
+ return { backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-600' };
80
80
  }
81
81
  if (props.collection === 'commands') {
82
- return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-400' };
82
+ return { backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-600' };
83
83
  }
84
84
  if (props.collection === 'queries') {
85
- return { backgroundColor: 'green', textColor: 'green', content: 'Query', icon: MagnifyingGlassIcon, class: 'text-blue-400' };
85
+ return { backgroundColor: 'green', textColor: 'green', content: 'Query', icon: MagnifyingGlassIcon, class: 'text-green-600' };
86
86
  }
87
87
  if (props.collection === 'domains') {
88
88
  return {
@@ -90,14 +90,14 @@ const getBadge = () => {
90
90
  textColor: 'yellow',
91
91
  content: 'Domain',
92
92
  icon: RectangleGroupIcon,
93
- class: 'text-yellow-400',
93
+ class: 'text-yellow-600',
94
94
  };
95
95
  }
96
96
  if (props.collection === 'containers') {
97
- return { backgroundColor: 'blue', textColor: 'blue', content: 'Container', icon: DatabaseIcon, class: 'text-blue-400' };
97
+ return { backgroundColor: 'blue', textColor: 'blue', content: 'Container', icon: DatabaseIcon, class: 'text-blue-600' };
98
98
  }
99
99
  if (props.collection === 'flows') {
100
- return { backgroundColor: 'teal', textColor: 'teal', content: 'Flow', icon: QueueListIcon, class: 'text-teal-400' };
100
+ return { backgroundColor: 'teal', textColor: 'teal', content: 'Flow', icon: QueueListIcon, class: 'text-teal-600' };
101
101
  }
102
102
  };
103
103
 
@@ -36,7 +36,7 @@ if (isRemote) {
36
36
  const pageTitle = `${collection} | ${data.name} | GraphQL Schema`.replace(/^\w/, (c) => c.toUpperCase());
37
37
 
38
38
  const getServiceBadge = () => {
39
- return [{ backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-400' }];
39
+ return [{ backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-600' }];
40
40
  };
41
41
 
42
42
  const getGraphQLBadge = () => {
@@ -71,17 +71,17 @@ const getContentBadges = () =>
71
71
 
72
72
  const getBadge = () => {
73
73
  if (props.collection === 'services') {
74
- return [{ backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-400' }];
74
+ return [{ backgroundColor: 'pink', textColor: 'pink', content: 'Service', icon: ServerIcon, class: 'text-pink-600' }];
75
75
  }
76
76
  if (props.collection === 'events') {
77
- return [{ backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-400' }];
77
+ return [{ backgroundColor: 'orange', textColor: 'orange', content: 'Event', icon: BoltIcon, class: 'text-orange-600' }];
78
78
  }
79
79
  if (props.collection === 'commands') {
80
- return [{ backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-400' }];
80
+ return [{ backgroundColor: 'blue', textColor: 'blue', content: 'Command', icon: ChatBubbleLeftIcon, class: 'text-blue-600' }];
81
81
  }
82
82
  if (props.collection === 'queries') {
83
83
  return [
84
- { backgroundColor: 'green', textColor: 'green', content: 'Query', icon: MagnifyingGlassIcon, class: 'text-green-400' },
84
+ { backgroundColor: 'green', textColor: 'green', content: 'Query', icon: MagnifyingGlassIcon, class: 'text-green-600' },
85
85
  ];
86
86
  }
87
87
  if (props.collection === 'domains') {
@@ -91,7 +91,7 @@ const getBadge = () => {
91
91
  textColor: 'yellow',
92
92
  content: 'Domain',
93
93
  icon: RectangleGroupIcon,
94
- class: 'text-yellow-400',
94
+ class: 'text-yellow-600',
95
95
  },
96
96
  ];
97
97
  }
@@ -0,0 +1,178 @@
1
+ import { isSSR } from '@utils/feature';
2
+ import { HybridPage } from '@utils/page-loaders/hybrid-page';
3
+ import { getEvents } from '@utils/collections/events';
4
+ import { getCommands } from '@utils/collections/commands';
5
+ import { getQueries } from '@utils/collections/queries';
6
+ import { getServices, getSpecificationsForService } from '@utils/collections/services';
7
+ import { getOwner } from '@utils/collections/owners';
8
+ import { buildUrl } from '@utils/url-builder';
9
+ import { resourceFileExists, readResourceFile } from '@utils/resource-files';
10
+ import path from 'path';
11
+
12
+ // Helper function to enrich owners with full details
13
+ async function enrichOwners(ownersRaw: any[]) {
14
+ if (!ownersRaw || ownersRaw.length === 0) return [];
15
+
16
+ const owners = await Promise.all(ownersRaw.map(getOwner));
17
+ const filteredOwners = owners.filter((o) => o !== undefined);
18
+
19
+ return filteredOwners.map((o) => ({
20
+ id: o.data.id,
21
+ name: o.data.name,
22
+ type: o.collection,
23
+ href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
24
+ }));
25
+ }
26
+
27
+ async function fetchAllSchemas() {
28
+ // Fetch all messages
29
+ const events = await getEvents({ getAllVersions: true });
30
+ const commands = await getCommands({ getAllVersions: true });
31
+ const queries = await getQueries({ getAllVersions: true });
32
+
33
+ // Fetch all services
34
+ const services = await getServices({ getAllVersions: true });
35
+
36
+ // Combine all messages
37
+ const allMessages = [...events, ...commands, ...queries];
38
+
39
+ // Filter messages with schemas and read schema content - only keep essential data
40
+ const messagesWithSchemas = await Promise.all(
41
+ allMessages
42
+ .filter((message) => message.data.schemaPath)
43
+ .filter((message) => resourceFileExists(message, message.data.schemaPath ?? ''))
44
+ .map(async (message) => {
45
+ try {
46
+ const schemaPath = message.data.schemaPath ?? '';
47
+ const schemaContent = readResourceFile(message, schemaPath) ?? '';
48
+ const schemaExtension = path.extname(schemaPath).slice(1);
49
+ const enrichedOwners = await enrichOwners(message.data.owners || []);
50
+
51
+ return {
52
+ collection: message.collection,
53
+ data: {
54
+ id: message.data.id,
55
+ name: message.data.name,
56
+ version: message.data.version,
57
+ summary: message.data.summary,
58
+ schemaPath: message.data.schemaPath,
59
+ producers: message.data.producers || [],
60
+ consumers: message.data.consumers || [],
61
+ owners: enrichedOwners,
62
+ },
63
+ schemaContent,
64
+ schemaExtension,
65
+ };
66
+ } catch (error) {
67
+ console.error(`Error reading schema for ${message.data.id}:`, error);
68
+ const enrichedOwners = await enrichOwners(message.data.owners || []);
69
+ return {
70
+ collection: message.collection,
71
+ data: {
72
+ id: message.data.id,
73
+ name: message.data.name,
74
+ version: message.data.version,
75
+ summary: message.data.summary,
76
+ schemaPath: message.data.schemaPath,
77
+ producers: message.data.producers || [],
78
+ consumers: message.data.consumers || [],
79
+ owners: enrichedOwners,
80
+ },
81
+ schemaContent: '',
82
+ schemaExtension: 'json',
83
+ };
84
+ }
85
+ })
86
+ );
87
+
88
+ // Filter services with specifications and read spec content - only keep essential data
89
+ const servicesWithSpecs = await Promise.all(
90
+ services.map(async (service) => {
91
+ try {
92
+ const specifications = getSpecificationsForService(service);
93
+
94
+ if (specifications.length === 0) {
95
+ return null;
96
+ }
97
+
98
+ return await Promise.all(
99
+ specifications.map(async (spec) => {
100
+ if (!resourceFileExists(service, spec.path)) {
101
+ return null;
102
+ }
103
+
104
+ const schemaContent = readResourceFile(service, spec.path) ?? '';
105
+ const schemaExtension = spec.type;
106
+ const enrichedOwners = await enrichOwners(service.data.owners || []);
107
+
108
+ return {
109
+ collection: 'services',
110
+ data: {
111
+ id: `${service.data.id}`,
112
+ name: `${service.data.name} - ${spec.name}`,
113
+ version: service.data.version,
114
+ summary: service.data.summary,
115
+ schemaPath: spec.path,
116
+ owners: enrichedOwners,
117
+ },
118
+ schemaContent,
119
+ schemaExtension,
120
+ specType: spec.type,
121
+ specName: spec.name,
122
+ specFilenameWithoutExtension: spec.filenameWithoutExtension,
123
+ };
124
+ })
125
+ );
126
+ } catch (error) {
127
+ console.error(`Error reading specifications for service ${service.data.id}:`, error);
128
+ return null;
129
+ }
130
+ })
131
+ );
132
+
133
+ // Flatten and filter out null values
134
+ const flatServicesWithSpecs = servicesWithSpecs.flat().filter((service) => service !== null);
135
+
136
+ return [...messagesWithSchemas, ...flatServicesWithSpecs];
137
+ }
138
+
139
+ export class Page extends HybridPage {
140
+ static get prerender(): boolean {
141
+ return !isSSR();
142
+ }
143
+
144
+ static async getStaticPaths(): Promise<Array<{ params: any; props: any }>> {
145
+ if (isSSR()) {
146
+ return [];
147
+ }
148
+
149
+ const allSchemas = await fetchAllSchemas();
150
+
151
+ return [
152
+ {
153
+ params: {},
154
+ props: {
155
+ schemas: allSchemas,
156
+ },
157
+ },
158
+ ];
159
+ }
160
+
161
+ protected static async fetchData(_params: any) {
162
+ const allSchemas = await fetchAllSchemas();
163
+ return {
164
+ schemas: allSchemas,
165
+ };
166
+ }
167
+
168
+ protected static hasValidProps(props: any): boolean {
169
+ return props && props.schemas !== undefined;
170
+ }
171
+
172
+ protected static createNotFoundResponse(): Response {
173
+ return new Response(null, {
174
+ status: 404,
175
+ statusText: 'Schema explorer not found',
176
+ });
177
+ }
178
+ }
@@ -1,163 +1,13 @@
1
1
  ---
2
2
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
3
- import { getEvents } from '@utils/collections/events';
4
- import { getCommands } from '@utils/collections/commands';
5
- import { getQueries } from '@utils/collections/queries';
6
- import { getServices, getSpecificationsForService } from '@utils/collections/services';
7
3
  import SchemaExplorer from '@components/SchemaExplorer/SchemaExplorer';
8
4
  import { isEventCatalogScaleEnabled } from '@utils/feature';
9
- import { getOwner } from '@utils/collections/owners';
10
- import { buildUrl } from '@utils/url-builder';
11
- import fs from 'fs';
12
- import path from 'path';
5
+ import { Page } from './_index.data';
13
6
 
14
- // Fetch all messages
15
- const events = await getEvents({ getAllVersions: true });
16
- const commands = await getCommands({ getAllVersions: true });
17
- const queries = await getQueries({ getAllVersions: true });
7
+ export const prerender = Page.prerender;
8
+ export const getStaticPaths = Page.getStaticPaths;
18
9
 
19
- // Fetch all services
20
- const services = await getServices({ getAllVersions: true });
21
-
22
- // Combine all messages
23
- const allMessages = [...events, ...commands, ...queries];
24
-
25
- // Helper function to enrich owners with full details
26
- async function enrichOwners(ownersRaw: any[]) {
27
- if (!ownersRaw || ownersRaw.length === 0) return [];
28
-
29
- const owners = await Promise.all(ownersRaw.map(getOwner));
30
- const filteredOwners = owners.filter((o) => o !== undefined);
31
-
32
- return filteredOwners.map((o) => ({
33
- id: o.data.id,
34
- name: o.data.name,
35
- type: o.collection,
36
- href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
37
- }));
38
- }
39
-
40
- // Filter messages with schemas and read schema content - only keep essential data
41
- const messagesWithSchemas = await Promise.all(
42
- allMessages
43
- .filter((message) => message.data.schemaPath)
44
- // Make sure the file exists
45
- .filter((message) => fs.existsSync(path.join(path.dirname(message.filePath ?? ''), message.data.schemaPath ?? '')))
46
- .map(async (message) => {
47
- try {
48
- // Get the schema file path
49
- const schemaPath = message.data.schemaPath;
50
- const fullSchemaPath = path.join(path.dirname(message.filePath ?? ''), schemaPath ?? '');
51
-
52
- // Read the schema content
53
- let schemaContent = '';
54
- if (fs.existsSync(fullSchemaPath)) {
55
- schemaContent = fs.readFileSync(fullSchemaPath, 'utf-8');
56
- }
57
-
58
- // Get schema file extension
59
- const schemaExtension = path.extname(schemaPath ?? '').slice(1);
60
-
61
- // Enrich owners with full details
62
- const enrichedOwners = await enrichOwners(message.data.owners || []);
63
-
64
- // Only return essential data - strip out markdown, full data objects, etc.
65
- return {
66
- collection: message.collection,
67
- data: {
68
- id: message.data.id,
69
- name: message.data.name,
70
- version: message.data.version,
71
- summary: message.data.summary,
72
- schemaPath: message.data.schemaPath,
73
- producers: message.data.producers || [],
74
- consumers: message.data.consumers || [],
75
- owners: enrichedOwners,
76
- },
77
- schemaContent,
78
- schemaExtension,
79
- };
80
- } catch (error) {
81
- console.error(`Error reading schema for ${message.data.id}:`, error);
82
- const enrichedOwners = await enrichOwners(message.data.owners || []);
83
- return {
84
- collection: message.collection,
85
- data: {
86
- id: message.data.id,
87
- name: message.data.name,
88
- version: message.data.version,
89
- summary: message.data.summary,
90
- schemaPath: message.data.schemaPath,
91
- producers: message.data.producers || [],
92
- consumers: message.data.consumers || [],
93
- owners: enrichedOwners,
94
- },
95
- schemaContent: '',
96
- schemaExtension: 'json',
97
- };
98
- }
99
- })
100
- );
101
-
102
- // Filter services with specifications and read spec content - only keep essential data
103
- const servicesWithSpecs = await Promise.all(
104
- services.map(async (service) => {
105
- try {
106
- const specifications = getSpecificationsForService(service);
107
-
108
- // Only include services that have specifications
109
- if (specifications.length === 0) {
110
- return null;
111
- }
112
-
113
- // Process each specification file for this service
114
- return await Promise.all(
115
- specifications.map(async (spec) => {
116
- const specPath = path.join(path.dirname(service.filePath ?? ''), spec.path);
117
-
118
- // Only include if the spec file exists
119
- if (!fs.existsSync(specPath)) {
120
- return null;
121
- }
122
-
123
- const schemaContent = fs.readFileSync(specPath, 'utf-8');
124
- // Use spec type (openapi, asyncapi) as the extension for proper labeling
125
- const schemaExtension = spec.type;
126
-
127
- // Enrich owners with full details
128
- const enrichedOwners = await enrichOwners(service.data.owners || []);
129
-
130
- // Only return essential data - strip out markdown, sends/receives, entities, etc.
131
- return {
132
- collection: 'services',
133
- data: {
134
- id: `${service.data.id}`,
135
- name: `${service.data.name} - ${spec.name}`,
136
- version: service.data.version,
137
- summary: service.data.summary,
138
- schemaPath: spec.path,
139
- owners: enrichedOwners,
140
- },
141
- schemaContent,
142
- schemaExtension,
143
- specType: spec.type,
144
- specName: spec.name,
145
- specFilenameWithoutExtension: spec.filenameWithoutExtension,
146
- };
147
- })
148
- );
149
- } catch (error) {
150
- console.error(`Error reading specifications for service ${service.data.id}:`, error);
151
- return null;
152
- }
153
- })
154
- );
155
-
156
- // Flatten and filter out null values
157
- const flatServicesWithSpecs = servicesWithSpecs.flat().filter((service) => service !== null);
158
-
159
- // Combine messages and services
160
- const allSchemas = [...messagesWithSchemas, ...flatServicesWithSpecs];
10
+ const { schemas } = await Page.getData(Astro);
161
11
 
162
12
  const apiAccessEnabled = isEventCatalogScaleEnabled();
163
13
  ---
@@ -167,7 +17,7 @@ const apiAccessEnabled = isEventCatalogScaleEnabled();
167
17
  <div class="flex docs-layout w-full h-full">
168
18
  <div class="w-full lg:mr-2 pr-8 py-6 flex flex-col h-full">
169
19
  <div class="w-full !max-w-none h-full flex flex-col overflow-hidden">
170
- <SchemaExplorer client:load schemas={allSchemas as any} apiAccessEnabled={apiAccessEnabled} />
20
+ <SchemaExplorer client:load schemas={schemas as any} apiAccessEnabled={apiAccessEnabled} />
171
21
  </div>
172
22
  </div>
173
23
  </div>
@@ -0,0 +1,86 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { isSSR } from '@utils/feature';
4
+
5
+ /**
6
+ * Get the absolute base path for a resource item.
7
+ *
8
+ * In SSR mode, filePath is relative to the Astro core directory (e.g., "../examples/default/domains/...").
9
+ * We need to resolve it using PROJECT_DIR to get the correct absolute path.
10
+ *
11
+ * In static mode, filePath is resolved correctly by Astro's build context.
12
+ *
13
+ * @param item - The resource item with a filePath property
14
+ * @returns The absolute path to the directory containing the resource
15
+ */
16
+ export function getResourceBasePath(item: { filePath?: string }): string {
17
+ if (!item.filePath) {
18
+ return '';
19
+ }
20
+
21
+ const filePath = item.filePath;
22
+
23
+ // In SSR mode, we need to resolve the relative path using PROJECT_DIR
24
+ if (isSSR()) {
25
+ const PROJECT_DIR = process.env.PROJECT_DIR || '';
26
+
27
+ if (PROJECT_DIR) {
28
+ // Get the project folder name from PROJECT_DIR (e.g., "default" from ".../examples/default")
29
+ const projectFolderName = path.basename(PROJECT_DIR);
30
+
31
+ // Find the project folder in the relative path and extract everything after it
32
+ // Pattern: ../examples/default/domains/... -> domains/...
33
+ const regex = new RegExp(`.*?${projectFolderName}/(.+)$`);
34
+ const match = filePath.match(regex);
35
+
36
+ if (match && match[1]) {
37
+ // Join PROJECT_DIR with the relative path within the project
38
+ return path.join(PROJECT_DIR, path.dirname(match[1]));
39
+ }
40
+ }
41
+ }
42
+
43
+ // Static mode: resolve directly using Astro's build context
44
+ return path.dirname(path.resolve(filePath));
45
+ }
46
+
47
+ /**
48
+ * Get the absolute path to a file within a resource directory.
49
+ *
50
+ * @param item - The resource item with a filePath property
51
+ * @param relativePath - The relative path to the file (e.g., "schema.json")
52
+ * @returns The absolute path to the file
53
+ */
54
+ export function getResourceFilePath(item: { filePath?: string }, relativePath: string): string {
55
+ const basePath = getResourceBasePath(item);
56
+ return path.join(basePath, relativePath);
57
+ }
58
+
59
+ /**
60
+ * Check if a file exists within a resource directory.
61
+ *
62
+ * @param item - The resource item with a filePath property
63
+ * @param relativePath - The relative path to the file (e.g., "schema.json")
64
+ * @returns True if the file exists, false otherwise
65
+ */
66
+ export function resourceFileExists(item: { filePath?: string }, relativePath: string): boolean {
67
+ const filePath = getResourceFilePath(item, relativePath);
68
+ return fs.existsSync(filePath);
69
+ }
70
+
71
+ /**
72
+ * Read a file from a resource directory.
73
+ *
74
+ * @param item - The resource item with a filePath property
75
+ * @param relativePath - The relative path to the file (e.g., "schema.json")
76
+ * @returns The file content as a string, or null if the file doesn't exist
77
+ */
78
+ export function readResourceFile(item: { filePath?: string }, relativePath: string): string | null {
79
+ const filePath = getResourceFilePath(item, relativePath);
80
+
81
+ if (!fs.existsSync(filePath)) {
82
+ return null;
83
+ }
84
+
85
+ return fs.readFileSync(filePath, 'utf-8');
86
+ }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/event-catalog/eventcatalog.git"
7
7
  },
8
8
  "type": "module",
9
- "version": "3.0.0-beta.13",
9
+ "version": "3.0.0-beta.15",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -147,6 +147,7 @@
147
147
  "preview": "astro preview",
148
148
  "astro": "astro",
149
149
  "start:catalog": "node scripts/start-catalog-locally.js",
150
+ "start:catalog:server": "node scripts/start-server-locally.js",
150
151
  "pagefind": "node scripts/pagefind.js",
151
152
  "preview:catalog": "node scripts/preview-catalog-locally.js",
152
153
  "generate:catalog": "node scripts/generate-catalog-locally.js",