@eventcatalog/sdk 2.26.1 → 2.26.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/index.js CHANGED
@@ -2466,430 +2466,118 @@ var dumpCatalog = (directory) => async (options) => {
2466
2466
  };
2467
2467
  };
2468
2468
 
2469
- // src/snapshots.ts
2470
- var import_node_fs9 = __toESM(require("fs"));
2471
- var import_node_path19 = __toESM(require("path"));
2472
- var import_node_crypto = require("crypto");
2473
- var import_node_child_process = require("child_process");
2469
+ // src/graph.ts
2474
2470
  var import_semver6 = require("semver");
2475
2471
 
2476
- // src/snapshot-diff.ts
2477
- var stableStringify = (value) => {
2478
- if (value === null || value === void 0 || typeof value !== "object") {
2479
- return JSON.stringify(value);
2480
- }
2481
- if (Array.isArray(value)) {
2482
- return "[" + value.map(stableStringify).join(",") + "]";
2483
- }
2484
- const sorted = Object.keys(value).sort().map((key) => JSON.stringify(key) + ":" + stableStringify(value[key]));
2485
- return "{" + sorted.join(",") + "}";
2486
- };
2487
- var flattenResources = (snapshot) => {
2488
- const resources = [];
2489
- const addResources = (items, type) => {
2490
- for (const item of items) {
2491
- resources.push({
2492
- resourceId: item.id,
2493
- version: item.version,
2494
- type,
2495
- data: item
2496
- });
2497
- }
2498
- };
2499
- addResources(snapshot.resources.domains, "domain");
2500
- addResources(snapshot.resources.services, "service");
2501
- addResources(snapshot.resources.agents || [], "agent");
2502
- addResources(snapshot.resources.messages.events, "event");
2503
- addResources(snapshot.resources.messages.commands, "command");
2504
- addResources(snapshot.resources.messages.queries, "query");
2505
- addResources(snapshot.resources.channels, "channel");
2506
- return resources;
2472
+ // src/adrs.ts
2473
+ var import_promises12 = __toESM(require("fs/promises"));
2474
+ var import_node_path19 = require("path");
2475
+ var getAdr = (directory) => async (id, version) => getResource(directory, id, version, { type: "adr" });
2476
+ var getAdrs = (directory) => async (options) => getResources(directory, { type: "adrs", latestOnly: options?.latestOnly });
2477
+ var writeAdr = (directory) => async (adr, options = {
2478
+ path: "",
2479
+ override: false,
2480
+ format: "mdx"
2481
+ }) => writeResource(directory, { ...adr }, { ...options, type: "adr" });
2482
+ var rmAdr = (directory) => async (path9) => {
2483
+ await import_promises12.default.rm((0, import_node_path19.join)(directory, path9), { recursive: true });
2484
+ invalidateFileCache();
2507
2485
  };
2508
- var EXCLUDED_FIELDS = /* @__PURE__ */ new Set(["markdown", "_eventcatalog"]);
2509
- var getComparableFields = (data) => {
2510
- const result = {};
2511
- for (const [key, value] of Object.entries(data)) {
2512
- if (!EXCLUDED_FIELDS.has(key)) {
2513
- result[key] = value;
2514
- }
2515
- }
2516
- return result;
2486
+ var rmAdrById = (directory) => async (id, version, persistFiles) => {
2487
+ await rmResourceById(directory, id, version, { type: "adr", persistFiles });
2517
2488
  };
2518
- var findChangedFields = (dataA, dataB) => {
2519
- const fieldsA = getComparableFields(dataA);
2520
- const fieldsB = getComparableFields(dataB);
2521
- const allKeys = /* @__PURE__ */ new Set([...Object.keys(fieldsA), ...Object.keys(fieldsB)]);
2522
- const changed = [];
2523
- for (const key of allKeys) {
2524
- if (stableStringify(fieldsA[key] ?? null) !== stableStringify(fieldsB[key] ?? null)) {
2525
- changed.push(key);
2526
- }
2527
- }
2528
- return changed;
2489
+ var versionAdr = (directory) => async (id) => versionResource(directory, id);
2490
+ var adrHasVersion = (directory) => async (id, version) => {
2491
+ const file = await findFileById(directory, id, version);
2492
+ return !!file;
2529
2493
  };
2530
- var resourceKey = (r) => `${r.resourceId}@${r.version}`;
2531
- var idTypeKey = (r) => `${r.resourceId}:${r.type}`;
2532
- var computeResourceDiff = (snapshotA, snapshotB) => {
2533
- const resourcesA = flattenResources(snapshotA);
2534
- const resourcesB = flattenResources(snapshotB);
2535
- const mapA = /* @__PURE__ */ new Map();
2536
- const byIdA = /* @__PURE__ */ new Map();
2537
- for (const r of resourcesA) {
2538
- mapA.set(resourceKey(r), r);
2539
- byIdA.set(idTypeKey(r), r);
2540
- }
2541
- const mapB = /* @__PURE__ */ new Map();
2542
- const byIdB = /* @__PURE__ */ new Map();
2543
- for (const r of resourcesB) {
2544
- mapB.set(resourceKey(r), r);
2545
- byIdB.set(idTypeKey(r), r);
2546
- }
2547
- const changes = [];
2548
- const handledIds = /* @__PURE__ */ new Set();
2549
- for (const resource of resourcesB) {
2550
- const key = resourceKey(resource);
2551
- if (!mapA.has(key)) {
2552
- const idKey = idTypeKey(resource);
2553
- const oldResource = byIdA.get(idKey);
2554
- if (oldResource && oldResource.version !== resource.version && !handledIds.has(idKey)) {
2555
- const changedFields = findChangedFields(oldResource.data, resource.data);
2556
- changes.push({
2557
- resourceId: resource.resourceId,
2558
- version: resource.version,
2559
- type: resource.type,
2560
- changeType: "versioned",
2561
- previousVersion: oldResource.version,
2562
- newVersion: resource.version,
2563
- changedFields: changedFields.length > 0 ? changedFields : void 0
2564
- });
2565
- handledIds.add(idKey);
2566
- } else if (!handledIds.has(idKey)) {
2567
- changes.push({
2568
- resourceId: resource.resourceId,
2569
- version: resource.version,
2570
- type: resource.type,
2571
- changeType: "added"
2572
- });
2573
- }
2574
- }
2575
- }
2576
- for (const resource of resourcesA) {
2577
- const key = resourceKey(resource);
2578
- if (!mapB.has(key)) {
2579
- const idKey = idTypeKey(resource);
2580
- if (!handledIds.has(idKey)) {
2581
- changes.push({
2582
- resourceId: resource.resourceId,
2583
- version: resource.version,
2584
- type: resource.type,
2585
- changeType: "removed"
2586
- });
2587
- }
2588
- }
2589
- }
2590
- for (const resourceB of resourcesB) {
2591
- const key = resourceKey(resourceB);
2592
- const resourceA = mapA.get(key);
2593
- if (resourceA) {
2594
- const changedFields = findChangedFields(resourceA.data, resourceB.data);
2595
- if (changedFields.length > 0) {
2596
- changes.push({
2597
- resourceId: resourceB.resourceId,
2598
- version: resourceB.version,
2599
- type: resourceB.type,
2600
- changeType: "modified",
2601
- changedFields
2602
- });
2603
- }
2604
- }
2605
- }
2606
- return changes;
2494
+ var addFileToAdr = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version, { type: "adr" });
2495
+
2496
+ // src/data-products.ts
2497
+ var import_promises13 = __toESM(require("fs/promises"));
2498
+ var import_node_path20 = require("path");
2499
+ var getDataProduct = (directory) => async (id, version) => getResource(directory, id, version, { type: "data-product" });
2500
+ var getDataProducts = (directory) => async (options) => getResources(directory, { type: "data-products", latestOnly: options?.latestOnly });
2501
+ var writeDataProduct = (directory) => async (dataProduct, options = {
2502
+ path: "",
2503
+ override: false,
2504
+ format: "mdx"
2505
+ }) => writeResource(directory, { ...dataProduct }, { ...options, type: "data-product" });
2506
+ var writeDataProductToDomain = (directory) => async (dataProduct, domain, options = { path: "", format: "mdx", override: false }) => {
2507
+ let pathForDataProduct = domain.version && domain.version !== "latest" ? `/${domain.id}/versioned/${domain.version}/data-products` : `/${domain.id}/data-products`;
2508
+ pathForDataProduct = (0, import_node_path20.join)(pathForDataProduct, dataProduct.id);
2509
+ await writeResource(directory, { ...dataProduct }, { ...options, path: pathForDataProduct, type: "data-product" });
2607
2510
  };
2608
- var getRelationshipKey = (serviceId, resourceId, resourceVersion, direction) => {
2609
- return `${serviceId}:${direction}:${resourceId}@${resourceVersion || "latest"}`;
2511
+ var rmDataProduct = (directory) => async (path9) => {
2512
+ await import_promises13.default.rm((0, import_node_path20.join)(directory, path9), { recursive: true });
2513
+ invalidateFileCache();
2610
2514
  };
2611
- var extractRelationships = (snapshot) => {
2612
- const relationships = /* @__PURE__ */ new Map();
2613
- for (const service of [...snapshot.resources.services, ...snapshot.resources.agents || []]) {
2614
- for (const direction of ["sends", "receives"]) {
2615
- const pointers = service[direction] || [];
2616
- for (const pointer of pointers) {
2617
- const key = getRelationshipKey(service.id, pointer.id, pointer.version, direction);
2618
- relationships.set(key, {
2619
- serviceId: service.id,
2620
- serviceVersion: service.version,
2621
- resourceId: pointer.id,
2622
- resourceVersion: pointer.version,
2623
- direction
2624
- });
2625
- }
2626
- }
2627
- }
2628
- return relationships;
2515
+ var rmDataProductById = (directory) => async (id, version, persistFiles) => {
2516
+ await rmResourceById(directory, id, version, { type: "data-product", persistFiles });
2629
2517
  };
2630
- var computeRelationshipDiff = (snapshotA, snapshotB) => {
2631
- const relsA = extractRelationships(snapshotA);
2632
- const relsB = extractRelationships(snapshotB);
2633
- const changes = [];
2634
- for (const [key, rel] of relsB) {
2635
- if (!relsA.has(key)) {
2636
- changes.push({ ...rel, changeType: "added" });
2637
- }
2638
- }
2639
- for (const [key, rel] of relsA) {
2640
- if (!relsB.has(key)) {
2641
- changes.push({ ...rel, changeType: "removed" });
2642
- }
2643
- }
2644
- return changes;
2518
+ var versionDataProduct = (directory) => async (id) => versionResource(directory, id);
2519
+ var dataProductHasVersion = (directory) => async (id, version) => {
2520
+ const file = await findFileById(directory, id, version);
2521
+ return !!file;
2645
2522
  };
2523
+ var addFileToDataProduct = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version);
2646
2524
 
2647
- // src/snapshots.ts
2648
- var SNAPSHOT_VERSION = "1.0.0";
2649
- var getEventCatalogVersion2 = (catalogDir) => {
2650
- try {
2651
- const packageJson = import_node_fs9.default.readFileSync(import_node_path19.default.join(catalogDir, "package.json"), "utf8");
2652
- const packageJsonObject = JSON.parse(packageJson);
2653
- return packageJsonObject["dependencies"]?.["@eventcatalog/core"] ?? "unknown";
2654
- } catch {
2655
- return "unknown";
2656
- }
2525
+ // src/containers.ts
2526
+ var import_promises14 = __toESM(require("fs/promises"));
2527
+ var import_node_path21 = require("path");
2528
+ var getContainer = (directory) => async (id, version) => getResource(directory, id, version, { type: "container" });
2529
+ var getContainers = (directory) => async (options) => getResources(directory, { type: "containers", latestOnly: options?.latestOnly });
2530
+ var writeContainer = (directory) => async (data, options = {
2531
+ path: "",
2532
+ override: false,
2533
+ format: "mdx"
2534
+ }) => writeResource(directory, { ...data }, { ...options, type: "container" });
2535
+ var versionContainer = (directory) => async (id) => versionResource(directory, id);
2536
+ var rmContainer = (directory) => async (path9) => {
2537
+ await import_promises14.default.rm((0, import_node_path21.join)(directory, path9), { recursive: true });
2538
+ invalidateFileCache();
2657
2539
  };
2658
- var pickCoreFields = (resource) => {
2659
- const picked = { id: resource.id, version: resource.version, name: resource.name };
2660
- if (resource.sends) picked.sends = resource.sends;
2661
- if (resource.receives) picked.receives = resource.receives;
2662
- if (resource.deprecated) picked.deprecated = resource.deprecated;
2663
- if (resource.owners) picked.owners = resource.owners;
2664
- if (resource.schemaPath) picked.schemaPath = resource.schemaPath;
2665
- if (resource.schemaHash) picked.schemaHash = resource.schemaHash;
2666
- return picked;
2540
+ var rmContainerById = (directory) => async (id, version, persistFiles) => {
2541
+ await rmResourceById(directory, id, version, { type: "container", persistFiles });
2667
2542
  };
2668
- var deduplicateByLatestVersion = (resources) => {
2669
- const seen = /* @__PURE__ */ new Map();
2670
- for (const r of resources) {
2671
- const existing = seen.get(r.id);
2672
- if (!existing || (0, import_semver6.compare)(r.version, existing.version) > 0) {
2673
- seen.set(r.id, r);
2674
- }
2675
- }
2676
- return Array.from(seen.values());
2543
+ var containerHasVersion = (directory) => async (id, version) => {
2544
+ const file = await findFileById(directory, id, version);
2545
+ return !!file;
2677
2546
  };
2678
- var stripToCore = (resources) => {
2679
- if (!resources || resources.length === 0) return [];
2680
- return deduplicateByLatestVersion(resources).map(pickCoreFields);
2547
+ var addFileToContainer = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version);
2548
+ var writeContainerToService = (directory) => async (container, service, options = { path: "", format: "mdx", override: false }) => {
2549
+ const resourcePath = await getResourcePath(directory, service.id, service.version);
2550
+ if (!resourcePath) {
2551
+ throw new Error("Service not found");
2552
+ }
2553
+ let pathForContainer = service.version && service.version !== "latest" ? `${resourcePath.directory}/versioned/${service.version}/containers` : `${resourcePath.directory}/containers`;
2554
+ pathForContainer = (0, import_node_path21.join)(pathForContainer, container.id);
2555
+ await writeResource(directory, { ...container }, { ...options, path: pathForContainer, type: "container" });
2681
2556
  };
2682
- var detectGitInfo = (catalogDir) => {
2683
- try {
2684
- const opts = { cwd: catalogDir, encoding: "utf8", stdio: "pipe" };
2685
- const branch = (0, import_node_child_process.execSync)("git rev-parse --abbrev-ref HEAD", opts).trim();
2686
- const commit = (0, import_node_child_process.execSync)("git rev-parse --short HEAD", opts).trim();
2687
- const status = (0, import_node_child_process.execSync)("git status --porcelain", opts).trim();
2688
- return { branch, commit, dirty: status.length > 0 };
2689
- } catch {
2690
- return void 0;
2691
- }
2692
- };
2693
- var enrichWithSchemaHashes = async (getSchemaForMessage2, resources) => {
2694
- await Promise.all(
2695
- resources.map(async (resource) => {
2696
- if (!resource.schemaPath) return;
2697
- const schema = await getSchemaForMessage2(resource.id, resource.version);
2698
- if (!schema) return;
2699
- resource.schemaHash = (0, import_node_crypto.createHash)("sha256").update(schema.schema).digest("hex");
2700
- })
2701
- );
2702
- };
2703
- var createSnapshot = (directory) => {
2704
- return async (options) => {
2705
- const { label, outputDir, git } = options || {};
2706
- const sdk = src_default(directory);
2707
- const [domains, services, agents, events, commands, queries, channels] = await Promise.all([
2708
- sdk.getDomains(),
2709
- sdk.getServices(),
2710
- sdk.getAgents(),
2711
- sdk.getEvents(),
2712
- sdk.getCommands(),
2713
- sdk.getQueries(),
2714
- sdk.getChannels()
2715
- ]);
2716
- await Promise.all([
2717
- enrichWithSchemaHashes(sdk.getSchemaForMessage, events || []),
2718
- enrichWithSchemaHashes(sdk.getSchemaForMessage, commands || []),
2719
- enrichWithSchemaHashes(sdk.getSchemaForMessage, queries || [])
2720
- ]);
2721
- const snapshotDomains = stripToCore(domains);
2722
- const snapshotServices = stripToCore(services);
2723
- const snapshotAgents = stripToCore(agents);
2724
- const snapshotEvents = stripToCore(events);
2725
- const snapshotCommands = stripToCore(commands);
2726
- const snapshotQueries = stripToCore(queries);
2727
- const snapshotChannels = stripToCore(channels);
2728
- const snapshotLabel = label || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2729
- const gitInfo = git || detectGitInfo(directory);
2730
- const snapshot = {
2731
- snapshotVersion: SNAPSHOT_VERSION,
2732
- catalogVersion: getEventCatalogVersion2(directory),
2733
- label: snapshotLabel,
2734
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2735
- ...gitInfo ? { git: gitInfo } : {},
2736
- resources: {
2737
- domains: snapshotDomains,
2738
- services: snapshotServices,
2739
- agents: snapshotAgents,
2740
- messages: {
2741
- events: snapshotEvents,
2742
- commands: snapshotCommands,
2743
- queries: snapshotQueries
2744
- },
2745
- channels: snapshotChannels
2746
- }
2747
- };
2748
- const snapshotsDir = outputDir || import_node_path19.default.join(directory, ".snapshots");
2749
- import_node_fs9.default.mkdirSync(snapshotsDir, { recursive: true });
2750
- const fileName = `${snapshotLabel}.snapshot.json`;
2751
- const filePath = import_node_path19.default.join(snapshotsDir, fileName);
2752
- import_node_fs9.default.writeFileSync(filePath, JSON.stringify(snapshot));
2753
- return { filePath, snapshot };
2754
- };
2755
- };
2756
- var diffSnapshots = (directory) => async (snapshotAPath, snapshotBPath) => {
2757
- const snapshotA = JSON.parse(import_node_fs9.default.readFileSync(snapshotAPath, "utf-8"));
2758
- const snapshotB = JSON.parse(import_node_fs9.default.readFileSync(snapshotBPath, "utf-8"));
2759
- const resourceChanges = computeResourceDiff(snapshotA, snapshotB);
2760
- const relationshipChanges = computeRelationshipDiff(snapshotA, snapshotB);
2761
- const resourceCounts = { added: 0, removed: 0, modified: 0, versioned: 0 };
2762
- for (const r of resourceChanges) resourceCounts[r.changeType]++;
2763
- const relCounts = { added: 0, removed: 0 };
2764
- for (const r of relationshipChanges) relCounts[r.changeType]++;
2765
- return {
2766
- snapshotA: { label: snapshotA.label, createdAt: snapshotA.createdAt },
2767
- snapshotB: { label: snapshotB.label, createdAt: snapshotB.createdAt },
2768
- summary: {
2769
- totalChanges: resourceChanges.length + relationshipChanges.length,
2770
- resourcesAdded: resourceCounts.added,
2771
- resourcesRemoved: resourceCounts.removed,
2772
- resourcesModified: resourceCounts.modified,
2773
- resourcesVersioned: resourceCounts.versioned,
2774
- relationshipsAdded: relCounts.added,
2775
- relationshipsRemoved: relCounts.removed
2776
- },
2777
- resources: resourceChanges,
2778
- relationships: relationshipChanges
2779
- };
2780
- };
2781
- var listSnapshots = (directory) => async () => {
2782
- const snapshotsDir = import_node_path19.default.join(directory, ".snapshots");
2783
- if (!import_node_fs9.default.existsSync(snapshotsDir)) return [];
2784
- const files = import_node_fs9.default.readdirSync(snapshotsDir).filter((f) => f.endsWith(".snapshot.json"));
2785
- const snapshots = [];
2786
- for (const file of files) {
2787
- try {
2788
- const filePath = import_node_path19.default.join(snapshotsDir, file);
2789
- const content = JSON.parse(import_node_fs9.default.readFileSync(filePath, "utf-8"));
2790
- snapshots.push({
2791
- label: content.label,
2792
- createdAt: content.createdAt,
2793
- filePath,
2794
- ...content.git ? { git: content.git } : {}
2795
- });
2796
- } catch {
2797
- }
2798
- }
2799
- return snapshots.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
2800
- };
2801
-
2802
- // src/changelogs.ts
2803
- var import_node_path20 = __toESM(require("path"));
2804
- var import_node_fs10 = __toESM(require("fs"));
2805
- var import_promises12 = __toESM(require("fs/promises"));
2806
- var import_gray_matter8 = __toESM(require("gray-matter"));
2807
- var writeChangelog = (catalogDir) => async (id, changelog, options = {}) => {
2808
- const { version, format = "mdx" } = options;
2809
- const resourceFile = await findFileById(catalogDir, id, version);
2810
- if (!resourceFile) {
2811
- throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
2812
- }
2813
- const resourceDir = (0, import_node_path20.dirname)(resourceFile);
2814
- const changelogPath = import_node_path20.default.join(resourceDir, `changelog.${format}`);
2815
- const { markdown, ...frontmatter } = changelog;
2816
- const fm = { ...frontmatter };
2817
- if (fm.createdAt instanceof Date) {
2818
- fm.createdAt = fm.createdAt;
2819
- }
2820
- if (!fm.badges || fm.badges.length === 0) {
2821
- delete fm.badges;
2557
+ var writeContainerToSystem = (directory) => async (container, system, options = { path: "", format: "mdx", override: false }) => {
2558
+ const resourcePath = await getResourcePath(directory, system.id, system.version);
2559
+ if (!resourcePath) {
2560
+ throw new Error("System not found");
2822
2561
  }
2823
- import_node_fs10.default.mkdirSync(resourceDir, { recursive: true });
2824
- const document = import_gray_matter8.default.stringify(markdown.trim(), fm);
2825
- import_node_fs10.default.writeFileSync(changelogPath, document);
2826
- invalidateFileCache();
2562
+ const pathForContainer = (0, import_node_path21.join)(resourcePath.directory, "containers", container.id);
2563
+ await writeResource(directory, { ...container }, { ...options, path: pathForContainer, type: "container" });
2827
2564
  };
2828
- var appendChangelog = (catalogDir) => async (id, changelog, options = {}) => {
2829
- const { version, format = "mdx" } = options;
2830
- const resourceFile = await findFileById(catalogDir, id, version);
2831
- if (!resourceFile) {
2832
- throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
2833
- }
2834
- const resourceDir = (0, import_node_path20.dirname)(resourceFile);
2835
- const mdxPath = import_node_path20.default.join(resourceDir, "changelog.mdx");
2836
- const mdPath = import_node_path20.default.join(resourceDir, "changelog.md");
2837
- const existingPath = import_node_fs10.default.existsSync(mdxPath) ? mdxPath : import_node_fs10.default.existsSync(mdPath) ? mdPath : void 0;
2838
- if (!existingPath) {
2839
- return writeChangelog(catalogDir)(id, changelog, options);
2840
- }
2841
- const existing = import_gray_matter8.default.read(existingPath);
2842
- const existingContent = existing.content.trim();
2843
- const newEntry = changelog.markdown.trim();
2844
- const combined = `${newEntry}
2845
2565
 
2846
- ---
2847
-
2848
- ${existingContent}`;
2849
- const fm = { ...existing.data };
2850
- fm.createdAt = changelog.createdAt;
2851
- if (changelog.badges && changelog.badges.length > 0) {
2852
- fm.badges = changelog.badges;
2853
- } else {
2854
- delete fm.badges;
2855
- }
2856
- const document = import_gray_matter8.default.stringify(combined, fm);
2857
- import_node_fs10.default.writeFileSync(existingPath, document);
2858
- invalidateFileCache();
2859
- };
2860
- var getChangelog = (catalogDir) => async (id, options = {}) => {
2861
- const { version } = options;
2862
- const resourceFile = await findFileById(catalogDir, id, version);
2863
- if (!resourceFile) return void 0;
2864
- const resourceDir = (0, import_node_path20.dirname)(resourceFile);
2865
- const mdxPath = import_node_path20.default.join(resourceDir, "changelog.mdx");
2866
- const mdPath = import_node_path20.default.join(resourceDir, "changelog.md");
2867
- const changelogPath = import_node_fs10.default.existsSync(mdxPath) ? mdxPath : import_node_fs10.default.existsSync(mdPath) ? mdPath : void 0;
2868
- if (!changelogPath) return void 0;
2869
- const { data, content } = import_gray_matter8.default.read(changelogPath);
2870
- return { ...data, markdown: content.trim() };
2871
- };
2872
- var rmChangelog = (catalogDir) => async (id, options = {}) => {
2873
- const { version } = options;
2874
- const resourceFile = await findFileById(catalogDir, id, version);
2875
- if (!resourceFile) {
2876
- throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
2877
- }
2878
- const resourceDir = (0, import_node_path20.dirname)(resourceFile);
2879
- const mdxPath = import_node_path20.default.join(resourceDir, "changelog.mdx");
2880
- const mdPath = import_node_path20.default.join(resourceDir, "changelog.md");
2881
- if (import_node_fs10.default.existsSync(mdxPath)) {
2882
- await import_promises12.default.rm(mdxPath);
2883
- }
2884
- if (import_node_fs10.default.existsSync(mdPath)) {
2885
- await import_promises12.default.rm(mdPath);
2886
- }
2887
- invalidateFileCache();
2888
- };
2566
+ // src/data-stores.ts
2567
+ var getDataStore = getContainer;
2568
+ var getDataStores = getContainers;
2569
+ var writeDataStore = writeContainer;
2570
+ var versionDataStore = versionContainer;
2571
+ var rmDataStore = rmContainer;
2572
+ var rmDataStoreById = rmContainerById;
2573
+ var dataStoreHasVersion = containerHasVersion;
2574
+ var addFileToDataStore = addFileToContainer;
2575
+ var writeDataStoreToService = writeContainerToService;
2576
+ var writeDataStoreToSystem = writeContainerToSystem;
2889
2577
 
2890
2578
  // src/entities.ts
2891
- var import_promises13 = __toESM(require("fs/promises"));
2892
- var import_node_path21 = require("path");
2579
+ var import_promises15 = __toESM(require("fs/promises"));
2580
+ var import_node_path22 = require("path");
2893
2581
  var getEntity = (directory) => async (id, version) => getResource(directory, id, version, { type: "entity" });
2894
2582
  var getEntities = (directory) => async (options) => getResources(directory, { type: "entities", latestOnly: options?.latestOnly });
2895
2583
  var writeEntity = (directory) => async (entity, options = {
@@ -2902,11 +2590,11 @@ var writeEntityToSystem = (directory) => async (entity, system, options = { path
2902
2590
  if (!resourcePath) {
2903
2591
  throw new Error("System not found");
2904
2592
  }
2905
- const pathForEntity = (0, import_node_path21.join)(resourcePath.directory, "entities", entity.id);
2593
+ const pathForEntity = (0, import_node_path22.join)(resourcePath.directory, "entities", entity.id);
2906
2594
  await writeResource(directory, { ...entity }, { ...options, path: pathForEntity, type: "entity" });
2907
2595
  };
2908
2596
  var rmEntity = (directory) => async (path9) => {
2909
- await import_promises13.default.rm((0, import_node_path21.join)(directory, path9), { recursive: true });
2597
+ await import_promises15.default.rm((0, import_node_path22.join)(directory, path9), { recursive: true });
2910
2598
  invalidateFileCache();
2911
2599
  };
2912
2600
  var rmEntityById = (directory) => async (id, version, persistFiles) => {
@@ -2919,8 +2607,8 @@ var entityHasVersion = (directory) => async (id, version) => {
2919
2607
  };
2920
2608
 
2921
2609
  // src/flows.ts
2922
- var import_promises14 = __toESM(require("fs/promises"));
2923
- var import_node_path22 = require("path");
2610
+ var import_promises16 = __toESM(require("fs/promises"));
2611
+ var import_node_path23 = require("path");
2924
2612
 
2925
2613
  // src/flow-builder.ts
2926
2614
  var cloneStep = (step) => ({
@@ -3384,144 +3072,815 @@ var FlowBuilder = class _FlowBuilder {
3384
3072
  throw new Error(`Flow step "${step.id}" references missing next step "${nextStepId}"`);
3385
3073
  }
3386
3074
  }
3387
- }
3388
- }
3389
- };
3390
-
3391
- // src/flows.ts
3392
- var getFlow = (directory) => async (id, version) => getResource(directory, id, version, { type: "flow" });
3393
- var getFlows = (directory) => async (options) => getResources(directory, { type: "flows", latestOnly: options?.latestOnly });
3394
- var writeFlow = (directory) => async (flow, options = {
3395
- path: "",
3396
- override: false,
3397
- format: "mdx"
3398
- }) => writeResource(directory, { ...flow }, { ...options, type: "flow" });
3399
- var writeVersionedFlow = (directory) => async (flow) => {
3400
- const path9 = getVersionedDirectory(flow.id, flow.version);
3401
- return await writeFlow(directory)({ ...flow }, { path: path9 });
3402
- };
3403
- var writeFlowToDomain = (directory) => async (flow, domain, options = { path: "", format: "mdx", override: false }) => {
3404
- let pathForFlow = domain.version && domain.version !== "latest" ? `/${domain.id}/versioned/${domain.version}/flows` : `/${domain.id}/flows`;
3405
- pathForFlow = (0, import_node_path22.join)(pathForFlow, flow.id);
3406
- await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3075
+ }
3076
+ }
3077
+ };
3078
+
3079
+ // src/flows.ts
3080
+ var getFlow = (directory) => async (id, version) => getResource(directory, id, version, { type: "flow" });
3081
+ var getFlows = (directory) => async (options) => getResources(directory, { type: "flows", latestOnly: options?.latestOnly });
3082
+ var writeFlow = (directory) => async (flow, options = {
3083
+ path: "",
3084
+ override: false,
3085
+ format: "mdx"
3086
+ }) => writeResource(directory, { ...flow }, { ...options, type: "flow" });
3087
+ var writeVersionedFlow = (directory) => async (flow) => {
3088
+ const path9 = getVersionedDirectory(flow.id, flow.version);
3089
+ return await writeFlow(directory)({ ...flow }, { path: path9 });
3090
+ };
3091
+ var writeFlowToDomain = (directory) => async (flow, domain, options = { path: "", format: "mdx", override: false }) => {
3092
+ let pathForFlow = domain.version && domain.version !== "latest" ? `/${domain.id}/versioned/${domain.version}/flows` : `/${domain.id}/flows`;
3093
+ pathForFlow = (0, import_node_path23.join)(pathForFlow, flow.id);
3094
+ await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3095
+ };
3096
+ var writeFlowToService = (directory) => async (flow, service, options = { path: "", format: "mdx", override: false }) => {
3097
+ let pathForFlow = service.version && service.version !== "latest" ? `/${service.id}/versioned/${service.version}/flows` : `/${service.id}/flows`;
3098
+ pathForFlow = (0, import_node_path23.join)(pathForFlow, flow.id);
3099
+ await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3100
+ };
3101
+ var writeFlowToSystem = (directory) => async (flow, system, options = { path: "", format: "mdx", override: false }) => {
3102
+ const resourcePath = await getResourcePath(directory, system.id, system.version);
3103
+ if (!resourcePath) {
3104
+ throw new Error("System not found");
3105
+ }
3106
+ const pathForFlow = (0, import_node_path23.join)(resourcePath.directory, "flows", flow.id);
3107
+ await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3108
+ };
3109
+ var writeFlowToAgent = (directory) => async (flow, agent, options = { path: "", format: "mdx", override: false }) => {
3110
+ let pathForFlow = agent.version && agent.version !== "latest" ? `/${agent.id}/versioned/${agent.version}/flows` : `/${agent.id}/flows`;
3111
+ pathForFlow = (0, import_node_path23.join)(pathForFlow, flow.id);
3112
+ await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3113
+ };
3114
+ var rmFlow = (directory) => async (path9) => {
3115
+ await import_promises16.default.rm((0, import_node_path23.join)(directory, path9), { recursive: true });
3116
+ invalidateFileCache();
3117
+ };
3118
+ var rmFlowById = (directory) => async (id, version, persistFiles) => {
3119
+ await rmResourceById(directory, id, version, { type: "flow", persistFiles });
3120
+ };
3121
+ var versionFlow = (directory) => async (id) => versionResource(directory, id);
3122
+ var flowHasVersion = (directory) => async (id, version) => {
3123
+ const file = await findFileById(directory, id, version);
3124
+ return !!file;
3125
+ };
3126
+ var addFileToFlow = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version, { type: "flow" });
3127
+
3128
+ // src/graph.ts
3129
+ var DEFAULT_DEPTH = Number.POSITIVE_INFINITY;
3130
+ var RESOURCE_TYPE_ORDER = [
3131
+ "domain",
3132
+ "system",
3133
+ "service",
3134
+ "agent",
3135
+ "event",
3136
+ "command",
3137
+ "query",
3138
+ "channel",
3139
+ "entity",
3140
+ "container",
3141
+ "data-product",
3142
+ "flow",
3143
+ "adr"
3144
+ ];
3145
+ var typeOrder = new Map(RESOURCE_TYPE_ORDER.map((type, index) => [type, index]));
3146
+ var NON_ADR_RESOURCE_TYPES = RESOURCE_TYPE_ORDER.filter((type) => type !== "adr");
3147
+ var NESTED_TRAVERSAL_CONCURRENCY = 16;
3148
+ var RESOURCE_TYPE_ALIASES = {
3149
+ domains: "domain",
3150
+ systems: "system",
3151
+ services: "service",
3152
+ agents: "agent",
3153
+ events: "event",
3154
+ commands: "command",
3155
+ queries: "query",
3156
+ channels: "channel",
3157
+ entities: "entity",
3158
+ containers: "container",
3159
+ "data-products": "data-product",
3160
+ flows: "flow",
3161
+ adrs: "adr"
3162
+ };
3163
+ var resourceKey = (resource) => `${resource.type}:${resource.id}:${resource.version}`;
3164
+ var toGraphResource = (type, resource) => ({
3165
+ type,
3166
+ id: resource.id,
3167
+ version: resource.version
3168
+ });
3169
+ var sortResources = (left, right) => {
3170
+ const typeComparison = (typeOrder.get(left.type) || 0) - (typeOrder.get(right.type) || 0);
3171
+ if (typeComparison !== 0) return typeComparison;
3172
+ const idComparison = left.id.localeCompare(right.id);
3173
+ return idComparison !== 0 ? idComparison : left.version.localeCompare(right.version);
3174
+ };
3175
+ var normalizeResourceType = (type) => {
3176
+ if (!type) return void 0;
3177
+ if (RESOURCE_TYPE_ORDER.includes(type)) return type;
3178
+ return RESOURCE_TYPE_ALIASES[type];
3179
+ };
3180
+ var indexResources = (resources) => {
3181
+ const byId = /* @__PURE__ */ new Map();
3182
+ const byVersion = /* @__PURE__ */ new Map();
3183
+ for (const resource of resources) {
3184
+ const versions = byId.get(resource.id);
3185
+ if (versions) versions.push(resource);
3186
+ else byId.set(resource.id, [resource]);
3187
+ byVersion.set(`${resource.id}:${resource.version}`, resource);
3188
+ }
3189
+ return { byId, byVersion };
3190
+ };
3191
+ var pathIncludes = (path9, key) => {
3192
+ let current = path9;
3193
+ while (current) {
3194
+ if (current.key === key) return true;
3195
+ current = current.parent;
3196
+ }
3197
+ return false;
3198
+ };
3199
+ var mapWithConcurrency = async (items, concurrency, transform) => {
3200
+ const results = new Array(items.length);
3201
+ let nextIndex = 0;
3202
+ const worker = async () => {
3203
+ while (nextIndex < items.length) {
3204
+ const index = nextIndex++;
3205
+ results[index] = await transform(items[index]);
3206
+ }
3207
+ };
3208
+ const workers = Array.from({ length: Math.min(concurrency, items.length) }, worker);
3209
+ await Promise.all(workers);
3210
+ return results;
3211
+ };
3212
+ var validateDepth = (depth) => {
3213
+ if (!Number.isInteger(depth) || depth < 0) {
3214
+ throw new Error("Graph depth must be a non-negative integer");
3215
+ }
3216
+ };
3217
+ var getGraph = (directory) => {
3218
+ const graph = async (root, options = {}) => {
3219
+ const depth = options.depth ?? DEFAULT_DEPTH;
3220
+ if (options.depth !== void 0) validateDepth(depth);
3221
+ const collectionLoaders = {
3222
+ domain: getDomains(directory),
3223
+ system: getSystems(directory),
3224
+ service: getServices(directory),
3225
+ agent: getAgents(directory),
3226
+ event: getEvents(directory),
3227
+ command: getCommands(directory),
3228
+ query: getQueries(directory),
3229
+ flow: getFlows(directory),
3230
+ channel: getChannels(directory),
3231
+ entity: getEntities(directory),
3232
+ container: getDataStores(directory),
3233
+ "data-product": getDataProducts(directory),
3234
+ adr: getAdrs(directory)
3235
+ };
3236
+ const latestIndexCache = /* @__PURE__ */ new Map();
3237
+ const allVersionsIndexCache = /* @__PURE__ */ new Map();
3238
+ const adjacencyCache = /* @__PURE__ */ new Map();
3239
+ const loadLatestIndex = (type) => {
3240
+ const cachedIndex = latestIndexCache.get(type);
3241
+ if (cachedIndex) return cachedIndex;
3242
+ const index = collectionLoaders[type]({ latestOnly: true }).then((resources2) => indexResources(resources2 || []));
3243
+ latestIndexCache.set(type, index);
3244
+ return index;
3245
+ };
3246
+ const loadAllVersionsIndex = (type) => {
3247
+ const cachedIndex = allVersionsIndexCache.get(type);
3248
+ if (cachedIndex) return cachedIndex;
3249
+ const latestIndex = latestIndexCache.get(type);
3250
+ const index = Promise.all([collectionLoaders[type](), latestIndex]).then(([resources2, loadedLatestIndex]) => {
3251
+ const allVersionsIndex = indexResources(resources2 || []);
3252
+ for (const [id, latestResources] of loadedLatestIndex?.byId || []) {
3253
+ const latestResource = latestResources[0];
3254
+ if (!latestResource) continue;
3255
+ const key = `${id}:${latestResource.version}`;
3256
+ if (!allVersionsIndex.byVersion.has(key)) continue;
3257
+ allVersionsIndex.byVersion.set(key, latestResource);
3258
+ const versions = allVersionsIndex.byId.get(id);
3259
+ const matchingVersion = versions?.findIndex((resource) => resource.version === latestResource.version) ?? -1;
3260
+ if (versions && matchingVersion !== -1) versions[matchingVersion] = latestResource;
3261
+ }
3262
+ return allVersionsIndex;
3263
+ });
3264
+ allVersionsIndexCache.set(type, index);
3265
+ return index;
3266
+ };
3267
+ const read = async (type, pointer) => {
3268
+ const latestIndex = await loadLatestIndex(type);
3269
+ const latestResource = latestIndex.byId.get(pointer.id)?.[0];
3270
+ if (!pointer.version || pointer.version === "latest") {
3271
+ return latestResource;
3272
+ }
3273
+ if (latestResource?.version === pointer.version) return latestResource;
3274
+ const allVersionsIndex = await loadAllVersionsIndex(type);
3275
+ const exactMatch = allVersionsIndex.byVersion.get(`${pointer.id}:${pointer.version}`);
3276
+ if (exactMatch) return exactMatch;
3277
+ const range = (0, import_semver6.validRange)(pointer.version);
3278
+ if (!range) return void 0;
3279
+ const candidates = allVersionsIndex.byId.get(pointer.id) || [];
3280
+ const version = (0, import_semver6.maxSatisfying)(
3281
+ candidates.map((resource) => resource.version),
3282
+ range
3283
+ );
3284
+ return candidates.find((resource) => resource.version === version);
3285
+ };
3286
+ const resolvePointer = async (pointer, candidateTypes) => {
3287
+ const explicitType = normalizeResourceType(pointer.type);
3288
+ if (pointer.type && !explicitType) return [];
3289
+ const types = explicitType ? [explicitType] : candidateTypes;
3290
+ const resolved = await Promise.all(
3291
+ types.map(async (type) => {
3292
+ const resource = await read(type, pointer);
3293
+ return resource && resource.hidden !== true ? { type, resource } : void 0;
3294
+ })
3295
+ );
3296
+ return resolved.filter((resource) => resource !== void 0);
3297
+ };
3298
+ const resolvePointers = async (pointers, candidateTypes) => {
3299
+ const resolved = await Promise.all(pointers.map((pointer) => resolvePointer(pointer, candidateTypes)));
3300
+ return resolved.flat();
3301
+ };
3302
+ let adrTargetIndex;
3303
+ const loadAdrTargetIndex = () => {
3304
+ if (adrTargetIndex) return adrTargetIndex;
3305
+ adrTargetIndex = loadAllVersionsIndex("adr").then((adrIndex) => {
3306
+ const targets = /* @__PURE__ */ new Map();
3307
+ for (const adr of adrIndex.byVersion.values()) {
3308
+ if (adr.hidden === true) continue;
3309
+ for (const pointer of adr.appliesTo || []) {
3310
+ const type = normalizeResourceType(pointer.type);
3311
+ if (!type || type === "adr") continue;
3312
+ const key = `${type}:${pointer.id}`;
3313
+ const entries = targets.get(key);
3314
+ const target = { pointer, resource: adr };
3315
+ if (entries) entries.push(target);
3316
+ else targets.set(key, [target]);
3317
+ }
3318
+ }
3319
+ return targets;
3320
+ });
3321
+ return adrTargetIndex;
3322
+ };
3323
+ const pointerMatchesVersion = (pointer, version) => {
3324
+ if (!pointer.version || pointer.version === "latest") return true;
3325
+ if (pointer.version === version) return true;
3326
+ const range = (0, import_semver6.validRange)(pointer.version);
3327
+ return range ? (0, import_semver6.maxSatisfying)([version], range) === version : false;
3328
+ };
3329
+ const getAdrsForResource = async (type, resource) => {
3330
+ if (type === "adr") return [];
3331
+ const targets = (await loadAdrTargetIndex()).get(`${type}:${resource.id}`) || [];
3332
+ return targets.filter(({ pointer }) => pointerMatchesVersion(pointer, resource.version)).map(({ resource: resource2 }) => ({ type: "adr", resource: resource2 }));
3333
+ };
3334
+ const resolveChildren = async (type, resource) => {
3335
+ const children = [];
3336
+ const addPointers = async (pointers, candidateTypes) => {
3337
+ children.push(...await resolvePointers(pointers, candidateTypes));
3338
+ };
3339
+ if (type === "domain") {
3340
+ await addPointers(resource.domains || [], ["domain"]);
3341
+ await addPointers(resource.systems || [], ["system"]);
3342
+ await addPointers(resource.services || [], ["service"]);
3343
+ await addPointers(resource.agents || [], ["agent"]);
3344
+ await addPointers(resource.entities || [], ["entity"]);
3345
+ await addPointers(resource.flows || [], ["flow"]);
3346
+ await addPointers([...resource.dataProducts || [], ...resource["data-products"] || []], ["data-product"]);
3347
+ await addPointers([...resource.sends || [], ...resource.receives || []], ["event", "command", "query"]);
3348
+ } else if (type === "system") {
3349
+ await addPointers(resource.relationships || [], ["system"]);
3350
+ await addPointers(resource.services || [], ["service"]);
3351
+ await addPointers(resource.flows || [], ["flow"]);
3352
+ await addPointers(resource.entities || [], ["entity"]);
3353
+ await addPointers(resource.containers || [], ["container"]);
3354
+ } else if (type === "service" || type === "agent") {
3355
+ await addPointers([...resource.sends || [], ...resource.receives || []], ["event", "command", "query"]);
3356
+ await addPointers(resource.entities || [], ["entity"]);
3357
+ await addPointers(resource.flows || [], ["flow"]);
3358
+ await addPointers([...resource.writesTo || [], ...resource.readsFrom || []], ["container"]);
3359
+ } else if (type === "event" || type === "command" || type === "query") {
3360
+ await addPointers([...resource.channels || [], ...resource.messageChannels || []], ["channel"]);
3361
+ } else if (type === "channel") {
3362
+ await addPointers(resource.routes || [], ["channel"]);
3363
+ } else if (type === "data-product") {
3364
+ await addPointers(
3365
+ [...resource.inputs || [], ...resource.outputs || []],
3366
+ ["event", "command", "query", "channel", "container", "service"]
3367
+ );
3368
+ } else if (type === "flow") {
3369
+ for (const step of resource.steps || []) {
3370
+ if (step.message) await addPointers([step.message], ["event", "command", "query"]);
3371
+ if (step.agent) await addPointers([step.agent], ["agent"]);
3372
+ if (step.service) await addPointers([step.service], ["service"]);
3373
+ if (step.flow) await addPointers([step.flow], ["flow"]);
3374
+ if (step.container) await addPointers([step.container], ["container"]);
3375
+ if (step.dataProduct) await addPointers([step.dataProduct], ["data-product"]);
3376
+ }
3377
+ } else if (type === "adr") {
3378
+ await addPointers(resource.appliesTo || [], NON_ADR_RESOURCE_TYPES);
3379
+ await addPointers(
3380
+ [
3381
+ ...resource.supersedes || [],
3382
+ ...resource.supersededBy || [],
3383
+ ...resource.amends || [],
3384
+ ...resource.amendedBy || [],
3385
+ ...resource.related || []
3386
+ ],
3387
+ ["adr"]
3388
+ );
3389
+ }
3390
+ children.push(...await getAdrsForResource(type, resource));
3391
+ const uniqueChildren = /* @__PURE__ */ new Map();
3392
+ for (const child of children) {
3393
+ const graphResource = toGraphResource(child.type, child.resource);
3394
+ uniqueChildren.set(resourceKey(graphResource), child);
3395
+ }
3396
+ return Array.from(uniqueChildren.values()).sort(
3397
+ (left, right) => sortResources(toGraphResource(left.type, left.resource), toGraphResource(right.type, right.resource))
3398
+ );
3399
+ };
3400
+ const getChildren = (type, resource) => {
3401
+ const key = resourceKey(toGraphResource(type, resource));
3402
+ const cachedChildren = adjacencyCache.get(key);
3403
+ if (cachedChildren) return cachedChildren;
3404
+ const children = resolveChildren(type, resource);
3405
+ adjacencyCache.set(key, children);
3406
+ return children;
3407
+ };
3408
+ const buildNode = async (type, resource, remainingDepth, ancestors) => {
3409
+ const graphResource = toGraphResource(type, resource);
3410
+ const key = resourceKey(graphResource);
3411
+ if (remainingDepth === 0) return { ...graphResource, children: [] };
3412
+ const nextAncestors = { key, parent: ancestors };
3413
+ const resolvedChildren = await getChildren(type, resource);
3414
+ const children = await mapWithConcurrency(
3415
+ resolvedChildren,
3416
+ NESTED_TRAVERSAL_CONCURRENCY,
3417
+ ({ type: childType, resource: childResource }) => {
3418
+ const child = toGraphResource(childType, childResource);
3419
+ if (pathIncludes(nextAncestors, resourceKey(child))) return Promise.resolve({ ...child, children: [] });
3420
+ return buildNode(childType, childResource, remainingDepth - 1, nextAncestors);
3421
+ }
3422
+ );
3423
+ return { ...graphResource, children };
3424
+ };
3425
+ const rootResource = await read(root.type, root);
3426
+ if (!rootResource || rootResource.hidden === true) return void 0;
3427
+ const flatRoot = toGraphResource(root.type, rootResource);
3428
+ if (!options.flat) {
3429
+ const nestedRoot = await buildNode(root.type, rootResource, depth);
3430
+ return { root: nestedRoot };
3431
+ }
3432
+ const flatRootKey = resourceKey(flatRoot);
3433
+ const resources = /* @__PURE__ */ new Map([[flatRootKey, flatRoot]]);
3434
+ const visited = /* @__PURE__ */ new Set([flatRootKey]);
3435
+ const queue = [
3436
+ { type: root.type, resource: rootResource, remainingDepth: depth }
3437
+ ];
3438
+ for (let index = 0; index < queue.length; index++) {
3439
+ const current = queue[index];
3440
+ if (current.remainingDepth === 0) continue;
3441
+ const children = await getChildren(current.type, current.resource);
3442
+ for (const child of children) {
3443
+ const graphResource = toGraphResource(child.type, child.resource);
3444
+ const key = resourceKey(graphResource);
3445
+ if (visited.has(key)) continue;
3446
+ visited.add(key);
3447
+ resources.set(key, graphResource);
3448
+ queue.push({ ...child, remainingDepth: current.remainingDepth - 1 });
3449
+ }
3450
+ }
3451
+ const relatedResources = Array.from(resources.values()).filter((resource) => resourceKey(resource) !== flatRootKey).sort(sortResources);
3452
+ return {
3453
+ root: flatRoot,
3454
+ resources: [flatRoot, ...relatedResources]
3455
+ };
3456
+ };
3457
+ return graph;
3458
+ };
3459
+
3460
+ // src/snapshots.ts
3461
+ var import_node_fs9 = __toESM(require("fs"));
3462
+ var import_node_path24 = __toESM(require("path"));
3463
+ var import_node_crypto = require("crypto");
3464
+ var import_node_child_process = require("child_process");
3465
+ var import_semver7 = require("semver");
3466
+
3467
+ // src/snapshot-diff.ts
3468
+ var stableStringify = (value) => {
3469
+ if (value === null || value === void 0 || typeof value !== "object") {
3470
+ return JSON.stringify(value);
3471
+ }
3472
+ if (Array.isArray(value)) {
3473
+ return "[" + value.map(stableStringify).join(",") + "]";
3474
+ }
3475
+ const sorted = Object.keys(value).sort().map((key) => JSON.stringify(key) + ":" + stableStringify(value[key]));
3476
+ return "{" + sorted.join(",") + "}";
3477
+ };
3478
+ var flattenResources = (snapshot) => {
3479
+ const resources = [];
3480
+ const addResources = (items, type) => {
3481
+ for (const item of items) {
3482
+ resources.push({
3483
+ resourceId: item.id,
3484
+ version: item.version,
3485
+ type,
3486
+ data: item
3487
+ });
3488
+ }
3489
+ };
3490
+ addResources(snapshot.resources.domains, "domain");
3491
+ addResources(snapshot.resources.services, "service");
3492
+ addResources(snapshot.resources.agents || [], "agent");
3493
+ addResources(snapshot.resources.messages.events, "event");
3494
+ addResources(snapshot.resources.messages.commands, "command");
3495
+ addResources(snapshot.resources.messages.queries, "query");
3496
+ addResources(snapshot.resources.channels, "channel");
3497
+ return resources;
3498
+ };
3499
+ var EXCLUDED_FIELDS = /* @__PURE__ */ new Set(["markdown", "_eventcatalog"]);
3500
+ var getComparableFields = (data) => {
3501
+ const result = {};
3502
+ for (const [key, value] of Object.entries(data)) {
3503
+ if (!EXCLUDED_FIELDS.has(key)) {
3504
+ result[key] = value;
3505
+ }
3506
+ }
3507
+ return result;
3508
+ };
3509
+ var findChangedFields = (dataA, dataB) => {
3510
+ const fieldsA = getComparableFields(dataA);
3511
+ const fieldsB = getComparableFields(dataB);
3512
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(fieldsA), ...Object.keys(fieldsB)]);
3513
+ const changed = [];
3514
+ for (const key of allKeys) {
3515
+ if (stableStringify(fieldsA[key] ?? null) !== stableStringify(fieldsB[key] ?? null)) {
3516
+ changed.push(key);
3517
+ }
3518
+ }
3519
+ return changed;
3520
+ };
3521
+ var resourceKey2 = (r) => `${r.resourceId}@${r.version}`;
3522
+ var idTypeKey = (r) => `${r.resourceId}:${r.type}`;
3523
+ var computeResourceDiff = (snapshotA, snapshotB) => {
3524
+ const resourcesA = flattenResources(snapshotA);
3525
+ const resourcesB = flattenResources(snapshotB);
3526
+ const mapA = /* @__PURE__ */ new Map();
3527
+ const byIdA = /* @__PURE__ */ new Map();
3528
+ for (const r of resourcesA) {
3529
+ mapA.set(resourceKey2(r), r);
3530
+ byIdA.set(idTypeKey(r), r);
3531
+ }
3532
+ const mapB = /* @__PURE__ */ new Map();
3533
+ const byIdB = /* @__PURE__ */ new Map();
3534
+ for (const r of resourcesB) {
3535
+ mapB.set(resourceKey2(r), r);
3536
+ byIdB.set(idTypeKey(r), r);
3537
+ }
3538
+ const changes = [];
3539
+ const handledIds = /* @__PURE__ */ new Set();
3540
+ for (const resource of resourcesB) {
3541
+ const key = resourceKey2(resource);
3542
+ if (!mapA.has(key)) {
3543
+ const idKey = idTypeKey(resource);
3544
+ const oldResource = byIdA.get(idKey);
3545
+ if (oldResource && oldResource.version !== resource.version && !handledIds.has(idKey)) {
3546
+ const changedFields = findChangedFields(oldResource.data, resource.data);
3547
+ changes.push({
3548
+ resourceId: resource.resourceId,
3549
+ version: resource.version,
3550
+ type: resource.type,
3551
+ changeType: "versioned",
3552
+ previousVersion: oldResource.version,
3553
+ newVersion: resource.version,
3554
+ changedFields: changedFields.length > 0 ? changedFields : void 0
3555
+ });
3556
+ handledIds.add(idKey);
3557
+ } else if (!handledIds.has(idKey)) {
3558
+ changes.push({
3559
+ resourceId: resource.resourceId,
3560
+ version: resource.version,
3561
+ type: resource.type,
3562
+ changeType: "added"
3563
+ });
3564
+ }
3565
+ }
3566
+ }
3567
+ for (const resource of resourcesA) {
3568
+ const key = resourceKey2(resource);
3569
+ if (!mapB.has(key)) {
3570
+ const idKey = idTypeKey(resource);
3571
+ if (!handledIds.has(idKey)) {
3572
+ changes.push({
3573
+ resourceId: resource.resourceId,
3574
+ version: resource.version,
3575
+ type: resource.type,
3576
+ changeType: "removed"
3577
+ });
3578
+ }
3579
+ }
3580
+ }
3581
+ for (const resourceB of resourcesB) {
3582
+ const key = resourceKey2(resourceB);
3583
+ const resourceA = mapA.get(key);
3584
+ if (resourceA) {
3585
+ const changedFields = findChangedFields(resourceA.data, resourceB.data);
3586
+ if (changedFields.length > 0) {
3587
+ changes.push({
3588
+ resourceId: resourceB.resourceId,
3589
+ version: resourceB.version,
3590
+ type: resourceB.type,
3591
+ changeType: "modified",
3592
+ changedFields
3593
+ });
3594
+ }
3595
+ }
3596
+ }
3597
+ return changes;
3598
+ };
3599
+ var getRelationshipKey = (serviceId, resourceId, resourceVersion, direction) => {
3600
+ return `${serviceId}:${direction}:${resourceId}@${resourceVersion || "latest"}`;
3601
+ };
3602
+ var extractRelationships = (snapshot) => {
3603
+ const relationships = /* @__PURE__ */ new Map();
3604
+ for (const service of [...snapshot.resources.services, ...snapshot.resources.agents || []]) {
3605
+ for (const direction of ["sends", "receives"]) {
3606
+ const pointers = service[direction] || [];
3607
+ for (const pointer of pointers) {
3608
+ const key = getRelationshipKey(service.id, pointer.id, pointer.version, direction);
3609
+ relationships.set(key, {
3610
+ serviceId: service.id,
3611
+ serviceVersion: service.version,
3612
+ resourceId: pointer.id,
3613
+ resourceVersion: pointer.version,
3614
+ direction
3615
+ });
3616
+ }
3617
+ }
3618
+ }
3619
+ return relationships;
3620
+ };
3621
+ var computeRelationshipDiff = (snapshotA, snapshotB) => {
3622
+ const relsA = extractRelationships(snapshotA);
3623
+ const relsB = extractRelationships(snapshotB);
3624
+ const changes = [];
3625
+ for (const [key, rel] of relsB) {
3626
+ if (!relsA.has(key)) {
3627
+ changes.push({ ...rel, changeType: "added" });
3628
+ }
3629
+ }
3630
+ for (const [key, rel] of relsA) {
3631
+ if (!relsB.has(key)) {
3632
+ changes.push({ ...rel, changeType: "removed" });
3633
+ }
3634
+ }
3635
+ return changes;
3636
+ };
3637
+
3638
+ // src/snapshots.ts
3639
+ var SNAPSHOT_VERSION = "1.0.0";
3640
+ var getEventCatalogVersion2 = (catalogDir) => {
3641
+ try {
3642
+ const packageJson = import_node_fs9.default.readFileSync(import_node_path24.default.join(catalogDir, "package.json"), "utf8");
3643
+ const packageJsonObject = JSON.parse(packageJson);
3644
+ return packageJsonObject["dependencies"]?.["@eventcatalog/core"] ?? "unknown";
3645
+ } catch {
3646
+ return "unknown";
3647
+ }
3648
+ };
3649
+ var pickCoreFields = (resource) => {
3650
+ const picked = { id: resource.id, version: resource.version, name: resource.name };
3651
+ if (resource.sends) picked.sends = resource.sends;
3652
+ if (resource.receives) picked.receives = resource.receives;
3653
+ if (resource.deprecated) picked.deprecated = resource.deprecated;
3654
+ if (resource.owners) picked.owners = resource.owners;
3655
+ if (resource.schemaPath) picked.schemaPath = resource.schemaPath;
3656
+ if (resource.schemaHash) picked.schemaHash = resource.schemaHash;
3657
+ return picked;
3658
+ };
3659
+ var deduplicateByLatestVersion = (resources) => {
3660
+ const seen = /* @__PURE__ */ new Map();
3661
+ for (const r of resources) {
3662
+ const existing = seen.get(r.id);
3663
+ if (!existing || (0, import_semver7.compare)(r.version, existing.version) > 0) {
3664
+ seen.set(r.id, r);
3665
+ }
3666
+ }
3667
+ return Array.from(seen.values());
3668
+ };
3669
+ var stripToCore = (resources) => {
3670
+ if (!resources || resources.length === 0) return [];
3671
+ return deduplicateByLatestVersion(resources).map(pickCoreFields);
3672
+ };
3673
+ var detectGitInfo = (catalogDir) => {
3674
+ try {
3675
+ const opts = { cwd: catalogDir, encoding: "utf8", stdio: "pipe" };
3676
+ const branch = (0, import_node_child_process.execSync)("git rev-parse --abbrev-ref HEAD", opts).trim();
3677
+ const commit = (0, import_node_child_process.execSync)("git rev-parse --short HEAD", opts).trim();
3678
+ const status = (0, import_node_child_process.execSync)("git status --porcelain", opts).trim();
3679
+ return { branch, commit, dirty: status.length > 0 };
3680
+ } catch {
3681
+ return void 0;
3682
+ }
3683
+ };
3684
+ var enrichWithSchemaHashes = async (getSchemaForMessage2, resources) => {
3685
+ await Promise.all(
3686
+ resources.map(async (resource) => {
3687
+ if (!resource.schemaPath) return;
3688
+ const schema = await getSchemaForMessage2(resource.id, resource.version);
3689
+ if (!schema) return;
3690
+ resource.schemaHash = (0, import_node_crypto.createHash)("sha256").update(schema.schema).digest("hex");
3691
+ })
3692
+ );
3693
+ };
3694
+ var createSnapshot = (directory) => {
3695
+ return async (options) => {
3696
+ const { label, outputDir, git } = options || {};
3697
+ const sdk = src_default(directory);
3698
+ const [domains, services, agents, events, commands, queries, channels] = await Promise.all([
3699
+ sdk.getDomains(),
3700
+ sdk.getServices(),
3701
+ sdk.getAgents(),
3702
+ sdk.getEvents(),
3703
+ sdk.getCommands(),
3704
+ sdk.getQueries(),
3705
+ sdk.getChannels()
3706
+ ]);
3707
+ await Promise.all([
3708
+ enrichWithSchemaHashes(sdk.getSchemaForMessage, events || []),
3709
+ enrichWithSchemaHashes(sdk.getSchemaForMessage, commands || []),
3710
+ enrichWithSchemaHashes(sdk.getSchemaForMessage, queries || [])
3711
+ ]);
3712
+ const snapshotDomains = stripToCore(domains);
3713
+ const snapshotServices = stripToCore(services);
3714
+ const snapshotAgents = stripToCore(agents);
3715
+ const snapshotEvents = stripToCore(events);
3716
+ const snapshotCommands = stripToCore(commands);
3717
+ const snapshotQueries = stripToCore(queries);
3718
+ const snapshotChannels = stripToCore(channels);
3719
+ const snapshotLabel = label || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3720
+ const gitInfo = git || detectGitInfo(directory);
3721
+ const snapshot = {
3722
+ snapshotVersion: SNAPSHOT_VERSION,
3723
+ catalogVersion: getEventCatalogVersion2(directory),
3724
+ label: snapshotLabel,
3725
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3726
+ ...gitInfo ? { git: gitInfo } : {},
3727
+ resources: {
3728
+ domains: snapshotDomains,
3729
+ services: snapshotServices,
3730
+ agents: snapshotAgents,
3731
+ messages: {
3732
+ events: snapshotEvents,
3733
+ commands: snapshotCommands,
3734
+ queries: snapshotQueries
3735
+ },
3736
+ channels: snapshotChannels
3737
+ }
3738
+ };
3739
+ const snapshotsDir = outputDir || import_node_path24.default.join(directory, ".snapshots");
3740
+ import_node_fs9.default.mkdirSync(snapshotsDir, { recursive: true });
3741
+ const fileName = `${snapshotLabel}.snapshot.json`;
3742
+ const filePath = import_node_path24.default.join(snapshotsDir, fileName);
3743
+ import_node_fs9.default.writeFileSync(filePath, JSON.stringify(snapshot));
3744
+ return { filePath, snapshot };
3745
+ };
3407
3746
  };
3408
- var writeFlowToService = (directory) => async (flow, service, options = { path: "", format: "mdx", override: false }) => {
3409
- let pathForFlow = service.version && service.version !== "latest" ? `/${service.id}/versioned/${service.version}/flows` : `/${service.id}/flows`;
3410
- pathForFlow = (0, import_node_path22.join)(pathForFlow, flow.id);
3411
- await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3747
+ var diffSnapshots = (directory) => async (snapshotAPath, snapshotBPath) => {
3748
+ const snapshotA = JSON.parse(import_node_fs9.default.readFileSync(snapshotAPath, "utf-8"));
3749
+ const snapshotB = JSON.parse(import_node_fs9.default.readFileSync(snapshotBPath, "utf-8"));
3750
+ const resourceChanges = computeResourceDiff(snapshotA, snapshotB);
3751
+ const relationshipChanges = computeRelationshipDiff(snapshotA, snapshotB);
3752
+ const resourceCounts = { added: 0, removed: 0, modified: 0, versioned: 0 };
3753
+ for (const r of resourceChanges) resourceCounts[r.changeType]++;
3754
+ const relCounts = { added: 0, removed: 0 };
3755
+ for (const r of relationshipChanges) relCounts[r.changeType]++;
3756
+ return {
3757
+ snapshotA: { label: snapshotA.label, createdAt: snapshotA.createdAt },
3758
+ snapshotB: { label: snapshotB.label, createdAt: snapshotB.createdAt },
3759
+ summary: {
3760
+ totalChanges: resourceChanges.length + relationshipChanges.length,
3761
+ resourcesAdded: resourceCounts.added,
3762
+ resourcesRemoved: resourceCounts.removed,
3763
+ resourcesModified: resourceCounts.modified,
3764
+ resourcesVersioned: resourceCounts.versioned,
3765
+ relationshipsAdded: relCounts.added,
3766
+ relationshipsRemoved: relCounts.removed
3767
+ },
3768
+ resources: resourceChanges,
3769
+ relationships: relationshipChanges
3770
+ };
3412
3771
  };
3413
- var writeFlowToSystem = (directory) => async (flow, system, options = { path: "", format: "mdx", override: false }) => {
3414
- const resourcePath = await getResourcePath(directory, system.id, system.version);
3415
- if (!resourcePath) {
3416
- throw new Error("System not found");
3772
+ var listSnapshots = (directory) => async () => {
3773
+ const snapshotsDir = import_node_path24.default.join(directory, ".snapshots");
3774
+ if (!import_node_fs9.default.existsSync(snapshotsDir)) return [];
3775
+ const files = import_node_fs9.default.readdirSync(snapshotsDir).filter((f) => f.endsWith(".snapshot.json"));
3776
+ const snapshots = [];
3777
+ for (const file of files) {
3778
+ try {
3779
+ const filePath = import_node_path24.default.join(snapshotsDir, file);
3780
+ const content = JSON.parse(import_node_fs9.default.readFileSync(filePath, "utf-8"));
3781
+ snapshots.push({
3782
+ label: content.label,
3783
+ createdAt: content.createdAt,
3784
+ filePath,
3785
+ ...content.git ? { git: content.git } : {}
3786
+ });
3787
+ } catch {
3788
+ }
3417
3789
  }
3418
- const pathForFlow = (0, import_node_path22.join)(resourcePath.directory, "flows", flow.id);
3419
- await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3420
- };
3421
- var writeFlowToAgent = (directory) => async (flow, agent, options = { path: "", format: "mdx", override: false }) => {
3422
- let pathForFlow = agent.version && agent.version !== "latest" ? `/${agent.id}/versioned/${agent.version}/flows` : `/${agent.id}/flows`;
3423
- pathForFlow = (0, import_node_path22.join)(pathForFlow, flow.id);
3424
- await writeResource(directory, { ...flow }, { ...options, path: pathForFlow, type: "flow" });
3425
- };
3426
- var rmFlow = (directory) => async (path9) => {
3427
- await import_promises14.default.rm((0, import_node_path22.join)(directory, path9), { recursive: true });
3428
- invalidateFileCache();
3429
- };
3430
- var rmFlowById = (directory) => async (id, version, persistFiles) => {
3431
- await rmResourceById(directory, id, version, { type: "flow", persistFiles });
3432
- };
3433
- var versionFlow = (directory) => async (id) => versionResource(directory, id);
3434
- var flowHasVersion = (directory) => async (id, version) => {
3435
- const file = await findFileById(directory, id, version);
3436
- return !!file;
3790
+ return snapshots.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
3437
3791
  };
3438
- var addFileToFlow = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version, { type: "flow" });
3439
3792
 
3440
- // src/containers.ts
3441
- var import_promises15 = __toESM(require("fs/promises"));
3442
- var import_node_path23 = require("path");
3443
- var getContainer = (directory) => async (id, version) => getResource(directory, id, version, { type: "container" });
3444
- var getContainers = (directory) => async (options) => getResources(directory, { type: "containers", latestOnly: options?.latestOnly });
3445
- var writeContainer = (directory) => async (data, options = {
3446
- path: "",
3447
- override: false,
3448
- format: "mdx"
3449
- }) => writeResource(directory, { ...data }, { ...options, type: "container" });
3450
- var versionContainer = (directory) => async (id) => versionResource(directory, id);
3451
- var rmContainer = (directory) => async (path9) => {
3452
- await import_promises15.default.rm((0, import_node_path23.join)(directory, path9), { recursive: true });
3793
+ // src/changelogs.ts
3794
+ var import_node_path25 = __toESM(require("path"));
3795
+ var import_node_fs10 = __toESM(require("fs"));
3796
+ var import_promises17 = __toESM(require("fs/promises"));
3797
+ var import_gray_matter8 = __toESM(require("gray-matter"));
3798
+ var writeChangelog = (catalogDir) => async (id, changelog, options = {}) => {
3799
+ const { version, format = "mdx" } = options;
3800
+ const resourceFile = await findFileById(catalogDir, id, version);
3801
+ if (!resourceFile) {
3802
+ throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
3803
+ }
3804
+ const resourceDir = (0, import_node_path25.dirname)(resourceFile);
3805
+ const changelogPath = import_node_path25.default.join(resourceDir, `changelog.${format}`);
3806
+ const { markdown, ...frontmatter } = changelog;
3807
+ const fm = { ...frontmatter };
3808
+ if (fm.createdAt instanceof Date) {
3809
+ fm.createdAt = fm.createdAt;
3810
+ }
3811
+ if (!fm.badges || fm.badges.length === 0) {
3812
+ delete fm.badges;
3813
+ }
3814
+ import_node_fs10.default.mkdirSync(resourceDir, { recursive: true });
3815
+ const document = import_gray_matter8.default.stringify(markdown.trim(), fm);
3816
+ import_node_fs10.default.writeFileSync(changelogPath, document);
3453
3817
  invalidateFileCache();
3454
3818
  };
3455
- var rmContainerById = (directory) => async (id, version, persistFiles) => {
3456
- await rmResourceById(directory, id, version, { type: "container", persistFiles });
3457
- };
3458
- var containerHasVersion = (directory) => async (id, version) => {
3459
- const file = await findFileById(directory, id, version);
3460
- return !!file;
3461
- };
3462
- var addFileToContainer = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version);
3463
- var writeContainerToService = (directory) => async (container, service, options = { path: "", format: "mdx", override: false }) => {
3464
- const resourcePath = await getResourcePath(directory, service.id, service.version);
3465
- if (!resourcePath) {
3466
- throw new Error("Service not found");
3819
+ var appendChangelog = (catalogDir) => async (id, changelog, options = {}) => {
3820
+ const { version, format = "mdx" } = options;
3821
+ const resourceFile = await findFileById(catalogDir, id, version);
3822
+ if (!resourceFile) {
3823
+ throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
3467
3824
  }
3468
- let pathForContainer = service.version && service.version !== "latest" ? `${resourcePath.directory}/versioned/${service.version}/containers` : `${resourcePath.directory}/containers`;
3469
- pathForContainer = (0, import_node_path23.join)(pathForContainer, container.id);
3470
- await writeResource(directory, { ...container }, { ...options, path: pathForContainer, type: "container" });
3471
- };
3472
- var writeContainerToSystem = (directory) => async (container, system, options = { path: "", format: "mdx", override: false }) => {
3473
- const resourcePath = await getResourcePath(directory, system.id, system.version);
3474
- if (!resourcePath) {
3475
- throw new Error("System not found");
3825
+ const resourceDir = (0, import_node_path25.dirname)(resourceFile);
3826
+ const mdxPath = import_node_path25.default.join(resourceDir, "changelog.mdx");
3827
+ const mdPath = import_node_path25.default.join(resourceDir, "changelog.md");
3828
+ const existingPath = import_node_fs10.default.existsSync(mdxPath) ? mdxPath : import_node_fs10.default.existsSync(mdPath) ? mdPath : void 0;
3829
+ if (!existingPath) {
3830
+ return writeChangelog(catalogDir)(id, changelog, options);
3476
3831
  }
3477
- const pathForContainer = (0, import_node_path23.join)(resourcePath.directory, "containers", container.id);
3478
- await writeResource(directory, { ...container }, { ...options, path: pathForContainer, type: "container" });
3479
- };
3832
+ const existing = import_gray_matter8.default.read(existingPath);
3833
+ const existingContent = existing.content.trim();
3834
+ const newEntry = changelog.markdown.trim();
3835
+ const combined = `${newEntry}
3480
3836
 
3481
- // src/data-stores.ts
3482
- var getDataStore = getContainer;
3483
- var getDataStores = getContainers;
3484
- var writeDataStore = writeContainer;
3485
- var versionDataStore = versionContainer;
3486
- var rmDataStore = rmContainer;
3487
- var rmDataStoreById = rmContainerById;
3488
- var dataStoreHasVersion = containerHasVersion;
3489
- var addFileToDataStore = addFileToContainer;
3490
- var writeDataStoreToService = writeContainerToService;
3491
- var writeDataStoreToSystem = writeContainerToSystem;
3837
+ ---
3492
3838
 
3493
- // src/data-products.ts
3494
- var import_promises16 = __toESM(require("fs/promises"));
3495
- var import_node_path24 = require("path");
3496
- var getDataProduct = (directory) => async (id, version) => getResource(directory, id, version, { type: "data-product" });
3497
- var getDataProducts = (directory) => async (options) => getResources(directory, { type: "data-products", latestOnly: options?.latestOnly });
3498
- var writeDataProduct = (directory) => async (dataProduct, options = {
3499
- path: "",
3500
- override: false,
3501
- format: "mdx"
3502
- }) => writeResource(directory, { ...dataProduct }, { ...options, type: "data-product" });
3503
- var writeDataProductToDomain = (directory) => async (dataProduct, domain, options = { path: "", format: "mdx", override: false }) => {
3504
- let pathForDataProduct = domain.version && domain.version !== "latest" ? `/${domain.id}/versioned/${domain.version}/data-products` : `/${domain.id}/data-products`;
3505
- pathForDataProduct = (0, import_node_path24.join)(pathForDataProduct, dataProduct.id);
3506
- await writeResource(directory, { ...dataProduct }, { ...options, path: pathForDataProduct, type: "data-product" });
3507
- };
3508
- var rmDataProduct = (directory) => async (path9) => {
3509
- await import_promises16.default.rm((0, import_node_path24.join)(directory, path9), { recursive: true });
3839
+ ${existingContent}`;
3840
+ const fm = { ...existing.data };
3841
+ fm.createdAt = changelog.createdAt;
3842
+ if (changelog.badges && changelog.badges.length > 0) {
3843
+ fm.badges = changelog.badges;
3844
+ } else {
3845
+ delete fm.badges;
3846
+ }
3847
+ const document = import_gray_matter8.default.stringify(combined, fm);
3848
+ import_node_fs10.default.writeFileSync(existingPath, document);
3510
3849
  invalidateFileCache();
3511
3850
  };
3512
- var rmDataProductById = (directory) => async (id, version, persistFiles) => {
3513
- await rmResourceById(directory, id, version, { type: "data-product", persistFiles });
3851
+ var getChangelog = (catalogDir) => async (id, options = {}) => {
3852
+ const { version } = options;
3853
+ const resourceFile = await findFileById(catalogDir, id, version);
3854
+ if (!resourceFile) return void 0;
3855
+ const resourceDir = (0, import_node_path25.dirname)(resourceFile);
3856
+ const mdxPath = import_node_path25.default.join(resourceDir, "changelog.mdx");
3857
+ const mdPath = import_node_path25.default.join(resourceDir, "changelog.md");
3858
+ const changelogPath = import_node_fs10.default.existsSync(mdxPath) ? mdxPath : import_node_fs10.default.existsSync(mdPath) ? mdPath : void 0;
3859
+ if (!changelogPath) return void 0;
3860
+ const { data, content } = import_gray_matter8.default.read(changelogPath);
3861
+ return { ...data, markdown: content.trim() };
3514
3862
  };
3515
- var versionDataProduct = (directory) => async (id) => versionResource(directory, id);
3516
- var dataProductHasVersion = (directory) => async (id, version) => {
3517
- const file = await findFileById(directory, id, version);
3518
- return !!file;
3863
+ var rmChangelog = (catalogDir) => async (id, options = {}) => {
3864
+ const { version } = options;
3865
+ const resourceFile = await findFileById(catalogDir, id, version);
3866
+ if (!resourceFile) {
3867
+ throw new Error(`No resource found with id: ${id}${version ? ` and version: ${version}` : ""}`);
3868
+ }
3869
+ const resourceDir = (0, import_node_path25.dirname)(resourceFile);
3870
+ const mdxPath = import_node_path25.default.join(resourceDir, "changelog.mdx");
3871
+ const mdPath = import_node_path25.default.join(resourceDir, "changelog.md");
3872
+ if (import_node_fs10.default.existsSync(mdxPath)) {
3873
+ await import_promises17.default.rm(mdxPath);
3874
+ }
3875
+ if (import_node_fs10.default.existsSync(mdPath)) {
3876
+ await import_promises17.default.rm(mdPath);
3877
+ }
3878
+ invalidateFileCache();
3519
3879
  };
3520
- var addFileToDataProduct = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version);
3521
3880
 
3522
3881
  // src/diagrams.ts
3523
- var import_promises17 = __toESM(require("fs/promises"));
3524
- var import_node_path25 = require("path");
3882
+ var import_promises18 = __toESM(require("fs/promises"));
3883
+ var import_node_path26 = require("path");
3525
3884
  var getDiagram = (directory) => async (id, version) => getResource(directory, id, version, { type: "diagram" });
3526
3885
  var getDiagrams = (directory) => async (options) => getResources(directory, { type: "diagrams", latestOnly: options?.latestOnly });
3527
3886
  var writeDiagram = (directory) => async (diagram, options = {
@@ -3530,7 +3889,7 @@ var writeDiagram = (directory) => async (diagram, options = {
3530
3889
  format: "mdx"
3531
3890
  }) => writeResource(directory, { ...diagram }, { ...options, type: "diagram" });
3532
3891
  var rmDiagram = (directory) => async (path9) => {
3533
- await import_promises17.default.rm((0, import_node_path25.join)(directory, path9), { recursive: true });
3892
+ await import_promises18.default.rm((0, import_node_path26.join)(directory, path9), { recursive: true });
3534
3893
  invalidateFileCache();
3535
3894
  };
3536
3895
  var rmDiagramById = (directory) => async (id, version, persistFiles) => {
@@ -3543,30 +3902,6 @@ var diagramHasVersion = (directory) => async (id, version) => {
3543
3902
  };
3544
3903
  var addFileToDiagram = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version, { type: "diagram" });
3545
3904
 
3546
- // src/adrs.ts
3547
- var import_promises18 = __toESM(require("fs/promises"));
3548
- var import_node_path26 = require("path");
3549
- var getAdr = (directory) => async (id, version) => getResource(directory, id, version, { type: "adr" });
3550
- var getAdrs = (directory) => async (options) => getResources(directory, { type: "adrs", latestOnly: options?.latestOnly });
3551
- var writeAdr = (directory) => async (adr, options = {
3552
- path: "",
3553
- override: false,
3554
- format: "mdx"
3555
- }) => writeResource(directory, { ...adr }, { ...options, type: "adr" });
3556
- var rmAdr = (directory) => async (path9) => {
3557
- await import_promises18.default.rm((0, import_node_path26.join)(directory, path9), { recursive: true });
3558
- invalidateFileCache();
3559
- };
3560
- var rmAdrById = (directory) => async (id, version, persistFiles) => {
3561
- await rmResourceById(directory, id, version, { type: "adr", persistFiles });
3562
- };
3563
- var versionAdr = (directory) => async (id) => versionResource(directory, id);
3564
- var adrHasVersion = (directory) => async (id, version) => {
3565
- const file = await findFileById(directory, id, version);
3566
- return !!file;
3567
- };
3568
- var addFileToAdr = (directory) => async (id, file, version) => addFileToResource(directory, id, file, version, { type: "adr" });
3569
-
3570
3905
  // src/index.ts
3571
3906
  var src_default = (path9) => {
3572
3907
  return {
@@ -4461,6 +4796,13 @@ var src_default = (path9) => {
4461
4796
  * @returns A JSON file with the catalog
4462
4797
  */
4463
4798
  dumpCatalog: dumpCatalog((0, import_node_path27.join)(path9)),
4799
+ /**
4800
+ * Returns the resources reachable from a catalog resource.
4801
+ * @param root - Resource to use as the root of the graph
4802
+ * @param options - Traversal depth and whether to return a flat resource list
4803
+ * @returns The resolved graph, or undefined when the root does not exist
4804
+ */
4805
+ getGraph: getGraph((0, import_node_path27.join)(path9)),
4464
4806
  /**
4465
4807
  * Returns the event catalog configuration file.
4466
4808
  * The event catalog configuration file is the file that contains the configuration for the event catalog.