@eventcatalog/core 5.0.0-beta.2 → 5.0.0-beta.20
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/LICENSE +234 -134
- package/README.md +5 -5
- package/dist/analytics/analytics.cjs +18 -3
- package/dist/analytics/analytics.d.cts +1 -1
- package/dist/analytics/analytics.d.ts +1 -1
- package/dist/analytics/analytics.js +3 -2
- package/dist/analytics/log-build.cjs +71 -35
- package/dist/analytics/log-build.js +5 -4
- package/dist/analytics/telemetry.cjs +42 -0
- package/dist/analytics/telemetry.d.cts +20 -0
- package/dist/analytics/telemetry.d.ts +20 -0
- package/dist/analytics/telemetry.js +8 -0
- package/dist/catalog-runtime.cjs +1 -1
- package/dist/{chunk-HGRFXTFC.js → chunk-3VQSVQTU.js} +1 -1
- package/dist/{chunk-KIDISU6X.js → chunk-5ZUN2TXB.js} +56 -33
- package/dist/{chunk-TQLRG35T.js → chunk-AWOO63ME.js} +71 -45
- package/dist/chunk-CPW6G62V.js +17 -0
- package/dist/{chunk-4J2ZM2HX.js → chunk-F236OJZD.js} +1 -1
- package/dist/{chunk-XARPIXWF.js → chunk-FWH5T6U4.js} +9 -3
- package/dist/{chunk-62EV4IJA.js → chunk-R2X4ZEF6.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +214 -129
- package/dist/eventcatalog.config.d.cts +59 -1
- package/dist/eventcatalog.config.d.ts +59 -1
- package/dist/eventcatalog.js +39 -15
- package/dist/federation/federate.js +2 -2
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
- package/dist/runtime-dependencies/@hocuspocus__provider.mjs +3 -0
- package/dist/runtime-dependencies/@hocuspocus__server.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-polyfill.mjs +3 -0
- package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +13 -1
- package/dist/runtime-dependencies/react-hotkeys-hook.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols__awareness.mjs +3 -0
- package/dist/runtime-dependencies/yjs.mjs +3 -0
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/dist/utils/license-status.cjs +71 -45
- package/dist/utils/license-status.d.cts +14 -5
- package/dist/utils/license-status.d.ts +14 -5
- package/dist/utils/license-status.js +1 -1
- package/eventcatalog/astro.config.mjs +23 -1
- package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
- package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
- package/eventcatalog/integrations/storage.mjs +20 -0
- package/eventcatalog/integrations/studio-server.mjs +32 -0
- package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
- package/eventcatalog/src/components/Grids/utils.tsx +0 -23
- package/eventcatalog/src/components/Header.astro +3 -3
- package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +6 -1
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +42 -3
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
- package/eventcatalog/src/components/NavigationProgress.astro +7 -0
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +12 -4
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
- package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
- package/eventcatalog/src/components/Search/search-utils.ts +26 -0
- package/eventcatalog/src/components/Seo.astro +5 -1
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +53 -83
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +131 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +4 -62
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +17 -150
- package/eventcatalog/src/components/Tables/Resources/ResourcesTable.tsx +425 -0
- package/eventcatalog/src/components/Tables/RowActionsMenu.tsx +157 -0
- package/eventcatalog/src/components/Tables/TablePagination.tsx +82 -0
- package/eventcatalog/src/features/ai/chat-api.ts +3 -3
- package/eventcatalog/src/features/auth/error.astro +4 -2
- package/eventcatalog/src/features/auth/login.astro +2 -1
- package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +10 -0
- package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
- package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
- package/eventcatalog/src/features/integrations/eventcatalog-features.ts +34 -1
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
- package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +47 -0
- package/eventcatalog/src/features/mcp/apps/canvas/styles.css +24 -0
- package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +278 -0
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +272 -0
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +77 -76
- package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +2 -1
- package/eventcatalog/src/features/mcp/mcp-apps.ts +6 -3
- package/eventcatalog/src/features/mcp/mcp-server.ts +36 -5
- package/eventcatalog/src/features/server/start.ts +25 -0
- package/eventcatalog/src/features/storage/database.ts +88 -0
- package/eventcatalog/src/features/storage/migrations.ts +85 -0
- package/eventcatalog/src/features/storage/sql/database.sql +5 -0
- package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
- package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
- package/eventcatalog/src/features/storage/sql.ts +28 -0
- package/eventcatalog/src/features/studio/agent-choreography.ts +384 -0
- package/eventcatalog/src/features/studio/agents.ts +28 -0
- package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
- package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
- package/eventcatalog/src/features/studio/api/client.ts +40 -0
- package/eventcatalog/src/features/studio/canvas-actions.ts +540 -0
- package/eventcatalog/src/features/studio/canvas-preview.ts +52 -0
- package/eventcatalog/src/features/studio/catalog-resources.ts +155 -0
- package/eventcatalog/src/features/studio/catalog.ts +173 -0
- package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +518 -0
- package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +118 -0
- package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +434 -0
- package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +143 -0
- package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
- package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
- package/eventcatalog/src/features/studio/components/JoinForm.tsx +109 -0
- package/eventcatalog/src/features/studio/components/LeftPanel.tsx +203 -0
- package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
- package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
- package/eventcatalog/src/features/studio/components/Presence.tsx +293 -0
- package/eventcatalog/src/features/studio/components/ShareDialog.tsx +396 -0
- package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
- package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +2091 -0
- package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
- package/eventcatalog/src/features/studio/document-name.ts +7 -0
- package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
- package/eventcatalog/src/features/studio/hooks/presence-sender.ts +63 -0
- package/eventcatalog/src/features/studio/hooks/presence-store.ts +119 -0
- package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +353 -0
- package/eventcatalog/src/features/studio/hooks/use-comments.ts +54 -0
- package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +109 -0
- package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +782 -0
- package/eventcatalog/src/features/studio/identity.ts +59 -0
- package/eventcatalog/src/features/studio/limits.ts +2 -0
- package/eventcatalog/src/features/studio/pages/[id].astro +69 -0
- package/eventcatalog/src/features/studio/pages/index.astro +784 -0
- package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +27 -0
- package/eventcatalog/src/features/studio/server/canvas-mcp.ts +495 -0
- package/eventcatalog/src/features/studio/server/runtime.ts +498 -0
- package/eventcatalog/src/features/studio/server/sign-in.ts +18 -0
- package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
- package/eventcatalog/src/features/studio/server/storage.ts +90 -0
- package/eventcatalog/src/features/studio/server/tool-icons.ts +30 -0
- package/eventcatalog/src/features/studio/tool-sync.ts +75 -0
- package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -7
- package/eventcatalog/src/pages/_index.astro +1 -1
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +52 -63
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +34 -46
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +11 -29
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_ResourcesPage.astro +79 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +32 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +63 -58
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +2 -62
- package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +13 -0
- package/eventcatalog/src/pages/index.astro +1 -1
- package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +24 -42
- package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +2 -0
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +2 -0
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +23 -23
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +13 -0
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +18 -27
- package/eventcatalog/src/stores/sidebar-store/state.ts +5 -0
- package/eventcatalog/src/styles/tailwind.css +2 -2
- package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
- package/eventcatalog/src/utils/collections/channels.ts +56 -1
- package/eventcatalog/src/utils/collections/flows.ts +50 -1
- package/eventcatalog/src/utils/collections/message-connections.ts +60 -0
- package/eventcatalog/src/utils/collections/message-triggers.ts +2 -1
- package/eventcatalog/src/utils/collections/resource-owners.ts +193 -0
- package/eventcatalog/src/utils/collections/resources.ts +310 -0
- package/eventcatalog/src/utils/collections/util.ts +31 -0
- package/eventcatalog/src/utils/feature.ts +8 -0
- package/eventcatalog/src/utils/git.ts +11 -5
- package/eventcatalog/src/utils/link-validation.ts +25 -19
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
- package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
- package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +0 -2
- package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
- package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
- package/eventcatalog/src/utils/page-title.ts +15 -0
- package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
- package/eventcatalog/src/utils/trial.ts +1 -1
- package/package.json +22 -16
- package/dist/runtime-dependencies/shelljs.mjs +0 -3
- package/eventcatalog/public/studio-bg.png +0 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +0 -838
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -344
- package/eventcatalog/src/components/Grids/SystemGrid.tsx +0 -185
- package/eventcatalog/src/components/Grids/components.tsx +0 -170
- package/eventcatalog/src/components/Grids/message-link.ts +0 -38
- package/eventcatalog/src/components/Studio/StudioPageModal.tsx +0 -150
- package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +0 -294
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.spec.ts +0 -65
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.ts +0 -46
- package/eventcatalog/src/pages/studio.astro +0 -316
- package/dist/{chunk-AYNZXUB5.js → chunk-KHACCTW2.js} +3 -3
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getItemsFromCollectionByIdAndSemverOrLatest,
|
|
5
|
+
createVersionedMap,
|
|
6
|
+
findInMap,
|
|
7
|
+
getVersionedMap,
|
|
8
|
+
satisfies,
|
|
9
|
+
uniqueResources,
|
|
10
|
+
} from './util';
|
|
4
11
|
import type { CollectionMessageTypes } from '@types';
|
|
5
12
|
|
|
6
13
|
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
@@ -195,3 +202,51 @@ export const getChannelChain = (
|
|
|
195
202
|
}
|
|
196
203
|
return [];
|
|
197
204
|
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* What a channel connects: the services and agents that send to it (`sends[].to`) or receive
|
|
208
|
+
* from it (`receives[].from`), and the messages that travel through it, from those pointers or
|
|
209
|
+
* from messages that list the channel (`data.messages` from getChannels). Pass raw entries:
|
|
210
|
+
* hydration resolves sends/receives to messages and drops the channel pointers. Pointers
|
|
211
|
+
* without a version mean the latest channel or message.
|
|
212
|
+
*/
|
|
213
|
+
export const getChannelConnections = (
|
|
214
|
+
channel: Channel,
|
|
215
|
+
catalog: {
|
|
216
|
+
endpoints: Array<CollectionEntry<'services'> | CollectionEntry<'agents'>>;
|
|
217
|
+
channels: Channel[];
|
|
218
|
+
messages: CollectionEntry<CollectionMessageTypes>[];
|
|
219
|
+
}
|
|
220
|
+
) => {
|
|
221
|
+
const channelMap = getVersionedMap(catalog.channels);
|
|
222
|
+
const messageMap = getVersionedMap(catalog.messages);
|
|
223
|
+
const isThisChannel = (pointer: { id: string; version?: string }) => {
|
|
224
|
+
const match = findInMap(channelMap, pointer.id, pointer.version);
|
|
225
|
+
return match?.data.id === channel.data.id && match?.data.version === channel.data.version;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const producers: Array<CollectionEntry<'services'> | CollectionEntry<'agents'>> = [];
|
|
229
|
+
const consumers: Array<CollectionEntry<'services'> | CollectionEntry<'agents'>> = [];
|
|
230
|
+
const messages: CollectionEntry<CollectionMessageTypes>[] = [];
|
|
231
|
+
const addMessage = (pointer: { id: string; version?: string }) => {
|
|
232
|
+
const message = findInMap(messageMap, pointer.id, pointer.version);
|
|
233
|
+
if (message) messages.push(message);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
for (const endpoint of catalog.endpoints) {
|
|
237
|
+
for (const send of (endpoint.data.sends || []) as any[]) {
|
|
238
|
+
if (!(send.to || []).some(isThisChannel)) continue;
|
|
239
|
+
producers.push(endpoint);
|
|
240
|
+
addMessage(send);
|
|
241
|
+
}
|
|
242
|
+
for (const receive of (endpoint.data.receives || []) as any[]) {
|
|
243
|
+
if (!(receive.from || []).some(isThisChannel)) continue;
|
|
244
|
+
consumers.push(endpoint);
|
|
245
|
+
addMessage(receive);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
for (const message of (channel.data as any).messages || []) addMessage(message);
|
|
250
|
+
|
|
251
|
+
return { producers: uniqueResources(producers), consumers: uniqueResources(consumers), messages: uniqueResources(messages) };
|
|
252
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
3
|
+
import { createVersionedMap, findInMap, getVersionedMap, uniqueResources } from '@utils/collections/util';
|
|
4
4
|
import { getDomains } from './domains';
|
|
5
5
|
import { getServices } from './services';
|
|
6
6
|
import { getAgents } from './agents';
|
|
@@ -147,6 +147,55 @@ export const getFlowsNotInAnyResource = async (): Promise<Flow[]> => {
|
|
|
147
147
|
return flowsNotInAnyResource;
|
|
148
148
|
};
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Finds the flows with a step that points at the service. A step without a version points
|
|
152
|
+
* at the latest service version, so `services` must include every version.
|
|
153
|
+
*/
|
|
154
|
+
export const getFlowsWithServiceStep = (
|
|
155
|
+
service: CollectionEntry<'services'>,
|
|
156
|
+
flows: Flow[],
|
|
157
|
+
services: CollectionEntry<'services'>[]
|
|
158
|
+
): Flow[] => {
|
|
159
|
+
const serviceMap = getVersionedMap(services);
|
|
160
|
+
return flows.filter((flow) =>
|
|
161
|
+
(flow.data.steps || []).some((step: any) => {
|
|
162
|
+
if (!step.service) return false;
|
|
163
|
+
const match = findInMap(serviceMap, step.service.id, step.service.version);
|
|
164
|
+
return match?.data.id === service.data.id && match?.data.version === service.data.version;
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/** A catalog entry a flow step points at (a service, message, agent, data store, data product or flow). */
|
|
170
|
+
type FlowStepResource = { collection: string; data: { id: string; version: string; [key: string]: any } };
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* The catalog resources a flow's steps point at, each listed once in step order: messages,
|
|
174
|
+
* services, agents, data stores, data products and sub-flows (the same steps the flow's
|
|
175
|
+
* sidebar lists). Expects steps as getFlows returns them, where messages, agents, data stores
|
|
176
|
+
* and data products are already resolved; services and sub-flows are resolved here, with a
|
|
177
|
+
* pointer without a version meaning the latest.
|
|
178
|
+
*/
|
|
179
|
+
export const getFlowStepResources = (
|
|
180
|
+
flow: Flow,
|
|
181
|
+
catalog: { services: CollectionEntry<'services'>[]; flows: Flow[] }
|
|
182
|
+
): FlowStepResource[] => {
|
|
183
|
+
const serviceMap = getVersionedMap(catalog.services);
|
|
184
|
+
const flowMap = getVersionedMap(catalog.flows);
|
|
185
|
+
const resources: FlowStepResource[] = [];
|
|
186
|
+
|
|
187
|
+
for (const step of (flow.data.steps || []) as any[]) {
|
|
188
|
+
const resource = step.service
|
|
189
|
+
? findInMap(serviceMap, step.service.id, step.service.version)
|
|
190
|
+
: step.flow
|
|
191
|
+
? findInMap(flowMap, step.flow.id, step.flow.version)
|
|
192
|
+
: [step.message, step.agent, step.container, step.dataProduct].find(Array.isArray)?.[0];
|
|
193
|
+
if (resource?.data) resources.push(resource);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return uniqueResources(resources);
|
|
197
|
+
};
|
|
198
|
+
|
|
150
199
|
/** A flow that includes a message in one of its steps, reduced to what the schema pages display. */
|
|
151
200
|
export interface FlowReference {
|
|
152
201
|
id: string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { CollectionEntry } from 'astro:content';
|
|
2
|
+
import type { CollectionMessageTypes } from '@types';
|
|
3
|
+
import { findInMap, getVersionedMap, uniqueResources } from './util';
|
|
4
|
+
import { getTriggeredByOfMessage, getTriggersOfMessage, messageMatchesPointer, type MessageReceiver } from './message-triggers';
|
|
5
|
+
|
|
6
|
+
type Message = CollectionEntry<CollectionMessageTypes>;
|
|
7
|
+
type Pointer = { id: string; version?: string };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* What a message connects to, beyond the producers and consumers getEvents/getCommands/getQueries
|
|
11
|
+
* already attach: the channels it travels on (its own `channels`, and the `to`/`from` channels of
|
|
12
|
+
* services, agents and domains that send or receive it), the flows with a step for it, and the
|
|
13
|
+
* messages it triggers or is triggered by. Receivers must be raw collection entries, because
|
|
14
|
+
* hydration drops the channel and trigger pointers on sends/receives.
|
|
15
|
+
*/
|
|
16
|
+
export const getMessageConnections = (
|
|
17
|
+
message: Message,
|
|
18
|
+
catalog: {
|
|
19
|
+
receivers: MessageReceiver[];
|
|
20
|
+
messages: Message[];
|
|
21
|
+
channels: CollectionEntry<'channels'>[];
|
|
22
|
+
flows: CollectionEntry<'flows'>[];
|
|
23
|
+
}
|
|
24
|
+
) => {
|
|
25
|
+
const channelMap = getVersionedMap(catalog.channels);
|
|
26
|
+
const resolveChannels = (pointers: Pointer[] = []) =>
|
|
27
|
+
pointers.map((pointer) => findInMap(channelMap, pointer.id, pointer.version)).filter((channel) => !!channel);
|
|
28
|
+
|
|
29
|
+
const channels = [...resolveChannels((message.data as any).channels)];
|
|
30
|
+
for (const receiver of catalog.receivers) {
|
|
31
|
+
for (const send of ((receiver.data as any).sends || []) as Array<Pointer & { to?: Pointer[] }>) {
|
|
32
|
+
if (messageMatchesPointer(message, send)) channels.push(...resolveChannels(send.to));
|
|
33
|
+
}
|
|
34
|
+
for (const receive of ((receiver.data as any).receives || []) as Array<Pointer & { from?: Pointer[] }>) {
|
|
35
|
+
if (messageMatchesPointer(message, receive)) channels.push(...resolveChannels(receive.from));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const flows = catalog.flows.filter((flow) =>
|
|
40
|
+
((flow.data.steps || []) as any[]).some((step) => {
|
|
41
|
+
const stepMessage = Array.isArray(step.message) ? step.message[0] : undefined;
|
|
42
|
+
return (
|
|
43
|
+
stepMessage?.collection === message.collection &&
|
|
44
|
+
stepMessage?.data.id === message.data.id &&
|
|
45
|
+
stepMessage?.data.version === message.data.version
|
|
46
|
+
);
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
channels: uniqueResources(channels as CollectionEntry<'channels'>[]),
|
|
52
|
+
flows: uniqueResources(flows),
|
|
53
|
+
triggers: uniqueResources(
|
|
54
|
+
getTriggersOfMessage(catalog.receivers, message, catalog.messages).map((trigger) => trigger.message)
|
|
55
|
+
),
|
|
56
|
+
triggeredBy: uniqueResources(
|
|
57
|
+
getTriggeredByOfMessage(catalog.receivers, message, catalog.messages).map((trigger) => trigger.message)
|
|
58
|
+
),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -23,7 +23,8 @@ export interface MessageTrigger {
|
|
|
23
23
|
condition?: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
/** Whether a pointer points at the message; a pointer without a version (or `latest`) means the latest version. */
|
|
27
|
+
export const messageMatchesPointer = (message: Message, pointer: { id: string; version?: string }) => {
|
|
27
28
|
if (pointer.id !== message.data.id) return false;
|
|
28
29
|
|
|
29
30
|
if (!pointer.version || pointer.version === 'latest') {
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { getCollection, type CollectionEntry, type CollectionKey } from 'astro:content';
|
|
2
|
+
import { getAdrs, getAdrsForResource } from './adrs';
|
|
3
|
+
import { getChannelConnections, getChannels } from './channels';
|
|
4
|
+
import { getCommands } from './commands';
|
|
5
|
+
import { getDomains } from './domains';
|
|
6
|
+
import { getEvents } from './events';
|
|
7
|
+
import { getFlows, getFlowStepResources, getFlowsWithServiceStep } from './flows';
|
|
8
|
+
import { getMessageConnections } from './message-connections';
|
|
9
|
+
import { getQueries } from './queries';
|
|
10
|
+
import { hasResources, type RelatedResources, type ResourceOwner, type ResourceOwnerCollection } from './resources';
|
|
11
|
+
import { getServices } from './services';
|
|
12
|
+
import { getSystems } from './systems';
|
|
13
|
+
|
|
14
|
+
// Loads the owners of Resources pages (domains, systems, services, flows, channels and messages)
|
|
15
|
+
// with the resources that point at them attached. Shared by the Resources pages, the sidebar's
|
|
16
|
+
// Resources links and the old /architecture redirects, so all three agree on which owners have
|
|
17
|
+
// a Resources page.
|
|
18
|
+
|
|
19
|
+
export const RESOURCE_OWNER_COLLECTIONS: ResourceOwnerCollection[] = [
|
|
20
|
+
'domains',
|
|
21
|
+
'systems',
|
|
22
|
+
'services',
|
|
23
|
+
'flows',
|
|
24
|
+
'channels',
|
|
25
|
+
'events',
|
|
26
|
+
'commands',
|
|
27
|
+
'queries',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export const loadResourceOwners = async (type: ResourceOwnerCollection): Promise<ResourceOwner[]> => {
|
|
31
|
+
switch (type) {
|
|
32
|
+
case 'systems':
|
|
33
|
+
return getSystems();
|
|
34
|
+
case 'services':
|
|
35
|
+
return getServices();
|
|
36
|
+
case 'flows':
|
|
37
|
+
return getFlows();
|
|
38
|
+
case 'channels':
|
|
39
|
+
return getChannels();
|
|
40
|
+
case 'events':
|
|
41
|
+
return getEvents();
|
|
42
|
+
case 'commands':
|
|
43
|
+
return getCommands();
|
|
44
|
+
case 'queries':
|
|
45
|
+
return getQueries();
|
|
46
|
+
case 'domains':
|
|
47
|
+
return getDomains({ includeServicesInSubdomains: false });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const once = <T>(load: () => Promise<T>) => {
|
|
52
|
+
let loaded: Promise<T> | undefined;
|
|
53
|
+
return () => (loaded ??= load());
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const isCurrentVersion = (entry: { data: { hidden?: boolean }; filePath?: string }) =>
|
|
57
|
+
entry.data.hidden !== true && !entry.filePath?.includes('versioned');
|
|
58
|
+
|
|
59
|
+
// Owners come from their own collection's loader, so an owner of a type is that collection's entry.
|
|
60
|
+
const asEntry = <C extends CollectionKey>(owner: ResourceOwner) => owner as unknown as CollectionEntry<C>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* What the related-resource lookups read. Each part loads the first time it is needed and is
|
|
64
|
+
* then shared, so working out every owner of a type, or every type, reads the catalog once.
|
|
65
|
+
*/
|
|
66
|
+
export const createResourcesCatalog = () => {
|
|
67
|
+
const catalog = {
|
|
68
|
+
adrs: once(() => getAdrs({ getAllVersions: false })),
|
|
69
|
+
services: once(() => getServices()),
|
|
70
|
+
allFlows: once(() => getFlows()),
|
|
71
|
+
currentFlows: once(() => getFlows({ getAllVersions: false })),
|
|
72
|
+
rawChannels: once(() => getCollection('channels')),
|
|
73
|
+
rawMessages: once(async () => [
|
|
74
|
+
...(await getCollection('events')),
|
|
75
|
+
...(await getCollection('commands')),
|
|
76
|
+
...(await getCollection('queries')),
|
|
77
|
+
]),
|
|
78
|
+
messages: once(async () => [...(await getEvents()), ...(await getCommands()), ...(await getQueries())]),
|
|
79
|
+
// Raw entries keep the channel and trigger pointers on sends/receives that hydration drops.
|
|
80
|
+
// Like the sidebar, channels use the current services and agents and triggers use every version.
|
|
81
|
+
currentEndpoints: once(async () =>
|
|
82
|
+
[...(await getCollection('services')), ...(await getCollection('agents'))].filter(isCurrentVersion)
|
|
83
|
+
),
|
|
84
|
+
receivers: once(async () => [
|
|
85
|
+
...(await getCollection('services')),
|
|
86
|
+
...(await getCollection('agents')),
|
|
87
|
+
...(await getCollection('domains')),
|
|
88
|
+
]),
|
|
89
|
+
};
|
|
90
|
+
return catalog;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type ResourcesCatalog = ReturnType<typeof createResourcesCatalog>;
|
|
94
|
+
|
|
95
|
+
type Relate = (owner: ResourceOwner) => RelatedResources;
|
|
96
|
+
|
|
97
|
+
// Loads what a type's lookups need, then returns a function that works out one owner's related resources.
|
|
98
|
+
const relatedResourcesFor = async (type: ResourceOwnerCollection, catalog: ResourcesCatalog): Promise<Relate> => {
|
|
99
|
+
const adrs = await catalog.adrs();
|
|
100
|
+
const adrsFor = (owner: ResourceOwner) => getAdrsForResource(asEntry<ResourceOwnerCollection>(owner), adrs);
|
|
101
|
+
|
|
102
|
+
switch (type) {
|
|
103
|
+
case 'services': {
|
|
104
|
+
const [flows, services] = await Promise.all([catalog.currentFlows(), catalog.services()]);
|
|
105
|
+
return (owner) => ({
|
|
106
|
+
adrs: adrsFor(owner),
|
|
107
|
+
stepFlows: getFlowsWithServiceStep(asEntry<'services'>(owner), flows, services),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
case 'flows': {
|
|
111
|
+
const [services, flows] = await Promise.all([catalog.services(), catalog.allFlows()]);
|
|
112
|
+
return (owner) => ({
|
|
113
|
+
adrs: adrsFor(owner),
|
|
114
|
+
stepResources: getFlowStepResources(asEntry<'flows'>(owner), { services, flows }),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
case 'channels': {
|
|
118
|
+
const [endpoints, channels, messages] = await Promise.all([
|
|
119
|
+
catalog.currentEndpoints(),
|
|
120
|
+
catalog.rawChannels(),
|
|
121
|
+
catalog.rawMessages(),
|
|
122
|
+
]);
|
|
123
|
+
return (owner) => {
|
|
124
|
+
const {
|
|
125
|
+
producers,
|
|
126
|
+
consumers,
|
|
127
|
+
messages: channelMessages,
|
|
128
|
+
} = getChannelConnections(asEntry<'channels'>(owner), { endpoints, channels, messages });
|
|
129
|
+
return { adrs: adrsFor(owner), channelProducers: producers, channelConsumers: consumers, channelMessages };
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case 'events':
|
|
133
|
+
case 'commands':
|
|
134
|
+
case 'queries': {
|
|
135
|
+
const [receivers, messages, channels, flows] = await Promise.all([
|
|
136
|
+
catalog.receivers(),
|
|
137
|
+
catalog.messages(),
|
|
138
|
+
catalog.rawChannels(),
|
|
139
|
+
catalog.currentFlows(),
|
|
140
|
+
]);
|
|
141
|
+
return (owner) => {
|
|
142
|
+
const connections = getMessageConnections(asEntry<'events' | 'commands' | 'queries'>(owner), {
|
|
143
|
+
receivers,
|
|
144
|
+
messages,
|
|
145
|
+
channels,
|
|
146
|
+
flows,
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
adrs: adrsFor(owner),
|
|
150
|
+
messageChannels: connections.channels,
|
|
151
|
+
messageFlows: connections.flows,
|
|
152
|
+
messageTriggers: connections.triggers,
|
|
153
|
+
messageTriggeredBy: connections.triggeredBy,
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
default:
|
|
158
|
+
return (owner) => ({ adrs: adrsFor(owner) });
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/** Every owner of the type with a Resources page, with its related resources attached. */
|
|
163
|
+
export const getOwnersWithResources = async (type: ResourceOwnerCollection, catalog = createResourcesCatalog()) => {
|
|
164
|
+
const [owners, relate] = await Promise.all([loadResourceOwners(type), relatedResourcesFor(type, catalog)]);
|
|
165
|
+
return owners.map((owner) => ({ ...owner, ...relate(owner) })).filter((owner) => hasResources(owner, type));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/** One owner with its related resources, or null when it does not exist or has no Resources page. Only that owner's lookups run. */
|
|
169
|
+
export const findOwnerWithResources = async (
|
|
170
|
+
type: ResourceOwnerCollection,
|
|
171
|
+
id: string,
|
|
172
|
+
version: string,
|
|
173
|
+
catalog = createResourcesCatalog()
|
|
174
|
+
): Promise<ResourceOwner | null> => {
|
|
175
|
+
const owner = (await loadResourceOwners(type)).find(
|
|
176
|
+
(candidate) => candidate.data.id === id && candidate.data.version === version
|
|
177
|
+
);
|
|
178
|
+
if (!owner) return null;
|
|
179
|
+
const withRelated = { ...owner, ...(await relatedResourcesFor(type, catalog))(owner) };
|
|
180
|
+
return hasResources(withRelated, type) ? withRelated : null;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/** `collection:id:version` of every owner with a Resources page, for links to those pages. */
|
|
184
|
+
export const getResourcesPageKeys = async (catalog = createResourcesCatalog()) => {
|
|
185
|
+
const keys = new Set<string>();
|
|
186
|
+
// One type at a time; the shared catalog means each part is still read only once.
|
|
187
|
+
for (const type of RESOURCE_OWNER_COLLECTIONS) {
|
|
188
|
+
for (const owner of await getOwnersWithResources(type, catalog)) {
|
|
189
|
+
keys.add(`${type}:${owner.data.id}:${owner.data.version}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return keys;
|
|
193
|
+
};
|