@eventcatalog/visualiser 5.0.0-beta.5 → 5.0.0-beta.7

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.
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-Q3OM5AL5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,427 @@
1
+ // src/model/schema.ts
2
+ import { z } from "zod";
3
+ var RESOURCE_TYPES = [
4
+ "domain",
5
+ "system",
6
+ "service",
7
+ "event",
8
+ "command",
9
+ "query",
10
+ "channel",
11
+ "container",
12
+ // Around the architecture, as Studio draws them: people, third parties, AI agents and user interfaces
13
+ "actor",
14
+ "external-system",
15
+ "agent",
16
+ "view",
17
+ // The domain model (an entity, e.g. Order, with its properties) and who owns what (a team)
18
+ "entity",
19
+ "team"
20
+ ];
21
+ var ResourceType = z.enum(RESOURCE_TYPES);
22
+ var MESSAGE_TYPES = /* @__PURE__ */ new Set([
23
+ "event",
24
+ "command",
25
+ "query"
26
+ ]);
27
+ var SCHEMA_FORMATS = [
28
+ "json-schema",
29
+ "avro",
30
+ "protobuf",
31
+ "json",
32
+ "yaml",
33
+ "xml",
34
+ "graphql",
35
+ "other"
36
+ ];
37
+ var SCHEMA_FORMAT = z.enum(SCHEMA_FORMATS);
38
+ var EntityProperty = z.object({
39
+ name: z.string().min(1).max(100),
40
+ type: z.string().min(1).max(100).describe(
41
+ 'e.g. "string", "number", "Customer" (another entity), "OrderLine[]"'
42
+ ),
43
+ required: z.boolean().optional(),
44
+ description: z.string().max(300).optional()
45
+ });
46
+ var CONTAINER_TYPES = [
47
+ "database",
48
+ "cache",
49
+ "objectStore",
50
+ "searchIndex",
51
+ "dataWarehouse",
52
+ "dataLake",
53
+ "externalSaaS",
54
+ "other"
55
+ ];
56
+ var Resource = z.object({
57
+ id: z.string().min(1).max(120).describe('Stable, unique id, e.g. "OrderPlaced" or "orders-service"'),
58
+ type: ResourceType,
59
+ name: z.string().min(1).max(200),
60
+ summary: z.string().max(1e3).optional().describe(
61
+ "One or two sentences on what it is or does. Give every resource one when you can: it is shown on its node and its page"
62
+ ),
63
+ parent: z.string().optional().describe(
64
+ "Id of what contains it: a service, agent, view or entity sits in a system or domain, a system in a domain, a domain in a domain (subdomain). Messages, channels, containers, actors and external systems usually have no parent"
65
+ ),
66
+ version: z.string().optional().describe("Defaults to 0.0.1"),
67
+ owners: z.array(z.string()).max(20).optional().describe("Teams or people that own it"),
68
+ technology: z.string().max(100).optional().describe('For containers and channels, e.g. "PostgreSQL", "Kafka", "SQS"'),
69
+ containerType: z.enum(CONTAINER_TYPES).optional().describe(
70
+ "For containers: what kind of data store it is (EventCatalog's container_type). Defaults to database"
71
+ ),
72
+ evidence: z.string().max(500).optional().describe(
73
+ 'Where this was found, e.g. "src/orders/publisher.ts:42" or "specs/orders.asyncapi.yaml"'
74
+ ),
75
+ properties: z.array(EntityProperty).max(50).optional().describe("For entities: their fields, e.g. id, status, total"),
76
+ card: z.boolean().optional().describe(
77
+ "For domains and systems: drawn as a card connected to what it holds, rather than a box around it (set in the view)"
78
+ ),
79
+ // Only web links: it's opened when "View the code" is pressed, so a javascript: or data: link would run there
80
+ url: z.url({ protocol: /^https?$/ }).max(1e3).optional().describe(
81
+ 'Link to the code or spec it was found in, e.g. a GitHub permalink (shown as "View the code")'
82
+ ),
83
+ schema: z.object({
84
+ format: SCHEMA_FORMAT,
85
+ content: z.string().min(1).max(2e4).describe("The schema, copied as it is from the spec or code"),
86
+ path: z.string().max(300).optional().describe('Where the schema lives, e.g. "schemas/OrderPlaced.avsc"')
87
+ }).optional().describe(
88
+ "For events, commands and queries: the message's schema (JSON Schema, Avro, Protobuf...), shown on its page"
89
+ )
90
+ });
91
+ var RELATION_KINDS = [
92
+ "sends",
93
+ "receives",
94
+ "routes-through",
95
+ "reads",
96
+ "writes",
97
+ "connects"
98
+ ];
99
+ var RelationKind = z.enum(RELATION_KINDS);
100
+ var Relation = z.object({
101
+ from: z.string().describe("Id of the resource the relation starts at"),
102
+ to: z.string().describe("Id of the resource it points to"),
103
+ kind: RelationKind.describe(
104
+ "sends / receives: service (or agent, view, actor, external system) -> message. routes-through: message -> channel. reads / writes: service -> container. connects: anything else (e.g. an actor using a view, a service calling an external system), described by its label"
105
+ ),
106
+ label: z.string().max(80).optional().describe(
107
+ `What it says on the diagram. For connects, what it means (e.g. "uses", "calls", "notifies"); for the others, leave it out for EventCatalog's wording (e.g. "publishes event") or set it to say more (e.g. "every 5 minutes")`
108
+ ),
109
+ fromField: z.string().max(100).optional().describe(
110
+ 'For a connection from an entity: the property it starts at (e.g. "customerId")'
111
+ ),
112
+ toField: z.string().max(100).optional().describe(
113
+ 'For a connection to an entity: the property it points to (e.g. "id")'
114
+ ),
115
+ inferred: z.boolean().optional().describe(
116
+ "true when guessed rather than seen directly in code or specs (drawn dashed)"
117
+ ),
118
+ evidence: z.string().max(500).optional()
119
+ });
120
+ var NOTE_COLOR_NAMES = [
121
+ "yellow",
122
+ "blue",
123
+ "green",
124
+ "pink",
125
+ "purple",
126
+ "gray"
127
+ ];
128
+ var LEVELS = ["overview", "services", "messages"];
129
+ var Note = z.object({
130
+ text: z.string().max(1e3),
131
+ resource: z.string().optional().describe(
132
+ "Id of the resource the note is about; none for a note on the whole diagram"
133
+ ),
134
+ author: z.string().max(100).optional(),
135
+ // Where it sits on the canvas (set by the view when people move it), its colour and width
136
+ x: z.number().optional(),
137
+ y: z.number().optional(),
138
+ color: z.enum(NOTE_COLOR_NAMES).optional(),
139
+ width: z.number().min(120).max(800).optional(),
140
+ // Written as a sticky note, or as plain text on the canvas, and when (shown on the note)
141
+ kind: z.enum(["sticky", "text"]).optional(),
142
+ fontSize: z.number().min(8).max(200).optional().describe("For text: its size, as it was scaled on the canvas"),
143
+ angle: z.number().min(-360).max(360).optional().describe("For text: how far it is turned, in degrees (clockwise)"),
144
+ createdAt: z.number().optional().describe("When it was written (milliseconds since 1970), shown on it"),
145
+ // As notes in EventCatalog are: on the level of detail it was written at (every level when not set)
146
+ level: z.enum(LEVELS).optional().describe(
147
+ "The level it shows at (overview, services or messages); every level when not set"
148
+ )
149
+ });
150
+ var Place = z.object({
151
+ x: z.number(),
152
+ y: z.number(),
153
+ width: z.number().optional(),
154
+ height: z.number().optional()
155
+ });
156
+ var Layout = z.object({
157
+ overview: z.record(z.string(), Place).optional(),
158
+ services: z.record(z.string(), Place).optional(),
159
+ messages: z.record(z.string(), Place).optional()
160
+ });
161
+ var CommentAuthor = z.object({
162
+ name: z.string().min(1).max(80),
163
+ color: z.string().max(20).default("#6b7280"),
164
+ agent: z.boolean().optional()
165
+ });
166
+ var XY = z.object({ x: z.number(), y: z.number() });
167
+ var PlaceLevel = z.union([z.literal(1), z.literal(2)]).optional();
168
+ var CommentThread = z.object({
169
+ id: z.string().min(1).max(60),
170
+ position: XY.describe("Where the pin is on the canvas (messages level)"),
171
+ nodeId: z.string().max(200).optional().describe("The resource it is pinned to, if it is"),
172
+ offset: XY.optional().describe("Where on that resource, from its top left"),
173
+ level: PlaceLevel.describe(
174
+ "For one at a place: the level it is on, 1 (overview) or 2 (services); none: messages"
175
+ ),
176
+ author: CommentAuthor,
177
+ createdAt: z.number(),
178
+ resolved: z.boolean().default(false),
179
+ messages: z.array(
180
+ z.object({
181
+ id: z.string().min(1).max(60),
182
+ text: z.string().min(1).max(4e3),
183
+ author: CommentAuthor,
184
+ createdAt: z.number()
185
+ })
186
+ ).min(1).max(200)
187
+ });
188
+ var HOTSPOT_SEVERITIES = ["critical", "warning", "info"];
189
+ var Hotspot = z.object({
190
+ id: z.string().min(1).max(60).default(() => crypto.randomUUID().slice(0, 8)),
191
+ severity: z.enum(HOTSPOT_SEVERITIES).default("warning").describe("critical, warning (the default) or info"),
192
+ title: z.string().min(1).max(120).describe(
193
+ 'What it is, short, e.g. "Single point of failure" or "No retries on payment"'
194
+ ),
195
+ description: z.string().max(1e3).optional().describe("Why it matters, and what to do about it"),
196
+ resource: z.string().max(200).optional().describe(
197
+ "Id of the resource it is about (it shows on it). Leave out for one at a place"
198
+ ),
199
+ position: XY.optional().describe(
200
+ "Where it is on the canvas, for one not on a resource: set by the view"
201
+ ),
202
+ level: PlaceLevel.describe(
203
+ "For one at a place: the level it is on, 1 (overview) or 2 (services); none: messages. Set by the view"
204
+ ),
205
+ author: CommentAuthor.optional().describe(
206
+ "Who flagged it (set it to you, with agent: true)"
207
+ ),
208
+ createdAt: z.number().optional()
209
+ });
210
+ var Model = z.object({
211
+ title: z.string().min(1).max(200).describe('What the diagram shows, e.g. "Orders domain"'),
212
+ resources: z.array(Resource).min(1).max(300),
213
+ relations: z.array(Relation).max(1e3).default([]),
214
+ notes: z.array(Note).max(100).optional().describe(
215
+ "Notes on the diagram or its resources (users add their own in the view)"
216
+ ),
217
+ comments: z.array(CommentThread).max(200).optional().describe(
218
+ "Comment threads people left on the canvas (and their replies): keep them as they are when you change the diagram"
219
+ ),
220
+ hotspots: z.array(Hotspot).max(100).optional().describe(
221
+ "Hotspots: what people should know about the architecture (risks, problems, the key parts), each on a resource. Keep the ones there are when you change the diagram"
222
+ ),
223
+ layout: Layout.optional().describe(
224
+ "Where things are on the canvas (set by the view when people arrange it): leave it as it is"
225
+ )
226
+ });
227
+ var Scene = z.object({
228
+ caption: z.string().max(400).optional().describe("What you say in this scene, shown under the diagram"),
229
+ level: z.enum(LEVELS).optional().describe(
230
+ "Level of detail: overview (domains, systems), services, messages (everything)"
231
+ ),
232
+ focus: z.array(z.string()).max(20).optional().describe(
233
+ "Ids of resources to zoom to: one zooms close to it, several fit them all. Leave out to keep the view (or show everything in the first scene)"
234
+ ),
235
+ highlight: z.array(z.string()).max(50).optional().describe("Ids to highlight, fading everything else. Defaults to focus"),
236
+ notes: z.array(z.object({ resource: z.string(), text: z.string().min(1).max(600) })).max(6).optional().describe(
237
+ 'Notes you write on the canvas, next to resources, e.g. "This is where the order is saved"'
238
+ ),
239
+ code: z.array(
240
+ z.object({
241
+ resource: z.string(),
242
+ title: z.string().max(120).optional().describe('e.g. "OrderPlaced.avsc" or "src/orders/publisher.ts:42"'),
243
+ language: z.string().max(30).optional(),
244
+ code: z.string().min(1).max(4e3).describe(
245
+ "Copied from the code or specs you read, e.g. the event's schema"
246
+ )
247
+ })
248
+ ).max(3).optional().describe(
249
+ "Code pinned next to a resource, e.g. an event's schema or the handler that consumes it"
250
+ )
251
+ });
252
+ var Tour = z.array(Scene).min(1).max(20);
253
+
254
+ // src/model/validate.ts
255
+ var RELATION_RULES = {
256
+ sends: {
257
+ from: ["service", "agent", "view", "actor", "external-system"],
258
+ to: ["event", "command", "query"]
259
+ },
260
+ receives: {
261
+ from: ["service", "agent", "view", "actor", "external-system"],
262
+ to: ["event", "command", "query"]
263
+ },
264
+ "routes-through": { from: ["event", "command", "query"], to: ["channel"] },
265
+ reads: { from: ["service", "agent"], to: ["container"] },
266
+ writes: { from: ["service", "agent"], to: ["container"] }
267
+ };
268
+ var IN_CONTAINERS = ["system", "domain"];
269
+ var PARENT_RULES = {
270
+ service: IN_CONTAINERS,
271
+ agent: IN_CONTAINERS,
272
+ view: IN_CONTAINERS,
273
+ event: IN_CONTAINERS,
274
+ command: IN_CONTAINERS,
275
+ query: IN_CONTAINERS,
276
+ channel: IN_CONTAINERS,
277
+ container: IN_CONTAINERS,
278
+ actor: IN_CONTAINERS,
279
+ "external-system": IN_CONTAINERS,
280
+ entity: IN_CONTAINERS,
281
+ team: IN_CONTAINERS,
282
+ system: IN_CONTAINERS,
283
+ domain: ["domain"]
284
+ };
285
+ function validateTour(model, tour) {
286
+ const ids = new Set(model.resources.map((r) => r.id));
287
+ const errors = [];
288
+ tour.forEach((scene, index) => {
289
+ const used = [
290
+ ...scene.focus ?? [],
291
+ ...scene.highlight ?? [],
292
+ ...(scene.notes ?? []).map((n) => n.resource),
293
+ ...(scene.code ?? []).map((c) => c.resource)
294
+ ];
295
+ for (const id of new Set(used))
296
+ if (!ids.has(id))
297
+ errors.push(
298
+ `Scene ${index + 1}: "${id}" isn't a resource in the diagram. Use the ids from the model.`
299
+ );
300
+ });
301
+ return errors;
302
+ }
303
+ function validateModel(model) {
304
+ const errors = [];
305
+ const warnings = [];
306
+ const byId = /* @__PURE__ */ new Map();
307
+ for (const resource of model.resources) {
308
+ if (byId.has(resource.id))
309
+ errors.push(
310
+ `Duplicate id "${resource.id}": every resource needs a unique id.`
311
+ );
312
+ byId.set(resource.id, resource);
313
+ }
314
+ for (const resource of model.resources) {
315
+ if (!resource.parent) continue;
316
+ const parent = byId.get(resource.parent);
317
+ const allowed = PARENT_RULES[resource.type];
318
+ if (!allowed) {
319
+ errors.push(
320
+ `${resource.type} "${resource.id}" has parent "${resource.parent}", but a ${resource.type} can't have a parent. Remove it.`
321
+ );
322
+ } else if (!parent) {
323
+ errors.push(
324
+ `${resource.type} "${resource.id}" has parent "${resource.parent}", which isn't a resource. Add it or remove the parent.`
325
+ );
326
+ } else if (!allowed.includes(parent.type)) {
327
+ errors.push(
328
+ `${resource.type} "${resource.id}" is in ${parent.type} "${parent.id}", but a ${resource.type} can only sit in a ${allowed.join(" or ")}.` + (resource.type === "domain" && parent.type === "system" ? " In EventCatalog domains contain systems: set the system's parent to the domain instead." : "")
329
+ );
330
+ }
331
+ }
332
+ for (const resource of model.resources) {
333
+ const seen = /* @__PURE__ */ new Set([resource.id]);
334
+ for (let current = resource.parent && byId.get(resource.parent); current; current = current.parent ? byId.get(current.parent) : void 0) {
335
+ if (seen.has(current.id)) {
336
+ errors.push(
337
+ `"${resource.id}" is inside itself (parents loop through "${current.id}"). Break the loop.`
338
+ );
339
+ break;
340
+ }
341
+ seen.add(current.id);
342
+ }
343
+ }
344
+ model.relations.forEach((relation, index) => {
345
+ const label = `Relation ${index} (${relation.from} ${relation.kind} ${relation.to})`;
346
+ const from = byId.get(relation.from);
347
+ const to = byId.get(relation.to);
348
+ if (!from)
349
+ errors.push(
350
+ `${label}: "${relation.from}" isn't a resource. Add it or fix the id.`
351
+ );
352
+ if (!to)
353
+ errors.push(
354
+ `${label}: "${relation.to}" isn't a resource. Add it or fix the id.`
355
+ );
356
+ if (!from || !to) return;
357
+ const rule = RELATION_RULES[relation.kind];
358
+ if (rule && (!rule.from.includes(from.type) || !rule.to.includes(to.type))) {
359
+ errors.push(
360
+ `${label}: "${relation.kind}" goes from a ${rule.from.join("/")} to a ${rule.to.join("/")}, not from a ${from.type} to a ${to.type}.`
361
+ );
362
+ }
363
+ });
364
+ (model.hotspots ?? []).forEach((hotspot, index) => {
365
+ if (hotspot.resource && !byId.has(hotspot.resource))
366
+ errors.push(
367
+ `Hotspot ${index + 1} ("${hotspot.title.slice(0, 40)}"): "${hotspot.resource}" isn't a resource. Use the id of a resource in the model.`
368
+ );
369
+ if (!hotspot.resource && !hotspot.position)
370
+ errors.push(
371
+ `Hotspot ${index + 1} ("${hotspot.title.slice(0, 40)}"): set resource, the id of the resource it's about.`
372
+ );
373
+ });
374
+ (model.notes ?? []).forEach((note, index) => {
375
+ if (note.resource && !byId.has(note.resource))
376
+ errors.push(
377
+ `Note ${index + 1}: "${note.resource}" isn't a resource. Use the id of a resource in the model, or leave it out.`
378
+ );
379
+ });
380
+ const connected = new Set(model.relations.flatMap((r) => [r.from, r.to]));
381
+ const sent = new Set(
382
+ model.relations.filter((r) => r.kind === "sends").map((r) => r.to)
383
+ );
384
+ for (const resource of model.resources) {
385
+ if (resource.type === "service" && !connected.has(resource.id))
386
+ warnings.push(
387
+ `Service "${resource.id}" has no relations: what does it send, receive, read or write?`
388
+ );
389
+ if (MESSAGE_TYPES.has(resource.type) && !sent.has(resource.id))
390
+ warnings.push(
391
+ `${resource.type} "${resource.id}" has no sender in the model.`
392
+ );
393
+ }
394
+ const inferred = model.relations.filter((r) => r.inferred).length;
395
+ if (model.relations.length >= 4 && inferred / model.relations.length > 0.5)
396
+ warnings.push(
397
+ `${inferred} of ${model.relations.length} relations are inferred: look for evidence in code or specs to confirm them.`
398
+ );
399
+ return { errors, warnings };
400
+ }
401
+
402
+ export {
403
+ RESOURCE_TYPES,
404
+ ResourceType,
405
+ MESSAGE_TYPES,
406
+ SCHEMA_FORMATS,
407
+ EntityProperty,
408
+ CONTAINER_TYPES,
409
+ Resource,
410
+ RELATION_KINDS,
411
+ RelationKind,
412
+ Relation,
413
+ NOTE_COLOR_NAMES,
414
+ LEVELS,
415
+ Note,
416
+ Layout,
417
+ CommentAuthor,
418
+ CommentThread,
419
+ HOTSPOT_SEVERITIES,
420
+ Hotspot,
421
+ Model,
422
+ Scene,
423
+ Tour,
424
+ validateTour,
425
+ validateModel
426
+ };
427
+ //# sourceMappingURL=chunk-R3QHQ7LF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/model/schema.ts","../src/model/validate.ts"],"sourcesContent":["/**\n * The architecture model agents send us: EventCatalog's vocabulary (domains, systems, services, messages,\n * channels, containers) and how they relate. Shared by the MCP server and the view, so no server-only imports.\n */\nimport { z } from \"zod\";\n\nexport const RESOURCE_TYPES = [\n \"domain\",\n \"system\",\n \"service\",\n \"event\",\n \"command\",\n \"query\",\n \"channel\",\n \"container\",\n // Around the architecture, as Studio draws them: people, third parties, AI agents and user interfaces\n \"actor\",\n \"external-system\",\n \"agent\",\n \"view\",\n // The domain model (an entity, e.g. Order, with its properties) and who owns what (a team)\n \"entity\",\n \"team\",\n] as const;\nexport const ResourceType = z.enum(RESOURCE_TYPES);\nexport type ResourceType = z.infer<typeof ResourceType>;\n\nexport const MESSAGE_TYPES = new Set<ResourceType>([\n \"event\",\n \"command\",\n \"query\",\n]);\n\nexport const SCHEMA_FORMATS = [\n \"json-schema\",\n \"avro\",\n \"protobuf\",\n \"json\",\n \"yaml\",\n \"xml\",\n \"graphql\",\n \"other\",\n] as const;\nconst SCHEMA_FORMAT = z.enum(SCHEMA_FORMATS);\n\n/** A field of an entity (as EventCatalog's entities have them), e.g. { name: \"orderId\", type: \"string\" } */\nexport const EntityProperty = z.object({\n name: z.string().min(1).max(100),\n type: z\n .string()\n .min(1)\n .max(100)\n .describe(\n 'e.g. \"string\", \"number\", \"Customer\" (another entity), \"OrderLine[]\"',\n ),\n required: z.boolean().optional(),\n description: z.string().max(300).optional(),\n});\nexport type EntityProperty = z.infer<typeof EntityProperty>;\n\n/** The kinds of data store (EventCatalog's container_type), e.g. a Redis cache is \"cache\" */\nexport const CONTAINER_TYPES = [\n \"database\",\n \"cache\",\n \"objectStore\",\n \"searchIndex\",\n \"dataWarehouse\",\n \"dataLake\",\n \"externalSaaS\",\n \"other\",\n] as const;\nexport type ContainerType = (typeof CONTAINER_TYPES)[number];\n\nexport const Resource = z.object({\n id: z\n .string()\n .min(1)\n .max(120)\n .describe('Stable, unique id, e.g. \"OrderPlaced\" or \"orders-service\"'),\n type: ResourceType,\n name: z.string().min(1).max(200),\n summary: z\n .string()\n .max(1000)\n .optional()\n .describe(\n \"One or two sentences on what it is or does. Give every resource one when you can: it is shown on its node and its page\",\n ),\n parent: z\n .string()\n .optional()\n .describe(\n \"Id of what contains it: a service, agent, view or entity sits in a system or domain, a system in a domain, a domain in a domain (subdomain). Messages, channels, containers, actors and external systems usually have no parent\",\n ),\n version: z.string().optional().describe(\"Defaults to 0.0.1\"),\n owners: z\n .array(z.string())\n .max(20)\n .optional()\n .describe(\"Teams or people that own it\"),\n technology: z\n .string()\n .max(100)\n .optional()\n .describe('For containers and channels, e.g. \"PostgreSQL\", \"Kafka\", \"SQS\"'),\n containerType: z\n .enum(CONTAINER_TYPES)\n .optional()\n .describe(\n \"For containers: what kind of data store it is (EventCatalog's container_type). Defaults to database\",\n ),\n evidence: z\n .string()\n .max(500)\n .optional()\n .describe(\n 'Where this was found, e.g. \"src/orders/publisher.ts:42\" or \"specs/orders.asyncapi.yaml\"',\n ),\n properties: z\n .array(EntityProperty)\n .max(50)\n .optional()\n .describe(\"For entities: their fields, e.g. id, status, total\"),\n card: z\n .boolean()\n .optional()\n .describe(\n \"For domains and systems: drawn as a card connected to what it holds, rather than a box around it (set in the view)\",\n ),\n // Only web links: it's opened when \"View the code\" is pressed, so a javascript: or data: link would run there\n url: z\n .url({ protocol: /^https?$/ })\n .max(1000)\n .optional()\n .describe(\n 'Link to the code or spec it was found in, e.g. a GitHub permalink (shown as \"View the code\")',\n ),\n schema: z\n .object({\n format: SCHEMA_FORMAT,\n content: z\n .string()\n .min(1)\n .max(20000)\n .describe(\"The schema, copied as it is from the spec or code\"),\n path: z\n .string()\n .max(300)\n .optional()\n .describe('Where the schema lives, e.g. \"schemas/OrderPlaced.avsc\"'),\n })\n .optional()\n .describe(\n \"For events, commands and queries: the message's schema (JSON Schema, Avro, Protobuf...), shown on its page\",\n ),\n});\nexport type Resource = z.infer<typeof Resource>;\n\nexport const RELATION_KINDS = [\n \"sends\",\n \"receives\",\n \"routes-through\",\n \"reads\",\n \"writes\",\n \"connects\",\n] as const;\nexport const RelationKind = z.enum(RELATION_KINDS);\nexport type RelationKind = z.infer<typeof RelationKind>;\n\nexport const Relation = z.object({\n from: z.string().describe(\"Id of the resource the relation starts at\"),\n to: z.string().describe(\"Id of the resource it points to\"),\n kind: RelationKind.describe(\n \"sends / receives: service (or agent, view, actor, external system) -> message. routes-through: message -> channel. reads / writes: service -> container. connects: anything else (e.g. an actor using a view, a service calling an external system), described by its label\",\n ),\n label: z\n .string()\n .max(80)\n .optional()\n .describe(\n 'What it says on the diagram. For connects, what it means (e.g. \"uses\", \"calls\", \"notifies\"); for the others, leave it out for EventCatalog\\'s wording (e.g. \"publishes event\") or set it to say more (e.g. \"every 5 minutes\")',\n ),\n fromField: z\n .string()\n .max(100)\n .optional()\n .describe(\n 'For a connection from an entity: the property it starts at (e.g. \"customerId\")',\n ),\n toField: z\n .string()\n .max(100)\n .optional()\n .describe(\n 'For a connection to an entity: the property it points to (e.g. \"id\")',\n ),\n inferred: z\n .boolean()\n .optional()\n .describe(\n \"true when guessed rather than seen directly in code or specs (drawn dashed)\",\n ),\n evidence: z.string().max(500).optional(),\n});\nexport type Relation = z.infer<typeof Relation>;\n\nexport const NOTE_COLOR_NAMES = [\n \"yellow\",\n \"blue\",\n \"green\",\n \"pink\",\n \"purple\",\n \"gray\",\n] as const;\n\nexport const LEVELS = [\"overview\", \"services\", \"messages\"] as const;\nexport type Level = (typeof LEVELS)[number];\n\nexport const Note = z.object({\n text: z.string().max(1000),\n resource: z\n .string()\n .optional()\n .describe(\n \"Id of the resource the note is about; none for a note on the whole diagram\",\n ),\n author: z.string().max(100).optional(),\n // Where it sits on the canvas (set by the view when people move it), its colour and width\n x: z.number().optional(),\n y: z.number().optional(),\n color: z.enum(NOTE_COLOR_NAMES).optional(),\n width: z.number().min(120).max(800).optional(),\n // Written as a sticky note, or as plain text on the canvas, and when (shown on the note)\n kind: z.enum([\"sticky\", \"text\"]).optional(),\n fontSize: z\n .number()\n .min(8)\n .max(200)\n .optional()\n .describe(\"For text: its size, as it was scaled on the canvas\"),\n angle: z\n .number()\n .min(-360)\n .max(360)\n .optional()\n .describe(\"For text: how far it is turned, in degrees (clockwise)\"),\n createdAt: z\n .number()\n .optional()\n .describe(\"When it was written (milliseconds since 1970), shown on it\"),\n // As notes in EventCatalog are: on the level of detail it was written at (every level when not set)\n level: z\n .enum(LEVELS)\n .optional()\n .describe(\n \"The level it shows at (overview, services or messages); every level when not set\",\n ),\n});\nexport type Note = z.infer<typeof Note>;\n\n/** Where a resource is on a level: its top-left corner (relative to its container on the canvas) and a container's size */\nconst Place = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().optional(),\n height: z.number().optional(),\n});\nexport const Layout = z.object({\n overview: z.record(z.string(), Place).optional(),\n services: z.record(z.string(), Place).optional(),\n messages: z.record(z.string(), Place).optional(),\n});\nexport type Layout = z.infer<typeof Layout>;\n\n/** Who wrote a comment: a person (their name and colour on the canvas) or an agent */\nexport const CommentAuthor = z.object({\n name: z.string().min(1).max(80),\n color: z.string().max(20).default(\"#6b7280\"),\n agent: z.boolean().optional(),\n});\nconst XY = z.object({ x: z.number(), y: z.number() });\n/** For something at a place (not on a resource): the level it was put on, 1 (overview) or 2 (services). None: messages */\nconst PlaceLevel = z.union([z.literal(1), z.literal(2)]).optional();\n\n/**\n * A comment thread on the canvas, as EventCatalog Studio's: pinned at a place, or on a resource (nodeId, the resource\n * id, with an offset from its top left, so it moves with it), with its messages (the first one starts it, the rest\n * reply), and resolved once it's dealt with\n */\nexport const CommentThread = z.object({\n id: z.string().min(1).max(60),\n position: XY.describe(\"Where the pin is on the canvas (messages level)\"),\n nodeId: z\n .string()\n .max(200)\n .optional()\n .describe(\"The resource it is pinned to, if it is\"),\n offset: XY.optional().describe(\"Where on that resource, from its top left\"),\n level: PlaceLevel.describe(\n \"For one at a place: the level it is on, 1 (overview) or 2 (services); none: messages\",\n ),\n author: CommentAuthor,\n createdAt: z.number(),\n resolved: z.boolean().default(false),\n messages: z\n .array(\n z.object({\n id: z.string().min(1).max(60),\n text: z.string().min(1).max(4000),\n author: CommentAuthor,\n createdAt: z.number(),\n }),\n )\n .min(1)\n .max(200),\n});\nexport type CommentThread = z.infer<typeof CommentThread>;\n\n/** How much a hotspot matters: critical (red), warning (amber) or info (blue) */\nexport const HOTSPOT_SEVERITIES = [\"critical\", \"warning\", \"info\"] as const;\nexport type HotspotSeverity = (typeof HOTSPOT_SEVERITIES)[number];\n\n/**\n * A hotspot: something on the diagram people should know about, as an architect would flag it: a risk, a single\n * point of failure, a known problem, or the key part to understand. On a resource (shown on it), or at a place\n */\nexport const Hotspot = z.object({\n id: z\n .string()\n .min(1)\n .max(60)\n .default(() => crypto.randomUUID().slice(0, 8)),\n severity: z\n .enum(HOTSPOT_SEVERITIES)\n .default(\"warning\")\n .describe(\"critical, warning (the default) or info\"),\n title: z\n .string()\n .min(1)\n .max(120)\n .describe(\n 'What it is, short, e.g. \"Single point of failure\" or \"No retries on payment\"',\n ),\n description: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Why it matters, and what to do about it\"),\n resource: z\n .string()\n .max(200)\n .optional()\n .describe(\n \"Id of the resource it is about (it shows on it). Leave out for one at a place\",\n ),\n position: XY.optional().describe(\n \"Where it is on the canvas, for one not on a resource: set by the view\",\n ),\n level: PlaceLevel.describe(\n \"For one at a place: the level it is on, 1 (overview) or 2 (services); none: messages. Set by the view\",\n ),\n author: CommentAuthor.optional().describe(\n \"Who flagged it (set it to you, with agent: true)\",\n ),\n createdAt: z.number().optional(),\n});\nexport type Hotspot = z.infer<typeof Hotspot>;\n\nexport const Model = z.object({\n title: z\n .string()\n .min(1)\n .max(200)\n .describe('What the diagram shows, e.g. \"Orders domain\"'),\n resources: z.array(Resource).min(1).max(300),\n relations: z.array(Relation).max(1000).default([]),\n notes: z\n .array(Note)\n .max(100)\n .optional()\n .describe(\n \"Notes on the diagram or its resources (users add their own in the view)\",\n ),\n comments: z\n .array(CommentThread)\n .max(200)\n .optional()\n .describe(\n \"Comment threads people left on the canvas (and their replies): keep them as they are when you change the diagram\",\n ),\n hotspots: z\n .array(Hotspot)\n .max(100)\n .optional()\n .describe(\n \"Hotspots: what people should know about the architecture (risks, problems, the key parts), each on a resource. Keep the ones there are when you change the diagram\",\n ),\n layout: Layout.optional().describe(\n \"Where things are on the canvas (set by the view when people arrange it): leave it as it is\",\n ),\n});\nexport type Model = z.infer<typeof Model>;\n\n/**\n * A scene of a tour: the agent showing the user something on the diagram, as a person at the canvas would. It\n * switches level, zooms to resources, highlights them (fading the rest), writes notes next to them and pins code.\n */\nexport const Scene = z.object({\n caption: z\n .string()\n .max(400)\n .optional()\n .describe(\"What you say in this scene, shown under the diagram\"),\n level: z\n .enum(LEVELS)\n .optional()\n .describe(\n \"Level of detail: overview (domains, systems), services, messages (everything)\",\n ),\n focus: z\n .array(z.string())\n .max(20)\n .optional()\n .describe(\n \"Ids of resources to zoom to: one zooms close to it, several fit them all. Leave out to keep the view (or show everything in the first scene)\",\n ),\n highlight: z\n .array(z.string())\n .max(50)\n .optional()\n .describe(\"Ids to highlight, fading everything else. Defaults to focus\"),\n notes: z\n .array(z.object({ resource: z.string(), text: z.string().min(1).max(600) }))\n .max(6)\n .optional()\n .describe(\n 'Notes you write on the canvas, next to resources, e.g. \"This is where the order is saved\"',\n ),\n code: z\n .array(\n z.object({\n resource: z.string(),\n title: z\n .string()\n .max(120)\n .optional()\n .describe('e.g. \"OrderPlaced.avsc\" or \"src/orders/publisher.ts:42\"'),\n language: z.string().max(30).optional(),\n code: z\n .string()\n .min(1)\n .max(4000)\n .describe(\n \"Copied from the code or specs you read, e.g. the event's schema\",\n ),\n }),\n )\n .max(3)\n .optional()\n .describe(\n \"Code pinned next to a resource, e.g. an event's schema or the handler that consumes it\",\n ),\n});\nexport type Scene = z.infer<typeof Scene>;\nexport const Tour = z.array(Scene).min(1).max(20);\n\n/** What the view shows: the model, where to start, and a tour to play */\nexport type ArchitecturePayload = {\n model: Model;\n focus?: string;\n level?: Level;\n viewUrl?: string;\n tour?: Scene[];\n};\n","/**\n * Checks beyond the schema: references point at something, relations go the right way, parents make sense.\n * Returns every problem at once, written so an agent can fix the model and try again.\n */\nimport {\n MESSAGE_TYPES,\n type Model,\n type Resource,\n type ResourceType,\n type Scene,\n} from \"./schema\";\n\nexport type ValidationResult = { errors: string[]; warnings: string[] };\n\n// What each relation kind connects\nconst RELATION_RULES: Record<\n string,\n { from: ResourceType[]; to: ResourceType[] }\n> = {\n sends: {\n from: [\"service\", \"agent\", \"view\", \"actor\", \"external-system\"],\n to: [\"event\", \"command\", \"query\"],\n },\n receives: {\n from: [\"service\", \"agent\", \"view\", \"actor\", \"external-system\"],\n to: [\"event\", \"command\", \"query\"],\n },\n \"routes-through\": { from: [\"event\", \"command\", \"query\"], to: [\"channel\"] },\n reads: { from: [\"service\", \"agent\"], to: [\"container\"] },\n writes: { from: [\"service\", \"agent\"], to: [\"container\"] },\n};\n// \"connects\" joins anything to anything (described by its label)\n\n// What each type of resource may sit in. Only domains and systems hold things (EventCatalog: domains contain systems\n// and subdomains, systems their services); on the canvas people can also put messages, channels and the like in them\nconst IN_CONTAINERS: ResourceType[] = [\"system\", \"domain\"];\nconst PARENT_RULES: Partial<Record<ResourceType, ResourceType[]>> = {\n service: IN_CONTAINERS,\n agent: IN_CONTAINERS,\n view: IN_CONTAINERS,\n event: IN_CONTAINERS,\n command: IN_CONTAINERS,\n query: IN_CONTAINERS,\n channel: IN_CONTAINERS,\n container: IN_CONTAINERS,\n actor: IN_CONTAINERS,\n \"external-system\": IN_CONTAINERS,\n entity: IN_CONTAINERS,\n team: IN_CONTAINERS,\n system: IN_CONTAINERS,\n domain: [\"domain\"],\n};\n\n/** A tour's scenes must point at resources in the model */\nexport function validateTour(model: Model, tour: Scene[]): string[] {\n const ids = new Set(model.resources.map((r) => r.id));\n const errors: string[] = [];\n tour.forEach((scene, index) => {\n const used = [\n ...(scene.focus ?? []),\n ...(scene.highlight ?? []),\n ...(scene.notes ?? []).map((n) => n.resource),\n ...(scene.code ?? []).map((c) => c.resource),\n ];\n for (const id of new Set(used))\n if (!ids.has(id))\n errors.push(\n `Scene ${index + 1}: \"${id}\" isn't a resource in the diagram. Use the ids from the model.`,\n );\n });\n return errors;\n}\n\nexport function validateModel(model: Model): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n const byId = new Map<string, Resource>();\n\n for (const resource of model.resources) {\n if (byId.has(resource.id))\n errors.push(\n `Duplicate id \"${resource.id}\": every resource needs a unique id.`,\n );\n byId.set(resource.id, resource);\n }\n\n for (const resource of model.resources) {\n if (!resource.parent) continue;\n const parent = byId.get(resource.parent);\n const allowed = PARENT_RULES[resource.type];\n if (!allowed) {\n errors.push(\n `${resource.type} \"${resource.id}\" has parent \"${resource.parent}\", but a ${resource.type} can't have a parent. Remove it.`,\n );\n } else if (!parent) {\n errors.push(\n `${resource.type} \"${resource.id}\" has parent \"${resource.parent}\", which isn't a resource. Add it or remove the parent.`,\n );\n } else if (!allowed.includes(parent.type)) {\n errors.push(\n `${resource.type} \"${resource.id}\" is in ${parent.type} \"${parent.id}\", but a ${resource.type} can only sit in a ${allowed.join(\" or \")}.` +\n (resource.type === \"domain\" && parent.type === \"system\"\n ? \" In EventCatalog domains contain systems: set the system's parent to the domain instead.\"\n : \"\"),\n );\n }\n }\n\n // Parent cycles\n for (const resource of model.resources) {\n const seen = new Set<string>([resource.id]);\n for (\n let current = resource.parent && byId.get(resource.parent);\n current;\n current = current.parent ? byId.get(current.parent) : undefined\n ) {\n if (seen.has(current.id)) {\n errors.push(\n `\"${resource.id}\" is inside itself (parents loop through \"${current.id}\"). Break the loop.`,\n );\n break;\n }\n seen.add(current.id);\n }\n }\n\n model.relations.forEach((relation, index) => {\n const label = `Relation ${index} (${relation.from} ${relation.kind} ${relation.to})`;\n const from = byId.get(relation.from);\n const to = byId.get(relation.to);\n if (!from)\n errors.push(\n `${label}: \"${relation.from}\" isn't a resource. Add it or fix the id.`,\n );\n if (!to)\n errors.push(\n `${label}: \"${relation.to}\" isn't a resource. Add it or fix the id.`,\n );\n if (!from || !to) return;\n const rule = RELATION_RULES[relation.kind];\n if (\n rule &&\n (!rule.from.includes(from.type) || !rule.to.includes(to.type))\n ) {\n errors.push(\n `${label}: \"${relation.kind}\" goes from a ${rule.from.join(\"/\")} to a ${rule.to.join(\"/\")}, not from a ${from.type} to a ${to.type}.`,\n );\n }\n });\n\n (model.hotspots ?? []).forEach((hotspot, index) => {\n if (hotspot.resource && !byId.has(hotspot.resource))\n errors.push(\n `Hotspot ${index + 1} (\"${hotspot.title.slice(0, 40)}\"): \"${hotspot.resource}\" isn't a resource. Use the id of a resource in the model.`,\n );\n if (!hotspot.resource && !hotspot.position)\n errors.push(\n `Hotspot ${index + 1} (\"${hotspot.title.slice(0, 40)}\"): set resource, the id of the resource it's about.`,\n );\n });\n (model.notes ?? []).forEach((note, index) => {\n if (note.resource && !byId.has(note.resource))\n errors.push(\n `Note ${index + 1}: \"${note.resource}\" isn't a resource. Use the id of a resource in the model, or leave it out.`,\n );\n });\n\n // Warnings: likely gaps, but still worth drawing\n const connected = new Set(model.relations.flatMap((r) => [r.from, r.to]));\n const sent = new Set(\n model.relations.filter((r) => r.kind === \"sends\").map((r) => r.to),\n );\n for (const resource of model.resources) {\n if (resource.type === \"service\" && !connected.has(resource.id))\n warnings.push(\n `Service \"${resource.id}\" has no relations: what does it send, receive, read or write?`,\n );\n if (MESSAGE_TYPES.has(resource.type) && !sent.has(resource.id))\n warnings.push(\n `${resource.type} \"${resource.id}\" has no sender in the model.`,\n );\n }\n const inferred = model.relations.filter((r) => r.inferred).length;\n if (model.relations.length >= 4 && inferred / model.relations.length > 0.5)\n warnings.push(\n `${inferred} of ${model.relations.length} relations are inferred: look for evidence in code or specs to confirm them.`,\n );\n\n return { errors, warnings };\n}\n"],"mappings":"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","names":[]}