@eventcatalog/sdk 2.26.0 → 2.26.2

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