@eventcatalog/cli 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -140,6 +140,7 @@ var import_node_path = require("path");
140
140
  var import_open = __toESM(require("open"));
141
141
  var import_sdk3 = __toESM(require("@eventcatalog/sdk"));
142
142
  var RESOURCE_TYPES = ["event", "command", "query", "service", "domain"];
143
+ var SUPPORTED_RESOURCE_TYPES = RESOURCE_TYPES.join(", ");
143
144
  var PLURAL_MAP = {
144
145
  events: "event",
145
146
  commands: "command",
@@ -147,11 +148,40 @@ var PLURAL_MAP = {
147
148
  services: "service",
148
149
  domains: "domain"
149
150
  };
151
+ var KNOWN_UNSUPPORTED_EXPORT_TYPES = /* @__PURE__ */ new Set([
152
+ "channel",
153
+ "channels",
154
+ "team",
155
+ "teams",
156
+ "user",
157
+ "users",
158
+ "container",
159
+ "containers",
160
+ "data-product",
161
+ "data-products",
162
+ "dataproduct",
163
+ "dataproducts",
164
+ "diagram",
165
+ "diagrams",
166
+ "flow",
167
+ "flows"
168
+ ]);
150
169
  function normalizeResourceType(resource) {
151
170
  const lower = resource.toLowerCase();
152
171
  if (PLURAL_MAP[lower]) return PLURAL_MAP[lower];
153
172
  return lower;
154
173
  }
174
+ function assertSupportedExportType(resource, type) {
175
+ const lower = resource.toLowerCase();
176
+ if (KNOWN_UNSUPPORTED_EXPORT_TYPES.has(lower)) {
177
+ throw new Error(
178
+ `Resource type '${resource}' is not yet supported for DSL export. Supported types: ${SUPPORTED_RESOURCE_TYPES}`
179
+ );
180
+ }
181
+ if (!RESOURCE_TYPES.includes(type)) {
182
+ throw new Error(`Invalid resource type '${resource}'. Must be one of: ${SUPPORTED_RESOURCE_TYPES}`);
183
+ }
184
+ }
155
185
  function getResourceFetcher(sdk, type) {
156
186
  switch (type) {
157
187
  case "event":
@@ -242,14 +272,14 @@ ${entries.join("\n")}
242
272
  async function exportCatalog(options) {
243
273
  const { hydrate = false, stdout = false, playground = false, output, dir } = options;
244
274
  const sdk = (0, import_sdk3.default)(dir);
245
- const dslParts = [];
246
- for (const type of RESOURCE_TYPES) {
247
- const fetcher = getCollectionFetcher(sdk, type);
248
- const resources = await fetcher({ latestOnly: true });
249
- if (!resources || resources.length === 0) continue;
250
- const rawDsl = await sdk.toDSL(resources, { type, hydrate });
251
- dslParts.push(rawDsl);
252
- }
275
+ const dslParts = (await Promise.all(
276
+ RESOURCE_TYPES.map(async (type) => {
277
+ const fetcher = getCollectionFetcher(sdk, type);
278
+ const resources = await fetcher({ latestOnly: true });
279
+ if (!resources || resources.length === 0) return "";
280
+ return sdk.toDSL(resources, { type, hydrate });
281
+ })
282
+ )).filter((dsl2) => Boolean(dsl2));
253
283
  if (dslParts.length === 0) {
254
284
  throw new Error(`No resources found in catalog at '${dir}'`);
255
285
  }
@@ -269,9 +299,9 @@ ${vizBlock}` : grouped;
269
299
  const encoded = Buffer.from(dsl).toString("base64");
270
300
  const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
271
301
  await (0, import_open.default)(playgroundUrl);
272
- lines.push("", ` Opening in playground...`);
302
+ lines.push("", ` Opening in EventCatalog Modelling...`);
273
303
  } else {
274
- lines.push("", ` Tip: Use --playground to open in the playground`);
304
+ lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
275
305
  }
276
306
  lines.push("");
277
307
  return lines.join("\n");
@@ -279,9 +309,7 @@ ${vizBlock}` : grouped;
279
309
  async function exportAll(options) {
280
310
  const { resource, hydrate = false, stdout = false, playground = false, output, dir } = options;
281
311
  const type = normalizeResourceType(resource);
282
- if (!RESOURCE_TYPES.includes(type)) {
283
- throw new Error(`Invalid resource type '${resource}'. Must be one of: ${RESOURCE_TYPES.join(", ")}`);
284
- }
312
+ assertSupportedExportType(resource, type);
285
313
  const plural = pluralize(type);
286
314
  const sdk = (0, import_sdk3.default)(dir);
287
315
  const fetcher = getCollectionFetcher(sdk, type);
@@ -305,9 +333,9 @@ ${vizBlock}` : grouped;
305
333
  const encoded = Buffer.from(dsl).toString("base64");
306
334
  const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
307
335
  await (0, import_open.default)(playgroundUrl);
308
- lines.push("", ` Opening in playground...`);
336
+ lines.push("", ` Opening in EventCatalog Modelling...`);
309
337
  } else {
310
- lines.push("", ` Tip: Use --playground to open in the playground`);
338
+ lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
311
339
  }
312
340
  lines.push("");
313
341
  return lines.join("\n");
@@ -318,9 +346,7 @@ async function exportResource(options) {
318
346
  return exportAll(options);
319
347
  }
320
348
  const type = normalizeResourceType(resource);
321
- if (!RESOURCE_TYPES.includes(type)) {
322
- throw new Error(`Invalid resource type '${resource}'. Must be one of: ${RESOURCE_TYPES.join(", ")}`);
323
- }
349
+ assertSupportedExportType(resource, type);
324
350
  const sdk = (0, import_sdk3.default)(dir);
325
351
  const fetcher = getResourceFetcher(sdk, type);
326
352
  const data = await fetcher(id, version2);
@@ -344,9 +370,9 @@ ${vizBlock}` : grouped;
344
370
  const encoded = Buffer.from(dsl).toString("base64");
345
371
  const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
346
372
  await (0, import_open.default)(playgroundUrl);
347
- lines.push("", ` Opening in playground...`);
373
+ lines.push("", ` Opening in EventCatalog Modelling...`);
348
374
  } else {
349
- lines.push("", ` Tip: Use --playground to open in the playground`);
375
+ lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
350
376
  }
351
377
  lines.push("");
352
378
  return lines.join("\n");
@@ -359,6 +385,20 @@ var import_node_crypto = require("crypto");
359
385
  var import_node_readline = require("readline");
360
386
  var import_gray_matter = __toESM(require("gray-matter"));
361
387
  var import_sdk4 = __toESM(require("@eventcatalog/sdk"));
388
+ function normalizeImportedFrontmatter(type, frontmatter) {
389
+ const normalized = { ...frontmatter };
390
+ if (type === "container") {
391
+ if (normalized.container_type === void 0 && normalized.containerType !== void 0) {
392
+ normalized.container_type = normalized.containerType;
393
+ delete normalized.containerType;
394
+ }
395
+ if (normalized.access_mode === void 0 && normalized.accessMode !== void 0) {
396
+ normalized.access_mode = normalized.accessMode;
397
+ delete normalized.accessMode;
398
+ }
399
+ }
400
+ return normalized;
401
+ }
362
402
  var RESOURCE_TYPE_FROM_FOLDER = {
363
403
  events: "event",
364
404
  commands: "command",
@@ -393,7 +433,7 @@ ${messages.join("\n")}`);
393
433
  services.shared.workspace.LangiumDocuments.deleteDocument(uri);
394
434
  } catch {
395
435
  }
396
- return outputs;
436
+ return { outputs, program: program2 };
397
437
  }
398
438
  function extractResourceTypeFolder(path) {
399
439
  const segments = path.split("/");
@@ -425,15 +465,17 @@ var MESSAGE_TYPE_FOLDER = {
425
465
  channel: "channels"
426
466
  };
427
467
  var DEFAULT_STUB_VERSION = "0.0.1";
428
- async function extractMessageStubs(source, compiledIds, nested = false) {
429
- const { createEcServices } = await import("@eventcatalog/language-server");
430
- const { EmptyFileSystem, URI } = await import("langium");
431
- const services = createEcServices(EmptyFileSystem);
432
- const uri = URI.parse(`file:///stub-extract-${Date.now()}.ec`);
433
- const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
434
- services.shared.workspace.LangiumDocuments.addDocument(document);
435
- await services.shared.workspace.DocumentBuilder.build([document]);
436
- const program2 = document.parseResult.value;
468
+ var NO_VERSION_KEY = "__no_version__";
469
+ function getResourceNameKey(type, id) {
470
+ return `${type}:${id}`;
471
+ }
472
+ function getResourceVersionKey(type, id, version2) {
473
+ return `${type}:${id}@${version2 || NO_VERSION_KEY}`;
474
+ }
475
+ function hasReferenceStatements(source) {
476
+ return /\b(?:sends|receives|writes-to|reads-from)\b/.test(source);
477
+ }
478
+ async function extractMessageStubs(program2, compiledIds, nested = false) {
437
479
  const stubs = [];
438
480
  const stubIds = /* @__PURE__ */ new Set();
439
481
  function processDefinitions(definitions, parentPath = "") {
@@ -459,63 +501,143 @@ async function extractMessageStubs(source, compiledIds, nested = false) {
459
501
  const servicePath = nested ? parentPath ? `${parentPath}/services/${def.name}` : `services/${def.name}` : "";
460
502
  const body = def.body || [];
461
503
  for (const stmt of body) {
462
- if (stmt.$type !== "SendsStmt" && stmt.$type !== "ReceivesStmt") continue;
463
- const msgType = stmt.messageType;
464
- const msgName = stmt.messageName;
465
- const hasBody = stmt.body && stmt.body.length > 0;
466
- if (hasBody) continue;
467
- const key = `${msgType}:${msgName}`;
468
- if (compiledIds.has(key) || stubIds.has(key)) continue;
469
- const folder = MESSAGE_TYPE_FOLDER[msgType];
470
- if (!folder) continue;
471
- const version2 = stmt.version || DEFAULT_STUB_VERSION;
472
- const stubFolder = nested && servicePath ? `${servicePath}/${folder}` : folder;
473
- stubIds.add(key);
474
- stubs.push({
475
- type: msgType,
476
- id: msgName,
477
- version: version2,
478
- frontmatter: {
479
- id: msgName,
480
- name: msgName,
481
- version: version2
482
- },
483
- markdown: "",
484
- path: `${stubFolder}/${msgName}/versioned/${version2}/index.md`
485
- });
486
- if (stmt.channelClause) {
487
- const channels = stmt.channelClause.channels || [];
488
- for (const ch of channels) {
489
- const chName = ch.channelName;
490
- const chKey = `channel:${chName}`;
491
- if (compiledIds.has(chKey) || stubIds.has(chKey)) continue;
492
- const chVersion = ch.channelVersion || DEFAULT_STUB_VERSION;
493
- const chFolder = nested && parentPath ? `${parentPath}/channels` : "channels";
494
- stubIds.add(chKey);
495
- stubs.push({
496
- type: "channel",
497
- id: chName,
498
- version: chVersion,
499
- frontmatter: {
504
+ if (stmt.$type === "SendsStmt" || stmt.$type === "ReceivesStmt") {
505
+ const msgType = stmt.messageType;
506
+ const msgName = stmt.messageName;
507
+ const hasBody = stmt.body && stmt.body.length > 0;
508
+ const version2 = stmt.version || DEFAULT_STUB_VERSION;
509
+ if (!hasBody) {
510
+ const folder = MESSAGE_TYPE_FOLDER[msgType];
511
+ if (folder) {
512
+ const key = getResourceVersionKey(msgType, msgName, version2);
513
+ const anyVersionKey = getResourceNameKey(msgType, msgName);
514
+ if (!compiledIds.has(key) && !stubIds.has(key) && !(!stmt.version && compiledIds.has(anyVersionKey))) {
515
+ const stubFolder = nested && servicePath ? `${servicePath}/${folder}` : folder;
516
+ stubIds.add(key);
517
+ stubs.push({
518
+ type: msgType,
519
+ id: msgName,
520
+ version: version2,
521
+ frontmatter: {
522
+ id: msgName,
523
+ name: msgName,
524
+ version: version2
525
+ },
526
+ markdown: "",
527
+ path: `${stubFolder}/${msgName}/versioned/${version2}/index.md`
528
+ });
529
+ }
530
+ }
531
+ }
532
+ if (stmt.channelClause) {
533
+ const channels = stmt.channelClause.channels || [];
534
+ for (const ch of channels) {
535
+ const chName = ch.channelName;
536
+ const chVersion = ch.channelVersion || DEFAULT_STUB_VERSION;
537
+ const chKey = getResourceVersionKey("channel", chName, chVersion);
538
+ const chAnyVersionKey = getResourceNameKey("channel", chName);
539
+ if (compiledIds.has(chKey) || stubIds.has(chKey)) continue;
540
+ if (!ch.channelVersion && compiledIds.has(chAnyVersionKey)) continue;
541
+ const chFolder = nested && parentPath ? `${parentPath}/channels` : "channels";
542
+ stubIds.add(chKey);
543
+ stubs.push({
544
+ type: "channel",
500
545
  id: chName,
501
- name: chName,
502
- version: chVersion
503
- },
504
- markdown: "",
505
- path: `${chFolder}/${chName}/versioned/${chVersion}/index.md`
506
- });
546
+ version: chVersion,
547
+ frontmatter: {
548
+ id: chName,
549
+ name: chName,
550
+ version: chVersion
551
+ },
552
+ markdown: "",
553
+ path: `${chFolder}/${chName}/versioned/${chVersion}/index.md`
554
+ });
555
+ }
507
556
  }
557
+ continue;
558
+ }
559
+ if (stmt.$type === "WritesToStmt" || stmt.$type === "ReadsFromStmt") {
560
+ const containerName = stmt.ref?.name;
561
+ if (!containerName) continue;
562
+ const containerVersion = stmt.ref?.version || DEFAULT_STUB_VERSION;
563
+ const containerKey = getResourceVersionKey("container", containerName, containerVersion);
564
+ const containerAnyVersionKey = getResourceNameKey("container", containerName);
565
+ if (compiledIds.has(containerKey) || stubIds.has(containerKey)) continue;
566
+ if (!stmt.ref?.version && compiledIds.has(containerAnyVersionKey)) continue;
567
+ const containerFolder = nested && parentPath ? `${parentPath}/containers` : "containers";
568
+ stubIds.add(containerKey);
569
+ stubs.push({
570
+ type: "container",
571
+ id: containerName,
572
+ version: containerVersion,
573
+ frontmatter: {
574
+ id: containerName,
575
+ name: containerName,
576
+ version: containerVersion
577
+ },
578
+ markdown: "",
579
+ path: `${containerFolder}/${containerName}/versioned/${containerVersion}/index.md`
580
+ });
508
581
  }
509
582
  }
510
583
  }
511
584
  }
512
585
  processDefinitions(program2.definitions);
513
- try {
514
- services.shared.workspace.LangiumDocuments.deleteDocument(uri);
515
- } catch {
516
- }
517
586
  return stubs;
518
587
  }
588
+ function getVersionFromBody(body) {
589
+ if (!body) return void 0;
590
+ const versionStmt = body.find((stmt) => stmt?.$type === "VersionStmt");
591
+ return versionStmt?.value;
592
+ }
593
+ function buildServiceOutputPath(serviceName, body, nested, parentPath) {
594
+ const folder = nested && parentPath ? `${parentPath}/services` : "services";
595
+ const version2 = getVersionFromBody(body);
596
+ if (version2) return `${folder}/${serviceName}/versioned/${version2}/index.md`;
597
+ return `${folder}/${serviceName}/index.md`;
598
+ }
599
+ function extractServiceContainerRefs(program2, nested = false) {
600
+ const refsByPath = /* @__PURE__ */ new Map();
601
+ function processDefinitions(definitions, parentPath = "") {
602
+ for (const def of definitions || []) {
603
+ if (def.$type === "VisualizerDef" && def.body) {
604
+ processDefinitions(def.body, parentPath);
605
+ continue;
606
+ }
607
+ if (def.$type === "DomainDef") {
608
+ const domainPath = nested ? `domains/${def.name}` : "";
609
+ const domainBody = def.body || [];
610
+ const domainServices = domainBody.filter((d) => d.$type === "ServiceDef");
611
+ processDefinitions(domainServices, domainPath);
612
+ const subdomains = domainBody.filter((d) => d.$type === "SubdomainDef");
613
+ for (const sub of subdomains) {
614
+ const subPath = nested ? `domains/${def.name}/subdomains/${sub.name}` : "";
615
+ const subServices = (sub.body || []).filter((d) => d.$type === "ServiceDef");
616
+ processDefinitions(subServices, subPath);
617
+ }
618
+ continue;
619
+ }
620
+ if (def.$type !== "ServiceDef") continue;
621
+ const body = def.body || [];
622
+ const writesTo = body.filter((stmt) => stmt.$type === "WritesToStmt" && stmt.ref?.name).map((stmt) => ({
623
+ id: stmt.ref.name,
624
+ ...stmt.ref.version ? { version: stmt.ref.version } : {}
625
+ }));
626
+ const readsFrom = body.filter((stmt) => stmt.$type === "ReadsFromStmt" && stmt.ref?.name).map((stmt) => ({
627
+ id: stmt.ref.name,
628
+ ...stmt.ref.version ? { version: stmt.ref.version } : {}
629
+ }));
630
+ if (writesTo.length === 0 && readsFrom.length === 0) continue;
631
+ const path = buildServiceOutputPath(def.name, body, nested, parentPath);
632
+ refsByPath.set(path, {
633
+ ...writesTo.length > 0 ? { writesTo } : {},
634
+ ...readsFrom.length > 0 ? { readsFrom } : {}
635
+ });
636
+ }
637
+ }
638
+ processDefinitions(program2.definitions || []);
639
+ return refsByPath;
640
+ }
519
641
  var SDK_WRITER_BASE = {
520
642
  event: "events",
521
643
  command: "commands",
@@ -524,6 +646,8 @@ var SDK_WRITER_BASE = {
524
646
  domain: "domains",
525
647
  channel: "channels",
526
648
  container: "containers",
649
+ dataProduct: "data-products",
650
+ diagram: "diagrams",
527
651
  team: "teams",
528
652
  user: "users"
529
653
  };
@@ -553,6 +677,12 @@ function getWriter(sdk, type) {
553
677
  return sdk.writeDomain;
554
678
  case "channel":
555
679
  return sdk.writeChannel;
680
+ case "container":
681
+ return sdk.writeDataStore;
682
+ case "dataProduct":
683
+ return sdk.writeDataProduct;
684
+ case "diagram":
685
+ return sdk.writeDiagram;
556
686
  case "team":
557
687
  return sdk.writeTeam;
558
688
  case "user":
@@ -575,6 +705,12 @@ function getReader(sdk, type) {
575
705
  return sdk.getDomain;
576
706
  case "channel":
577
707
  return sdk.getChannel;
708
+ case "container":
709
+ return sdk.getDataStore;
710
+ case "dataProduct":
711
+ return sdk.getDataProduct;
712
+ case "diagram":
713
+ return sdk.getDiagram;
578
714
  case "team":
579
715
  return sdk.getTeam;
580
716
  case "user":
@@ -718,26 +854,57 @@ async function importDSL(options) {
718
854
  didInit = true;
719
855
  }
720
856
  }
721
- const outputs = await parseDSL(source, { nested });
857
+ const parsed = await parseDSL(source, { nested });
858
+ const outputs = parsed.outputs;
722
859
  if (outputs.length === 0) {
723
860
  throw new Error("No resources found in DSL content");
724
861
  }
725
862
  const sdk = (0, import_sdk4.default)(catalogDir);
726
863
  const result = { created: [], updated: [], versioned: [], errors: [] };
864
+ const readerCache = /* @__PURE__ */ new Map();
865
+ const readResourceCached = async (reader, type, id, version2) => {
866
+ if (!reader) return void 0;
867
+ const cacheKey = getResourceVersionKey(type, id, version2);
868
+ if (!readerCache.has(cacheKey)) {
869
+ readerCache.set(
870
+ cacheKey,
871
+ reader(id, version2).catch(() => void 0)
872
+ );
873
+ }
874
+ return await readerCache.get(cacheKey);
875
+ };
876
+ const invalidateReaderCache = (type, id, version2) => {
877
+ readerCache.delete(getResourceVersionKey(type, id));
878
+ readerCache.delete(getResourceVersionKey(type, id, version2));
879
+ };
727
880
  const resources = outputs.map(parseCompiledOutput);
728
- const compiledIds = new Set(resources.map((r) => `${r.type}:${r.id}`));
729
- const stubs = await extractMessageStubs(source, compiledIds, nested);
881
+ const serviceContainerRefsByPath = extractServiceContainerRefs(parsed.program, nested);
882
+ for (const resource of resources) {
883
+ if (resource.type !== "service") continue;
884
+ const refs = serviceContainerRefsByPath.get(resource.path);
885
+ if (!refs) continue;
886
+ resource.frontmatter = {
887
+ ...resource.frontmatter,
888
+ ...refs
889
+ };
890
+ }
891
+ const compiledIds = /* @__PURE__ */ new Set();
892
+ for (const resource of resources) {
893
+ compiledIds.add(getResourceNameKey(resource.type, resource.id));
894
+ compiledIds.add(getResourceVersionKey(resource.type, resource.id, resource.version));
895
+ }
896
+ const stubs = hasReferenceStatements(source) ? await extractMessageStubs(parsed.program, compiledIds, nested) : [];
730
897
  resources.push(...stubs);
731
898
  for (const resource of resources) {
732
899
  const label = resource.version ? `${resource.type} ${resource.id}@${resource.version}` : `${resource.type} ${resource.id}`;
733
900
  if (dryRun) {
734
901
  const reader = getReader(sdk, resource.type);
735
902
  if (reader) {
736
- const existing = await reader(resource.id, resource.version).catch(() => void 0);
903
+ const existing = await readResourceCached(reader, resource.type, resource.id, resource.version);
737
904
  if (existing) {
738
905
  result.updated.push(label);
739
906
  } else {
740
- const latest = await reader(resource.id).catch(() => void 0);
907
+ const latest = await readResourceCached(reader, resource.type, resource.id);
741
908
  if (latest && latest.version && latest.version !== resource.version) {
742
909
  result.versioned.push(`${resource.type} ${resource.id}@${latest.version}`);
743
910
  }
@@ -755,20 +922,35 @@ async function importDSL(options) {
755
922
  }
756
923
  try {
757
924
  const reader = getReader(sdk, resource.type);
758
- const existing = reader ? await reader(resource.id, resource.version).catch(() => void 0) : void 0;
759
- let markdown = resource.markdown;
925
+ const existing = await readResourceCached(reader, resource.type, resource.id, resource.version);
926
+ const latest = !existing && resource.version ? await readResourceCached(reader, resource.type, resource.id) : void 0;
927
+ const versionedFrom = !existing && resource.version && latest?.version && latest.version !== resource.version ? latest.version : void 0;
928
+ const incomingMarkdown = resource.markdown;
929
+ const hasIncomingMarkdown = incomingMarkdown.trim().length > 0;
930
+ let markdown = incomingMarkdown;
931
+ if (!hasIncomingMarkdown) {
932
+ if (existing?.markdown) {
933
+ markdown = existing.markdown;
934
+ } else if (!existing && latest?.markdown) {
935
+ markdown = latest.markdown;
936
+ }
937
+ }
760
938
  if (!existing && TYPES_WITH_NODE_GRAPH.has(resource.type)) {
761
- markdown = markdown ? `${markdown}
939
+ if (!markdown) {
940
+ markdown = "<NodeGraph />";
941
+ } else if (!markdown.includes("<NodeGraph />")) {
942
+ markdown = `${markdown}
762
943
 
763
- <NodeGraph />` : "<NodeGraph />";
944
+ <NodeGraph />`;
945
+ }
764
946
  }
765
947
  const resourceData = {
766
- ...resource.frontmatter,
948
+ ...normalizeImportedFrontmatter(resource.type, resource.frontmatter),
767
949
  markdown
768
950
  };
769
951
  const writeOptions = {
770
952
  override: true,
771
- versionExistingContent: true
953
+ versionExistingContent: Boolean(versionedFrom)
772
954
  };
773
955
  if (!existing && nested) {
774
956
  const sdkPath = extractSdkPath(resource.path, resource.type);
@@ -777,10 +959,14 @@ async function importDSL(options) {
777
959
  }
778
960
  }
779
961
  await writer(resourceData, writeOptions);
962
+ invalidateReaderCache(resource.type, resource.id, resource.version);
780
963
  if (existing) {
781
964
  result.updated.push(label);
782
965
  } else {
783
966
  result.created.push(label);
967
+ if (versionedFrom) {
968
+ result.versioned.push(`${resource.type} ${resource.id}@${versionedFrom}`);
969
+ }
784
970
  }
785
971
  } catch (error) {
786
972
  result.errors.push(`${label}: ${error instanceof Error ? error.message : String(error)}`);
@@ -814,8 +1000,11 @@ var TYPE_CONFIG = {
814
1000
  query: { color: c.cyan, label: "query", order: 4 },
815
1001
  channel: { color: c.gray, label: "channel", order: 5 },
816
1002
  flow: { color: c.white, label: "flow", order: 6 },
817
- user: { color: c.blue, label: "user", order: 7 },
818
- team: { color: c.blue, label: "team", order: 8 }
1003
+ container: { color: c.white, label: "container", order: 7 },
1004
+ dataProduct: { color: c.white, label: "data product", order: 8 },
1005
+ diagram: { color: c.white, label: "diagram", order: 9 },
1006
+ user: { color: c.blue, label: "user", order: 10 },
1007
+ team: { color: c.blue, label: "team", order: 11 }
819
1008
  };
820
1009
  var DEFAULT_TYPE_CONFIG = { color: c.white, label: "resource", order: 99 };
821
1010
  function parseLabel(label) {
@@ -928,7 +1117,7 @@ import_commander.program.command("list").description("List all available SDK fun
928
1117
  process.exit(1);
929
1118
  }
930
1119
  });
931
- import_commander.program.command("export").description("Export a catalog resource to EventCatalog DSL (.ec) format").option("-a, --all", "Export the entire catalog (all resource types)", false).option("-r, --resource <type>", "Resource type (event, command, query, service, domain)").option("--id <id>", "Resource ID (omit to export all resources of the given type)").option("-v, --version <version>", "Resource version (defaults to latest)").option("--hydrate", "Include referenced resources (messages, channels, owners)", false).option("--stdout", "Print to stdout instead of writing a file", false).option("--playground", "Open the exported DSL in the playground", false).option("-o, --output <path>", "Output file path (defaults to <id>.ec or catalog.ec)").action(async (opts) => {
1120
+ import_commander.program.command("export").description("Export a catalog resource to EventCatalog DSL (.ec) format").option("-a, --all", "Export the entire catalog (all resource types)", false).option("-r, --resource <type>", "Resource type (event, command, query, service, domain)").option("--id <id>", "Resource ID (omit to export all resources of the given type)").option("-v, --version <version>", "Resource version (defaults to latest)").option("--hydrate", "Include referenced resources (messages, channels, owners)", false).option("--stdout", "Print to stdout instead of writing a file", false).option("--playground", "Open the exported DSL in EventCatalog Modelling", false).option("-o, --output <path>", "Output file path (defaults to <id>.ec or catalog.ec)").action(async (opts) => {
932
1121
  try {
933
1122
  const globalOpts = import_commander.program.opts();
934
1123
  const dir = globalOpts.dir || ".";