@eventcatalog/sdk 2.3.6 → 2.4.0
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/channels.js +30 -4
- package/dist/channels.js.map +1 -1
- package/dist/channels.mjs +44 -12
- package/dist/channels.mjs.map +1 -1
- package/dist/commands.d.mts +10 -1
- package/dist/commands.d.ts +10 -1
- package/dist/commands.js +28 -2
- package/dist/commands.js.map +1 -1
- package/dist/commands.mjs +34 -8
- package/dist/commands.mjs.map +1 -1
- package/dist/custom-docs.js +15 -1
- package/dist/custom-docs.js.map +1 -1
- package/dist/custom-docs.mjs +26 -9
- package/dist/custom-docs.mjs.map +1 -1
- package/dist/domains.js +27 -1
- package/dist/domains.js.map +1 -1
- package/dist/domains.mjs +34 -8
- package/dist/domains.mjs.map +1 -1
- package/dist/eventcatalog.js +40 -5
- package/dist/eventcatalog.js.map +1 -1
- package/dist/eventcatalog.mjs +67 -32
- package/dist/eventcatalog.mjs.map +1 -1
- package/dist/events.d.mts +10 -1
- package/dist/events.d.ts +10 -1
- package/dist/events.js +28 -2
- package/dist/events.js.map +1 -1
- package/dist/events.mjs +34 -8
- package/dist/events.mjs.map +1 -1
- package/dist/index.d.mts +26 -9
- package/dist/index.d.ts +26 -9
- package/dist/index.js +40 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -32
- package/dist/index.mjs.map +1 -1
- package/dist/queries.d.mts +10 -1
- package/dist/queries.d.ts +10 -1
- package/dist/queries.js +28 -2
- package/dist/queries.js.map +1 -1
- package/dist/queries.mjs +34 -8
- package/dist/queries.mjs.map +1 -1
- package/dist/services.js +27 -1
- package/dist/services.js.map +1 -1
- package/dist/services.mjs +33 -7
- package/dist/services.mjs.map +1 -1
- package/dist/teams.mjs +7 -6
- package/dist/teams.mjs.map +1 -1
- package/dist/types.d.d.mts +3 -0
- package/dist/types.d.d.ts +3 -0
- package/dist/types.d.js.map +1 -1
- package/dist/users.mjs +7 -6
- package/dist/users.mjs.map +1 -1
- package/package.json +1 -1
package/dist/channels.js
CHANGED
|
@@ -211,9 +211,22 @@ var writeResource = async (catalogDir, resource, options = {
|
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
213
|
var getResource = async (catalogDir, id, version, options) => {
|
|
214
|
+
const attachSchema = options?.attachSchema || false;
|
|
214
215
|
const file = await findFileById(catalogDir, id, version);
|
|
215
216
|
if (!file) return;
|
|
216
217
|
const { data, content } = import_gray_matter2.default.read(file);
|
|
218
|
+
if (attachSchema && data?.schemaPath) {
|
|
219
|
+
const resourceDirectory = (0, import_path.dirname)(file);
|
|
220
|
+
const pathToSchema = (0, import_path.join)(resourceDirectory, data.schemaPath);
|
|
221
|
+
if (import_node_fs2.default.existsSync(pathToSchema)) {
|
|
222
|
+
const schema = import_node_fs2.default.readFileSync(pathToSchema, "utf8");
|
|
223
|
+
try {
|
|
224
|
+
data.schema = JSON.parse(schema);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
data.schema = schema;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
217
230
|
return {
|
|
218
231
|
...data,
|
|
219
232
|
markdown: content.trim()
|
|
@@ -232,7 +245,8 @@ var getResources = async (catalogDir, {
|
|
|
232
245
|
type,
|
|
233
246
|
latestOnly = false,
|
|
234
247
|
ignore = [],
|
|
235
|
-
pattern = ""
|
|
248
|
+
pattern = "",
|
|
249
|
+
attachSchema = false
|
|
236
250
|
}) => {
|
|
237
251
|
const ignoreList = latestOnly ? `**/versioned/**` : "";
|
|
238
252
|
const filePattern = pattern || `${catalogDir}/**/${type}/**/index.{md,mdx}`;
|
|
@@ -240,6 +254,18 @@ var getResources = async (catalogDir, {
|
|
|
240
254
|
if (files.length === 0) return;
|
|
241
255
|
return files.map((file) => {
|
|
242
256
|
const { data, content } = import_gray_matter2.default.read(file);
|
|
257
|
+
if (attachSchema && data?.schemaPath) {
|
|
258
|
+
const resourceDirectory = (0, import_path.dirname)(file);
|
|
259
|
+
const pathToSchema = (0, import_path.join)(resourceDirectory, data.schemaPath);
|
|
260
|
+
if (import_node_fs2.default.existsSync(pathToSchema)) {
|
|
261
|
+
const schema = import_node_fs2.default.readFileSync(pathToSchema, "utf8");
|
|
262
|
+
try {
|
|
263
|
+
data.schema = JSON.parse(schema);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
data.schema = schema;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
243
269
|
return {
|
|
244
270
|
...data,
|
|
245
271
|
markdown: content.trim()
|
|
@@ -274,7 +300,7 @@ var getVersionedDirectory = (sourceDirectory, version) => {
|
|
|
274
300
|
// src/events.ts
|
|
275
301
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
276
302
|
var import_node_path2 = require("path");
|
|
277
|
-
var getEvent = (directory) => async (id, version) => getResource(directory, id, version, { type: "event" });
|
|
303
|
+
var getEvent = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "event", ...options });
|
|
278
304
|
var writeEvent = (directory) => async (event, options = {
|
|
279
305
|
path: "",
|
|
280
306
|
override: false,
|
|
@@ -287,7 +313,7 @@ var rmEventById = (directory) => async (id, version, persistFiles) => {
|
|
|
287
313
|
// src/commands.ts
|
|
288
314
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
289
315
|
var import_node_path3 = require("path");
|
|
290
|
-
var getCommand = (directory) => async (id, version) => getResource(directory, id, version, { type: "command" });
|
|
316
|
+
var getCommand = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "command", ...options });
|
|
291
317
|
var writeCommand = (directory) => async (command, options = {
|
|
292
318
|
path: "",
|
|
293
319
|
override: false,
|
|
@@ -299,7 +325,7 @@ var rmCommandById = (directory) => async (id, version, persistFiles) => rmResour
|
|
|
299
325
|
// src/queries.ts
|
|
300
326
|
var import_promises4 = __toESM(require("fs/promises"));
|
|
301
327
|
var import_node_path4 = require("path");
|
|
302
|
-
var getQuery = (directory) => async (id, version) => getResource(directory, id, version, { type: "query" });
|
|
328
|
+
var getQuery = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "query", ...options });
|
|
303
329
|
var writeQuery = (directory) => async (query, options = {
|
|
304
330
|
path: "",
|
|
305
331
|
override: false,
|
package/dist/channels.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/channels.ts","../src/internal/resources.ts","../src/internal/utils.ts","../src/events.ts","../src/commands.ts","../src/queries.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport type { Channel } from './types';\nimport { getResource, getResourcePath, getResources, rmResourceById, versionResource, writeResource } from './internal/resources';\nimport { findFileById } from './internal/utils';\nimport { getEvent, rmEventById, writeEvent } from './events';\nimport { getCommand, rmCommandById, writeCommand } from './commands';\nimport { getQuery, rmQueryById, writeQuery } from './queries';\n\n/**\n * Returns a channel from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the channel\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getChannel } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the channel\n * const channel = await getChannel('InventoryChannel');\n *\n * // Gets a version of the channel\n * const channel = await getChannel('InventoryChannel', '0.0.1');\n * ```\n */\nexport const getChannel =\n (directory: string) =>\n async (id: string, version?: string): Promise<Channel> =>\n getResource(directory, id, version, { type: 'channel' }) as Promise<Channel>;\n\n/**\n * Returns all channels from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the channels.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getChannels } = utils('/path/to/eventcatalog');\n *\n * // Gets all channels (and versions) from the catalog\n * const channels = await getChannels();\n *\n * // Gets all channels (only latest version) from the catalog\n * const channels = await getChannels({ latestOnly: true });\n * ```\n */\nexport const getChannels =\n (directory: string) =>\n async (options?: { latestOnly?: boolean }): Promise<Channel[]> =>\n getResources(directory, { type: 'channels', ...options }) as Promise<Channel[]>;\n\n/**\n * Write a channel to EventCatalog.\n *\n * You can optionally override the path of the channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeChannel } = utils('/path/to/eventcatalog');\n *\n * // Write a channel to the catalog\n * // channel would be written to channels/inventory.{env}.events\n * await writeChannel({\n * id: 'inventory.{env}.events',\n * name: 'Inventory channel',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * });\n *\n * // Write a channel to the catalog but override the path\n * // channel would be written to channels/Inventory/InventoryChannel\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { path: \"/channels/Inventory/InventoryChannel\"});\n *\n * // Write a channel to the catalog and override the existing content (if there is any)\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { override: true });\n *\n * // Write a channel to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { versionExistingContent: true });\n * ```\n */\nexport const writeChannel =\n (directory: string) =>\n async (\n channel: Channel,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = { path: '' }\n ) =>\n writeResource(directory, { ...channel }, { ...options, type: 'channel' });\n\n/**\n * Delete a channel at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmChannel } = utils('/path/to/eventcatalog');\n *\n * // removes a channel at the given path (channels dir is appended to the given path)\n * // Removes the channel at channels/InventoryChannel\n * await rmChannel('/InventoryChannel');\n * ```\n */\nexport const rmChannel = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a channel by it's id.\n *\n * Optionally specify a version to delete a specific version of the channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmChannelById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryChannel channel\n * await rmChannelById('inventory.{env}.events');\n *\n * // deletes a specific version of the InventoryChannel channel\n * await rmChannelById('inventory.{env}.events', '0.0.1');\n * ```\n */\nexport const rmChannelById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) =>\n rmResourceById(directory, id, version, { type: 'channel', persistFiles });\n\n/**\n * Version a channel by it's id.\n *\n * Takes the latest channel and moves it to a versioned directory.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionChannel } = utils('/path/to/eventcatalog');\n *\n * // moves the latest inventory.{env}.events channel to a versioned directory\n * // the version within that channel is used as the version number.\n * await versionChannel('inventory.{env}.events');\n *\n * ```\n */\nexport const versionChannel = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Check to see if the catalog has a version for the given channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { channelHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await channelHasVersion('inventory.{env}.events', '0.0.1');\n * await channelHasVersion('inventory.{env}.events', 'latest');\n * await channelHasVersion('inventory.{env}.events', '0.0.x');*\n *\n * ```\n */\nexport const channelHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n\n/**\n * Add an event/command/query to a channel by it's id.\n *\n * Optionally specify a version to add the message to a specific version of the service.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * // Adds an event to the service or command to the service\n * const { addEventToChannel, addCommandToChannel, addQueryToChannel } = utils('/path/to/eventcatalog');\n *\n * // Adds a new event (InventoryUpdatedEvent) that the InventoryService will send\n * await addEventToChannel('InventoryService', 'sends', { event: 'InventoryUpdatedEvent', version: '2.0.0' });\n * * // Adds a new event (OrderComplete) that the InventoryService will receive\n * await addEventToChannel('InventoryService', 'receives', { event: 'OrderComplete', version: '1.0.0' });\n *\n * // Adds a new command (UpdateInventoryCommand) that the InventoryService will send\n * await addCommandToChannel('InventoryService', 'sends', { command: 'UpdateInventoryCommand', version: '2.0.0' });\n * // Adds a new command (VerifyInventory) that the InventoryService will receive\n * await addCommandToChannel('InventoryService', 'receives', { command: 'VerifyInventory', version: '1.0.0' });\n *\n * // Adds a new query (GetInventoryQuery) that the InventoryService will send\n * await addQueryToChannel('InventoryService', 'sends', { query: 'GetInventoryQuery', version: '2.0.0' });\n * // Adds a new query (GetOrder) that the InventoryService will receive\n * await addQueryToChannel('InventoryService', 'receives', { query: 'GetOrder', version: '1.0.0' });\n *\n * ```\n */\n\nexport const addMessageToChannel =\n (directory: string, collection: string) =>\n async (id: string, _message: { id: string; version: string; parameters?: { [key: string]: string } }, version?: string) => {\n let channel: Channel = await getChannel(directory)(id, version);\n\n const functions = {\n events: {\n getMessage: getEvent,\n rmMessageById: rmEventById,\n writeMessage: writeEvent,\n },\n commands: {\n getMessage: getCommand,\n rmMessageById: rmCommandById,\n writeMessage: writeCommand,\n },\n queries: {\n getMessage: getQuery,\n rmMessageById: rmQueryById,\n writeMessage: writeQuery,\n },\n };\n\n const { getMessage, rmMessageById, writeMessage } = functions[collection as keyof typeof functions];\n\n const message = await getMessage(directory)(_message.id, _message.version);\n const messagePath = await getResourcePath(directory, _message.id, _message.version);\n const extension = extname(messagePath?.fullPath || '');\n\n if (!message) throw new Error(`Message ${_message.id} with version ${_message.version} not found`);\n\n if (message.channels === undefined) {\n message.channels = [];\n }\n\n const channelInfo = { id, version: channel.version, ...(_message.parameters && { parameters: _message.parameters }) };\n message.channels.push(channelInfo);\n\n // Add the message where it was to start..\n const existingResource = await findFileById(directory, _message.id, _message.version);\n\n if (!existingResource) {\n throw new Error(`Cannot find message ${id} in the catalog`);\n }\n\n const path = existingResource.split(`/${collection}`)[0];\n const pathToResource = join(path, collection);\n\n await rmMessageById(directory)(_message.id, _message.version, true);\n await writeMessage(pathToResource)(message, { format: extension === '.md' ? 'md' : 'mdx' });\n };\n","import { dirname, join } from 'path';\nimport { copyDir, findFileById, getFiles, searchFilesForId, versionExists } from './utils';\nimport matter from 'gray-matter';\nimport fs from 'node:fs/promises';\nimport fsSync from 'node:fs';\nimport { Message, Service, CustomDoc } from '../types';\nimport { satisfies } from 'semver';\nimport { lock, unlock } from 'proper-lockfile';\n\ntype Resource = Service | Message | CustomDoc;\n\nexport const versionResource = async (catalogDir: string, id: string) => {\n // Find all the events in the directory\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n const matchedFiles = await searchFilesForId(files, id);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No resource found with id: ${id}`);\n }\n\n // Event that is in the route of the project\n const file = matchedFiles[0];\n const sourceDirectory = dirname(file);\n const { data: { version = '0.0.1' } = {} } = matter.read(file);\n const targetDirectory = getVersionedDirectory(sourceDirectory, version);\n\n fsSync.mkdirSync(targetDirectory, { recursive: true });\n\n // Copy the event to the versioned directory\n await copyDir(catalogDir, sourceDirectory, targetDirectory, (src) => {\n return !src.includes('versioned');\n });\n\n // Remove all the files in the root of the resource as they have now been versioned\n await fs.readdir(sourceDirectory).then(async (resourceFiles) => {\n await Promise.all(\n resourceFiles.map(async (file) => {\n if (file !== 'versioned') {\n fsSync.rmSync(join(sourceDirectory, file), { recursive: true });\n }\n })\n );\n });\n};\n\nexport const writeResource = async (\n catalogDir: string,\n resource: Resource,\n options: { path?: string; type: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n type: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n) => {\n const path = options.path || `/${resource.id}`;\n const fullPath = join(catalogDir, path);\n const format = options.format || 'mdx';\n\n // Create directory if it doesn't exist\n fsSync.mkdirSync(fullPath, { recursive: true });\n\n // Create or get lock file path\n const lockPath = join(fullPath, `index.${format}`);\n\n // Ensure the file exists before attempting to lock it\n if (!fsSync.existsSync(lockPath)) {\n fsSync.writeFileSync(lockPath, '');\n }\n\n try {\n // Acquire lock with retry\n await lock(lockPath, {\n retries: 5,\n stale: 10000, // 10 seconds\n });\n\n const exists = await versionExists(catalogDir, resource.id, resource.version);\n\n if (exists && !options.override) {\n throw new Error(`Failed to write ${resource.id} (${options.type}) as the version ${resource.version} already exists`);\n }\n\n const { markdown, ...frontmatter } = resource;\n\n if (options.versionExistingContent && !exists) {\n const currentResource = await getResource(catalogDir, resource.id);\n\n if (currentResource) {\n if (satisfies(resource.version, `>${currentResource.version}`)) {\n await versionResource(catalogDir, resource.id);\n } else {\n throw new Error(`New version ${resource.version} is not greater than current version ${currentResource.version}`);\n }\n }\n }\n\n const document = matter.stringify(markdown.trim(), frontmatter);\n fsSync.writeFileSync(lockPath, document);\n } finally {\n // Always release the lock\n await unlock(lockPath).catch(() => {});\n }\n};\n\nexport const getResource = async (\n catalogDir: string,\n id: string,\n version?: string,\n options?: { type: string }\n): Promise<Resource | undefined> => {\n const file = await findFileById(catalogDir, id, version);\n if (!file) return;\n\n const { data, content } = matter.read(file);\n\n return {\n ...data,\n markdown: content.trim(),\n } as Resource;\n};\n\nexport const getResourcePath = async (catalogDir: string, id: string, version?: string) => {\n const file = await findFileById(catalogDir, id, version);\n if (!file) return;\n\n return {\n fullPath: file,\n relativePath: file.replace(catalogDir, ''),\n directory: dirname(file.replace(catalogDir, '')),\n };\n};\n\nexport const getResources = async (\n catalogDir: string,\n {\n type,\n latestOnly = false,\n ignore = [],\n pattern = '',\n }: { type: string; pattern?: string; latestOnly?: boolean; ignore?: string[] }\n): Promise<Resource[] | undefined> => {\n const ignoreList = latestOnly ? `**/versioned/**` : '';\n const filePattern = pattern || `${catalogDir}/**/${type}/**/index.{md,mdx}`;\n const files = await getFiles(filePattern, [ignoreList, ...ignore]);\n\n if (files.length === 0) return;\n\n return files.map((file) => {\n const { data, content } = matter.read(file);\n return {\n ...data,\n markdown: content.trim(),\n } as Resource;\n });\n};\n\nexport const rmResourceById = async (\n catalogDir: string,\n id: string,\n version?: string,\n options?: { type: string; persistFiles?: boolean }\n) => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n\n const matchedFiles = await searchFilesForId(files, id, version);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No ${options?.type || 'resource'} found with id: ${id}`);\n }\n\n if (options?.persistFiles) {\n await Promise.all(\n matchedFiles.map(async (file) => {\n await fs.rm(file, { recursive: true });\n })\n );\n } else {\n await Promise.all(\n matchedFiles.map(async (file) => {\n const directory = dirname(file);\n await fs.rm(directory, { recursive: true, force: true });\n })\n );\n }\n};\n\nexport const addFileToResource = async (\n catalogDir: string,\n id: string,\n file: { content: string; fileName: string },\n version?: string\n) => {\n const pathToResource = await findFileById(catalogDir, id, version);\n\n if (!pathToResource) throw new Error('Cannot find directory to write file to');\n\n let fileContent = file.content.trim();\n\n try {\n const json = JSON.parse(fileContent);\n fileContent = JSON.stringify(json, null, 2);\n } catch (error) {\n // Just silently fail if the file is not valid JSON\n // Write it as it is\n }\n\n fsSync.writeFileSync(join(dirname(pathToResource), file.fileName), fileContent);\n};\n\nexport const getFileFromResource = async (catalogDir: string, id: string, file: { fileName: string }, version?: string) => {\n const pathToResource = await findFileById(catalogDir, id, version);\n\n if (!pathToResource) throw new Error('Cannot find directory of resource');\n\n const exists = await fs\n .access(join(dirname(pathToResource), file.fileName))\n .then(() => true)\n .catch(() => false);\n if (!exists) throw new Error(`File ${file.fileName} does not exist in resource ${id} v(${version})`);\n\n return fsSync.readFileSync(join(dirname(pathToResource), file.fileName), 'utf-8');\n};\nexport const getVersionedDirectory = (sourceDirectory: string, version: any): string => {\n return join(sourceDirectory, 'versioned', version);\n};\n","import { globSync } from 'glob';\nimport fsSync from 'node:fs';\nimport { copy, CopyFilterAsync, CopyFilterSync } from 'fs-extra';\nimport { join, dirname, normalize, sep as pathSeparator, resolve, basename, relative } from 'node:path';\nimport matter from 'gray-matter';\nimport { satisfies, validRange, valid } from 'semver';\n\n/**\n * Returns true if a given version of a resource id exists in the catalog\n */\nexport const versionExists = async (catalogDir: string, id: string, version: string) => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n const matchedFiles = (await searchFilesForId(files, id, version)) || [];\n return matchedFiles.length > 0;\n};\n\nexport const findFileById = async (catalogDir: string, id: string, version?: string): Promise<string | undefined> => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n\n const matchedFiles = (await searchFilesForId(files, id)) || [];\n const latestVersion = matchedFiles.find((path) => !path.includes('versioned'));\n\n // If no version is provided, return the latest version\n if (!version) {\n return latestVersion;\n }\n\n // map files into gray matter to get versions\n const parsedFiles = matchedFiles.map((path) => {\n const { data } = matter.read(path);\n return { ...data, path };\n }) as any[];\n\n const semverRange = validRange(version);\n\n if (semverRange && valid(version)) {\n const match = parsedFiles.filter((c) => satisfies(c.version, semverRange));\n return match.length > 0 ? match[0].path : undefined;\n }\n\n // Order by version\n const sorted = parsedFiles.sort((a, b) => {\n return a.version.localeCompare(b.version);\n });\n\n // latest version\n const match = sorted.length > 0 ? [sorted[sorted.length - 1]] : [];\n\n if (match.length > 0) {\n return match[0].path;\n }\n};\n\nexport const getFiles = async (pattern: string, ignore: string | string[] = '') => {\n try {\n // 1. Normalize the input pattern to handle mixed separators potentially\n const normalizedInputPattern = normalize(pattern);\n\n // 2. Determine the absolute base directory (cwd for glob)\n // Resolve ensures it's absolute. Handles cases with/without globstar.\n const absoluteBaseDir = resolve(\n normalizedInputPattern.includes('**') ? normalizedInputPattern.split('**')[0] : dirname(normalizedInputPattern)\n );\n\n // 3. Determine the pattern part relative to the absolute base directory\n // We extract the part of the normalized pattern that comes *after* the absoluteBaseDir\n let relativePattern = relative(absoluteBaseDir, normalizedInputPattern);\n\n // On Windows, relative() might return empty string if paths are identical,\n // or might need normalization if the original pattern didn't have `**`\n // Example: pattern = 'dir/file.md', absoluteBaseDir='.../dir', normalized='...\\dir\\file.md'\n // relative() -> 'file.md'\n // Example: pattern = 'dir/**/file.md', absoluteBaseDir='.../dir', normalized='...\\dir\\**\\file.md'\n // relative() -> '**\\file.md'\n // Convert separators in the relative pattern to forward slashes for glob\n relativePattern = relativePattern.replace(/\\\\/g, '/');\n\n const ignoreList = Array.isArray(ignore) ? ignore : [ignore];\n\n const files = globSync(relativePattern, {\n cwd: absoluteBaseDir,\n ignore: ['node_modules/**', ...ignoreList],\n absolute: true,\n nodir: true,\n });\n\n // 5. Normalize results for consistency before returning\n return files.map(normalize);\n } catch (error: any) {\n // Add more diagnostic info to the error\n const absoluteBaseDirForError = resolve(\n normalize(pattern).includes('**') ? normalize(pattern).split('**')[0] : dirname(normalize(pattern))\n );\n const relativePatternForError = relative(absoluteBaseDirForError, normalize(pattern)).replace(/\\\\/g, '/');\n throw new Error(\n `Error finding files for pattern \"${pattern}\" (using cwd: \"${absoluteBaseDirForError}\", globPattern: \"${relativePatternForError}\"): ${error.message}`\n );\n }\n};\n\nexport const readMdxFile = async (path: string) => {\n const { data } = matter.read(path);\n const { markdown, ...frontmatter } = data;\n return { ...frontmatter, markdown };\n};\n\nexport const searchFilesForId = async (files: string[], id: string, version?: string) => {\n const idRegex = new RegExp(`^id:\\\\s*(['\"]|>-)?\\\\s*${id}['\"]?\\\\s*$`, 'm');\n const versionRegex = new RegExp(`^version:\\\\s*['\"]?${version}['\"]?\\\\s*$`, 'm');\n\n const matches = files.map((file) => {\n const content = fsSync.readFileSync(file, 'utf-8');\n const hasIdMatch = content.match(idRegex);\n\n // Check version if provided\n if (version && !content.match(versionRegex)) {\n return undefined;\n }\n\n if (hasIdMatch) {\n return file;\n }\n });\n\n return matches.filter(Boolean).filter((file) => file !== undefined);\n};\n\n/**\n * Function to copy a directory from source to target, uses a tmp directory\n * @param catalogDir\n * @param source\n * @param target\n * @param filter\n */\nexport const copyDir = async (catalogDir: string, source: string, target: string, filter?: CopyFilterAsync | CopyFilterSync) => {\n const tmpDirectory = join(catalogDir, 'tmp');\n fsSync.mkdirSync(tmpDirectory, { recursive: true });\n\n // Copy everything over\n await copy(source, tmpDirectory, {\n overwrite: true,\n filter,\n });\n\n await copy(tmpDirectory, target, {\n overwrite: true,\n filter,\n });\n\n // Remove the tmp directory\n fsSync.rmSync(tmpDirectory, { recursive: true });\n};\n\n// Makes sure values in sends/recieves are unique\nexport const uniqueVersions = (messages: { id: string; version: string }[]): { id: string; version: string }[] => {\n const uniqueSet = new Set();\n\n return messages.filter((message) => {\n const key = `${message.id}-${message.version}`;\n if (!uniqueSet.has(key)) {\n uniqueSet.add(key);\n return true;\n }\n return false;\n });\n};\n","import fs from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { findFileById } from './internal/utils';\nimport type { Event } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\n\n/**\n * Returns an event from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the event\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getEvent } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the event\n * const event = await getEvent('InventoryAdjusted');\n *\n * // Gets a version of the event\n * const event = await getEvent('InventoryAdjusted', '0.0.1');\n * ```\n */\nexport const getEvent =\n (directory: string) =>\n async (id: string, version?: string): Promise<Event> =>\n getResource(directory, id, version, { type: 'event' }) as Promise<Event>;\n\n/**\n * Returns all events from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the events.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getEvents } = utils('/path/to/eventcatalog');\n *\n * // Gets all events (and versions) from the catalog\n * const events = await getEvents();\n *\n * // Gets all events (only latest version) from the catalog\n * const events = await getEvents({ latestOnly: true });\n * ```\n */\nexport const getEvents =\n (directory: string) =>\n async (options?: { latestOnly?: boolean }): Promise<Event[]> =>\n getResources(directory, { type: 'events', ...options }) as Promise<Event[]>;\n\n/**\n * Write an event to EventCatalog.\n *\n * You can optionally overide the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeEvent } = utils('/path/to/eventcatalog');\n *\n * // Write an event to the catalog\n * // Event would be written to events/InventoryAdjusted\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write an event to the catalog but override the path\n * // Event would be written to events/Inventory/InventoryAdjusted\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Inventory/InventoryAdjusted\"});\n *\n * // Write a event to the catalog and override the existing content (if there is any)\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a event to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeEvent =\n (directory: string) =>\n async (\n event: Event,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...event }, { ...options, type: 'event' });\n/**\n * Write an event to a service in EventCatalog.\n *\n * You can optionally override the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeEventToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Inventory/events/InventoryAdjusted\n * await writeEventToService({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Inventory' });\n * ```\n */\nexport const writeEventToService =\n (directory: string) =>\n async (\n event: Event,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n\n let pathForEvent =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/events`\n : `${resourcePath.directory}/events`;\n pathForEvent = join(pathForEvent, event.id);\n await writeResource(directory, { ...event }, { ...options, path: pathForEvent, type: 'event' });\n };\n\n/**\n * Delete an event at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmEvent } = utils('/path/to/eventcatalog');\n *\n * // removes an event at the given path (events dir is appended to the given path)\n * // Removes the event at events/InventoryAdjusted\n * await rmEvent('/InventoryAdjusted');\n * ```\n */\nexport const rmEvent = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete an event by it's id.\n *\n * Optionally specify a version to delete a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmEventById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryAdjusted event\n * await rmEventById('InventoryAdjusted');\n *\n * // deletes a specific version of the InventoryAdjusted event\n * await rmEventById('InventoryAdjusted', '0.0.1');\n * ```\n */\nexport const rmEventById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) => {\n await rmResourceById(directory, id, version, { type: 'event', persistFiles });\n};\n\n/**\n * Version an event by it's id.\n *\n * Takes the latest event and moves it to a versioned directory.\n * All files with this event are also versioned (e.g /events/InventoryAdjusted/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionEvent } = utils('/path/to/eventcatalog');\n *\n * // moves the latest InventoryAdjusted event to a versioned directory\n * // the version within that event is used as the version number.\n * await versionEvent('InventoryAdjusted');\n *\n * ```\n */\nexport const versionEvent = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to an event by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToEvent } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest InventoryAdjusted event\n * await addFileToEvent('InventoryAdjusted', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the InventoryAdjusted event\n * await addFileToEvent('InventoryAdjusted', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToEvent =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to an event by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToEvent } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest InventoryAdjusted event\n * await addSchemaToEvent('InventoryAdjusted', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the InventoryAdjusted event\n * await addSchemaToEvent('InventoryAdjusted', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToEvent =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToEvent(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { eventHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await eventHasVersion('InventoryAdjusted', '0.0.1');\n * await eventHasVersion('InventoryAdjusted', 'latest');\n * await eventHasVersion('InventoryAdjusted', '0.0.x');*\n *\n * ```\n */\nexport const eventHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n","import fs from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Command } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\nimport { findFileById } from './internal/utils';\nimport { addMessageToService } from './services';\n\n/**\n * Returns a command from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the command\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getCommand } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the command\n * const command = await getCommand('UpdateInventory');\n *\n * // Gets a version of the command\n * const command = await getCommand('UpdateInventory', '0.0.1');\n * ```\n */\nexport const getCommand =\n (directory: string) =>\n async (id: string, version?: string): Promise<Command> =>\n getResource(directory, id, version, { type: 'command' }) as Promise<Command>;\n\n/**\n * Returns all commands from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the events.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getCommands } = utils('/path/to/eventcatalog');\n *\n * // Gets all commands (and versions) from the catalog\n * const commands = await getCommands();\n *\n * // Gets all commands (only latest version) from the catalog\n * const commands = await getCommands({ latestOnly: true });\n * ```\n */\nexport const getCommands =\n (directory: string) =>\n async (options?: { latestOnly?: boolean }): Promise<Command[]> =>\n getResources(directory, { type: 'commands', ...options }) as Promise<Command[]>;\n\n/**\n * Write a command to EventCatalog.\n *\n * You can optionally override the path of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeCommand } = utils('/path/to/eventcatalog');\n *\n * // Write a command to the catalog\n * // Command would be written to commands/UpdateInventory\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write a command to the catalog but override the path\n * // Command would be written to commands/Inventory/UpdateInventory\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Inventory/UpdateInventory\"});\n *\n * // Write a command to the catalog and override the existing content (if there is any)\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a command to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeCommand =\n (directory: string) =>\n async (\n command: Command,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...command }, { ...options, type: 'command' });\n\n/**\n * Write an command to a service in EventCatalog.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeCommandToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Inventory/commands/UpdateInventory\n * await writeCommandToService({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Inventory' });\n * ```\n */\nexport const writeCommandToService =\n (directory: string) =>\n async (\n command: Command,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n\n let pathForCommand =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/commands`\n : `${resourcePath.directory}/commands`;\n pathForCommand = join(pathForCommand, command.id);\n\n await writeResource(directory, { ...command }, { ...options, path: pathForCommand, type: 'command' });\n };\n\n/**\n * Delete a command at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmCommand } = utils('/path/to/eventcatalog');\n *\n * // removes a command at the given path (commands dir is appended to the given path)\n * // Removes the command at commands/UpdateInventory\n * await rmCommand('/UpdateInventory');\n * ```\n */\nexport const rmCommand = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a command by it's id.\n *\n * Optionally specify a version to delete a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmCommandById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest UpdateInventory command\n * await rmCommandById('UpdateInventory');\n *\n * // deletes a specific version of the UpdateInventory command\n * await rmCommandById('UpdateInventory', '0.0.1');\n * ```\n */\nexport const rmCommandById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) =>\n rmResourceById(directory, id, version, { type: 'command', persistFiles });\n\n/**\n * Version a command by it's id.\n *\n * Takes the latest command and moves it to a versioned directory.\n * All files with this command are also versioned (e.g /commands/UpdateInventory/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionCommand } = utils('/path/to/eventcatalog');\n *\n * // moves the latest UpdateInventory command to a versioned directory\n * // the version within that command is used as the version number.\n * await versionCommand('UpdateInventory');\n *\n * ```\n */\nexport const versionCommand = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to a command by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToCommand } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest UpdateInventory command\n * await addFileToCommand('UpdateInventory', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the UpdateInventory command\n * await addFileToCommand('UpdateInventory', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToCommand =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to a command by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToCommand } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest UpdateInventory command\n * await addSchemaToCommand('UpdateInventory', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the UpdateInventory command\n * await addSchemaToCommand('UpdateInventory', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToCommand =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToCommand(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { commandHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await commandHasVersion('InventoryAdjusted', '0.0.1');\n * await commandHasVersion('InventoryAdjusted', 'latest');\n * await commandHasVersion('InventoryAdjusted', '0.0.x');*\n *\n * ```\n */\nexport const commandHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n","import fs from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { findFileById } from './internal/utils';\nimport type { Query } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\n\n/**\n * Returns a query from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the query\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getQuery } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the event\n * const event = await getQuery('GetOrder');\n *\n * // Gets a version of the event\n * const event = await getQuery('GetOrder', '0.0.1');\n * ```\n */\nexport const getQuery =\n (directory: string) =>\n async (id: string, version?: string): Promise<Query> =>\n getResource(directory, id, version, { type: 'query' }) as Promise<Query>;\n\n/**\n * Write a query to EventCatalog.\n *\n * You can optionally override the path of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeQuery } = utils('/path/to/eventcatalog');\n *\n * // Write an event to the catalog\n * // Event would be written to queries/GetOrder\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write an event to the catalog but override the path\n * // Event would be written to queries/Inventory/GetOrder\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Orders/GetOrder\"});\n *\n * // Write a query to the catalog and override the existing content (if there is any)\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a query to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeQuery =\n (directory: string) =>\n async (\n query: Query,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...query }, { ...options, type: 'query' });\n\n/**\n * Returns all queries from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the queries.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getQueries } = utils('/path/to/eventcatalog');\n *\n * // Gets all queries (and versions) from the catalog\n * const queries = await getQueries();\n *\n * // Gets all queries (only latest version) from the catalog\n * const queries = await getQueries({ latestOnly: true });\n * ```\n */\nexport const getQueries =\n (directory: string) =>\n async (options?: { latestOnly?: boolean }): Promise<Query[]> =>\n getResources(directory, { type: 'queries', ...options }) as Promise<Query[]>;\n\n/**\n * Write a query to a service in EventCatalog.\n *\n * You can optionally override the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeQueryToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Orders/queries/GetOrder\n * await writeQueryToService({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Orders' });\n * ```\n */\nexport const writeQueryToService =\n (directory: string) =>\n async (\n query: Query,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n let pathForQuery =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/queries`\n : `${resourcePath.directory}/queries`;\n pathForQuery = join(pathForQuery, query.id);\n await writeResource(directory, { ...query }, { ...options, path: pathForQuery, type: 'query' });\n };\n\n/**\n * Delete a query at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmQuery } = utils('/path/to/eventcatalog');\n *\n * // removes an query at the given path (queries dir is appended to the given path)\n * // Removes the query at queries/GetOrders\n * await rmQuery('/GetOrders');\n * ```\n */\nexport const rmQuery = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a query by it's id.\n *\n * Optionally specify a version to delete a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmQueryById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryAdjusted query\n * await rmQueryById('GetOrder');\n *\n * // deletes a specific version of the GetOrder query\n * await rmQueryById('GetOrder', '0.0.1');\n * ```\n */\nexport const rmQueryById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) => {\n await rmResourceById(directory, id, version, { type: 'query', persistFiles });\n};\n\n/**\n * Version a query by it's id.\n *\n * Takes the latest query and moves it to a versioned directory.\n * All files with this query are also versioned (e.g /queries/GetOrder/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionQuery } = utils('/path/to/eventcatalog');\n *\n * // moves the latest GetOrder query to a versioned directory\n * // the version within that query is used as the version number.\n * await versionQuery('GetOrder');\n *\n * ```\n */\nexport const versionQuery = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to a query by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToQuery } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest GetOrder query\n * await addFileToQuery('GetOrder', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the GetOrder query\n * await addFileToQuery('GetOrder', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToQuery =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to a query by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToQuery } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest GetOrder query\n * await addSchemaToQuery('GetOrder', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the GetOrder query\n * await addSchemaToQuery('GetOrder', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToQuery =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToQuery(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { queryHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await queryHasVersion('GetOrder', '0.0.1');\n * await queryHasVersion('GetOrder', 'latest');\n * await queryHasVersion('GetOrder', '0.0.x');*\n *\n * ```\n */\nexport const queryHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n"],"mappings":"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","names":["import_promises","import_node_path","matter","match","fsSync","import_gray_matter","import_node_fs","import_semver","matter","fsSync","fs","file","import_promises","import_node_path","import_promises","import_node_path","import_promises","import_node_path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/channels.ts","../src/internal/resources.ts","../src/internal/utils.ts","../src/events.ts","../src/commands.ts","../src/queries.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport type { Channel } from './types';\nimport { getResource, getResourcePath, getResources, rmResourceById, versionResource, writeResource } from './internal/resources';\nimport { findFileById } from './internal/utils';\nimport { getEvent, rmEventById, writeEvent } from './events';\nimport { getCommand, rmCommandById, writeCommand } from './commands';\nimport { getQuery, rmQueryById, writeQuery } from './queries';\n\n/**\n * Returns a channel from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the channel\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getChannel } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the channel\n * const channel = await getChannel('InventoryChannel');\n *\n * // Gets a version of the channel\n * const channel = await getChannel('InventoryChannel', '0.0.1');\n * ```\n */\nexport const getChannel =\n (directory: string) =>\n async (id: string, version?: string): Promise<Channel> =>\n getResource(directory, id, version, { type: 'channel' }) as Promise<Channel>;\n\n/**\n * Returns all channels from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the channels.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getChannels } = utils('/path/to/eventcatalog');\n *\n * // Gets all channels (and versions) from the catalog\n * const channels = await getChannels();\n *\n * // Gets all channels (only latest version) from the catalog\n * const channels = await getChannels({ latestOnly: true });\n * ```\n */\nexport const getChannels =\n (directory: string) =>\n async (options?: { latestOnly?: boolean }): Promise<Channel[]> =>\n getResources(directory, { type: 'channels', ...options }) as Promise<Channel[]>;\n\n/**\n * Write a channel to EventCatalog.\n *\n * You can optionally override the path of the channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeChannel } = utils('/path/to/eventcatalog');\n *\n * // Write a channel to the catalog\n * // channel would be written to channels/inventory.{env}.events\n * await writeChannel({\n * id: 'inventory.{env}.events',\n * name: 'Inventory channel',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * });\n *\n * // Write a channel to the catalog but override the path\n * // channel would be written to channels/Inventory/InventoryChannel\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { path: \"/channels/Inventory/InventoryChannel\"});\n *\n * // Write a channel to the catalog and override the existing content (if there is any)\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { override: true });\n *\n * // Write a channel to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeChannel({\n * id: 'InventoryChannel',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * address: inventory.{env}.events,\n * protocols: ['http'],\n * }, { versionExistingContent: true });\n * ```\n */\nexport const writeChannel =\n (directory: string) =>\n async (\n channel: Channel,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = { path: '' }\n ) =>\n writeResource(directory, { ...channel }, { ...options, type: 'channel' });\n\n/**\n * Delete a channel at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmChannel } = utils('/path/to/eventcatalog');\n *\n * // removes a channel at the given path (channels dir is appended to the given path)\n * // Removes the channel at channels/InventoryChannel\n * await rmChannel('/InventoryChannel');\n * ```\n */\nexport const rmChannel = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a channel by it's id.\n *\n * Optionally specify a version to delete a specific version of the channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmChannelById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryChannel channel\n * await rmChannelById('inventory.{env}.events');\n *\n * // deletes a specific version of the InventoryChannel channel\n * await rmChannelById('inventory.{env}.events', '0.0.1');\n * ```\n */\nexport const rmChannelById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) =>\n rmResourceById(directory, id, version, { type: 'channel', persistFiles });\n\n/**\n * Version a channel by it's id.\n *\n * Takes the latest channel and moves it to a versioned directory.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionChannel } = utils('/path/to/eventcatalog');\n *\n * // moves the latest inventory.{env}.events channel to a versioned directory\n * // the version within that channel is used as the version number.\n * await versionChannel('inventory.{env}.events');\n *\n * ```\n */\nexport const versionChannel = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Check to see if the catalog has a version for the given channel.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { channelHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await channelHasVersion('inventory.{env}.events', '0.0.1');\n * await channelHasVersion('inventory.{env}.events', 'latest');\n * await channelHasVersion('inventory.{env}.events', '0.0.x');*\n *\n * ```\n */\nexport const channelHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n\n/**\n * Add an event/command/query to a channel by it's id.\n *\n * Optionally specify a version to add the message to a specific version of the service.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * // Adds an event to the service or command to the service\n * const { addEventToChannel, addCommandToChannel, addQueryToChannel } = utils('/path/to/eventcatalog');\n *\n * // Adds a new event (InventoryUpdatedEvent) that the InventoryService will send\n * await addEventToChannel('InventoryService', 'sends', { event: 'InventoryUpdatedEvent', version: '2.0.0' });\n * * // Adds a new event (OrderComplete) that the InventoryService will receive\n * await addEventToChannel('InventoryService', 'receives', { event: 'OrderComplete', version: '1.0.0' });\n *\n * // Adds a new command (UpdateInventoryCommand) that the InventoryService will send\n * await addCommandToChannel('InventoryService', 'sends', { command: 'UpdateInventoryCommand', version: '2.0.0' });\n * // Adds a new command (VerifyInventory) that the InventoryService will receive\n * await addCommandToChannel('InventoryService', 'receives', { command: 'VerifyInventory', version: '1.0.0' });\n *\n * // Adds a new query (GetInventoryQuery) that the InventoryService will send\n * await addQueryToChannel('InventoryService', 'sends', { query: 'GetInventoryQuery', version: '2.0.0' });\n * // Adds a new query (GetOrder) that the InventoryService will receive\n * await addQueryToChannel('InventoryService', 'receives', { query: 'GetOrder', version: '1.0.0' });\n *\n * ```\n */\n\nexport const addMessageToChannel =\n (directory: string, collection: string) =>\n async (id: string, _message: { id: string; version: string; parameters?: { [key: string]: string } }, version?: string) => {\n let channel: Channel = await getChannel(directory)(id, version);\n\n const functions = {\n events: {\n getMessage: getEvent,\n rmMessageById: rmEventById,\n writeMessage: writeEvent,\n },\n commands: {\n getMessage: getCommand,\n rmMessageById: rmCommandById,\n writeMessage: writeCommand,\n },\n queries: {\n getMessage: getQuery,\n rmMessageById: rmQueryById,\n writeMessage: writeQuery,\n },\n };\n\n const { getMessage, rmMessageById, writeMessage } = functions[collection as keyof typeof functions];\n\n const message = await getMessage(directory)(_message.id, _message.version);\n const messagePath = await getResourcePath(directory, _message.id, _message.version);\n const extension = extname(messagePath?.fullPath || '');\n\n if (!message) throw new Error(`Message ${_message.id} with version ${_message.version} not found`);\n\n if (message.channels === undefined) {\n message.channels = [];\n }\n\n const channelInfo = { id, version: channel.version, ...(_message.parameters && { parameters: _message.parameters }) };\n message.channels.push(channelInfo);\n\n // Add the message where it was to start..\n const existingResource = await findFileById(directory, _message.id, _message.version);\n\n if (!existingResource) {\n throw new Error(`Cannot find message ${id} in the catalog`);\n }\n\n const path = existingResource.split(`/${collection}`)[0];\n const pathToResource = join(path, collection);\n\n await rmMessageById(directory)(_message.id, _message.version, true);\n await writeMessage(pathToResource)(message, { format: extension === '.md' ? 'md' : 'mdx' });\n };\n","import { dirname, join } from 'path';\nimport { copyDir, findFileById, getFiles, searchFilesForId, versionExists } from './utils';\nimport matter from 'gray-matter';\nimport fs from 'node:fs/promises';\nimport fsSync from 'node:fs';\nimport { Message, Service, CustomDoc } from '../types';\nimport { satisfies } from 'semver';\nimport { lock, unlock } from 'proper-lockfile';\n\ntype Resource = Service | Message | CustomDoc;\n\nexport const versionResource = async (catalogDir: string, id: string) => {\n // Find all the events in the directory\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n const matchedFiles = await searchFilesForId(files, id);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No resource found with id: ${id}`);\n }\n\n // Event that is in the route of the project\n const file = matchedFiles[0];\n const sourceDirectory = dirname(file);\n const { data: { version = '0.0.1' } = {} } = matter.read(file);\n const targetDirectory = getVersionedDirectory(sourceDirectory, version);\n\n fsSync.mkdirSync(targetDirectory, { recursive: true });\n\n // Copy the event to the versioned directory\n await copyDir(catalogDir, sourceDirectory, targetDirectory, (src) => {\n return !src.includes('versioned');\n });\n\n // Remove all the files in the root of the resource as they have now been versioned\n await fs.readdir(sourceDirectory).then(async (resourceFiles) => {\n await Promise.all(\n resourceFiles.map(async (file) => {\n if (file !== 'versioned') {\n fsSync.rmSync(join(sourceDirectory, file), { recursive: true });\n }\n })\n );\n });\n};\n\nexport const writeResource = async (\n catalogDir: string,\n resource: Resource,\n options: { path?: string; type: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n type: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n) => {\n const path = options.path || `/${resource.id}`;\n const fullPath = join(catalogDir, path);\n const format = options.format || 'mdx';\n\n // Create directory if it doesn't exist\n fsSync.mkdirSync(fullPath, { recursive: true });\n\n // Create or get lock file path\n const lockPath = join(fullPath, `index.${format}`);\n\n // Ensure the file exists before attempting to lock it\n if (!fsSync.existsSync(lockPath)) {\n fsSync.writeFileSync(lockPath, '');\n }\n\n try {\n // Acquire lock with retry\n await lock(lockPath, {\n retries: 5,\n stale: 10000, // 10 seconds\n });\n\n const exists = await versionExists(catalogDir, resource.id, resource.version);\n\n if (exists && !options.override) {\n throw new Error(`Failed to write ${resource.id} (${options.type}) as the version ${resource.version} already exists`);\n }\n\n const { markdown, ...frontmatter } = resource;\n\n if (options.versionExistingContent && !exists) {\n const currentResource = await getResource(catalogDir, resource.id);\n\n if (currentResource) {\n if (satisfies(resource.version, `>${currentResource.version}`)) {\n await versionResource(catalogDir, resource.id);\n } else {\n throw new Error(`New version ${resource.version} is not greater than current version ${currentResource.version}`);\n }\n }\n }\n\n const document = matter.stringify(markdown.trim(), frontmatter);\n fsSync.writeFileSync(lockPath, document);\n } finally {\n // Always release the lock\n await unlock(lockPath).catch(() => {});\n }\n};\n\nexport const getResource = async (\n catalogDir: string,\n id: string,\n version?: string,\n options?: { type: string; attachSchema?: boolean }\n): Promise<Resource | undefined> => {\n const attachSchema = options?.attachSchema || false;\n const file = await findFileById(catalogDir, id, version);\n if (!file) return;\n\n const { data, content } = matter.read(file);\n\n if (attachSchema && data?.schemaPath) {\n const resourceDirectory = dirname(file);\n const pathToSchema = join(resourceDirectory, data.schemaPath);\n if (fsSync.existsSync(pathToSchema)) {\n const schema = fsSync.readFileSync(pathToSchema, 'utf8');\n // Try to parse the schema\n try {\n data.schema = JSON.parse(schema);\n } catch (error) {\n data.schema = schema;\n }\n }\n }\n\n return {\n ...data,\n markdown: content.trim(),\n } as Resource;\n};\n\nexport const getResourcePath = async (catalogDir: string, id: string, version?: string) => {\n const file = await findFileById(catalogDir, id, version);\n if (!file) return;\n\n return {\n fullPath: file,\n relativePath: file.replace(catalogDir, ''),\n directory: dirname(file.replace(catalogDir, '')),\n };\n};\n\nexport const getResources = async (\n catalogDir: string,\n {\n type,\n latestOnly = false,\n ignore = [],\n pattern = '',\n attachSchema = false,\n }: { type: string; pattern?: string; latestOnly?: boolean; ignore?: string[]; attachSchema?: boolean }\n): Promise<Resource[] | undefined> => {\n const ignoreList = latestOnly ? `**/versioned/**` : '';\n const filePattern = pattern || `${catalogDir}/**/${type}/**/index.{md,mdx}`;\n const files = await getFiles(filePattern, [ignoreList, ...ignore]);\n\n if (files.length === 0) return;\n\n return files.map((file) => {\n const { data, content } = matter.read(file);\n\n // Attach the schema if the attachSchema option is set to true\n if (attachSchema && data?.schemaPath) {\n const resourceDirectory = dirname(file);\n const pathToSchema = join(resourceDirectory, data.schemaPath);\n if (fsSync.existsSync(pathToSchema)) {\n const schema = fsSync.readFileSync(pathToSchema, 'utf8');\n // Try to parse the schema\n try {\n data.schema = JSON.parse(schema);\n } catch (error) {\n data.schema = schema;\n }\n }\n }\n return {\n ...data,\n markdown: content.trim(),\n } as Resource;\n });\n};\n\nexport const rmResourceById = async (\n catalogDir: string,\n id: string,\n version?: string,\n options?: { type: string; persistFiles?: boolean }\n) => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n\n const matchedFiles = await searchFilesForId(files, id, version);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No ${options?.type || 'resource'} found with id: ${id}`);\n }\n\n if (options?.persistFiles) {\n await Promise.all(\n matchedFiles.map(async (file) => {\n await fs.rm(file, { recursive: true });\n })\n );\n } else {\n await Promise.all(\n matchedFiles.map(async (file) => {\n const directory = dirname(file);\n await fs.rm(directory, { recursive: true, force: true });\n })\n );\n }\n};\n\nexport const addFileToResource = async (\n catalogDir: string,\n id: string,\n file: { content: string; fileName: string },\n version?: string\n) => {\n const pathToResource = await findFileById(catalogDir, id, version);\n\n if (!pathToResource) throw new Error('Cannot find directory to write file to');\n\n let fileContent = file.content.trim();\n\n try {\n const json = JSON.parse(fileContent);\n fileContent = JSON.stringify(json, null, 2);\n } catch (error) {\n // Just silently fail if the file is not valid JSON\n // Write it as it is\n }\n\n fsSync.writeFileSync(join(dirname(pathToResource), file.fileName), fileContent);\n};\n\nexport const getFileFromResource = async (catalogDir: string, id: string, file: { fileName: string }, version?: string) => {\n const pathToResource = await findFileById(catalogDir, id, version);\n\n if (!pathToResource) throw new Error('Cannot find directory of resource');\n\n const exists = await fs\n .access(join(dirname(pathToResource), file.fileName))\n .then(() => true)\n .catch(() => false);\n if (!exists) throw new Error(`File ${file.fileName} does not exist in resource ${id} v(${version})`);\n\n return fsSync.readFileSync(join(dirname(pathToResource), file.fileName), 'utf-8');\n};\nexport const getVersionedDirectory = (sourceDirectory: string, version: any): string => {\n return join(sourceDirectory, 'versioned', version);\n};\n","import { globSync } from 'glob';\nimport fsSync from 'node:fs';\nimport { copy, CopyFilterAsync, CopyFilterSync } from 'fs-extra';\nimport { join, dirname, normalize, sep as pathSeparator, resolve, basename, relative } from 'node:path';\nimport matter from 'gray-matter';\nimport { satisfies, validRange, valid } from 'semver';\n\n/**\n * Returns true if a given version of a resource id exists in the catalog\n */\nexport const versionExists = async (catalogDir: string, id: string, version: string) => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n const matchedFiles = (await searchFilesForId(files, id, version)) || [];\n return matchedFiles.length > 0;\n};\n\nexport const findFileById = async (catalogDir: string, id: string, version?: string): Promise<string | undefined> => {\n const files = await getFiles(`${catalogDir}/**/index.{md,mdx}`);\n\n const matchedFiles = (await searchFilesForId(files, id)) || [];\n const latestVersion = matchedFiles.find((path) => !path.includes('versioned'));\n\n // If no version is provided, return the latest version\n if (!version) {\n return latestVersion;\n }\n\n // map files into gray matter to get versions\n const parsedFiles = matchedFiles.map((path) => {\n const { data } = matter.read(path);\n return { ...data, path };\n }) as any[];\n\n const semverRange = validRange(version);\n\n if (semverRange && valid(version)) {\n const match = parsedFiles.filter((c) => satisfies(c.version, semverRange));\n return match.length > 0 ? match[0].path : undefined;\n }\n\n // Order by version\n const sorted = parsedFiles.sort((a, b) => {\n return a.version.localeCompare(b.version);\n });\n\n // latest version\n const match = sorted.length > 0 ? [sorted[sorted.length - 1]] : [];\n\n if (match.length > 0) {\n return match[0].path;\n }\n};\n\nexport const getFiles = async (pattern: string, ignore: string | string[] = '') => {\n try {\n // 1. Normalize the input pattern to handle mixed separators potentially\n const normalizedInputPattern = normalize(pattern);\n\n // 2. Determine the absolute base directory (cwd for glob)\n // Resolve ensures it's absolute. Handles cases with/without globstar.\n const absoluteBaseDir = resolve(\n normalizedInputPattern.includes('**') ? normalizedInputPattern.split('**')[0] : dirname(normalizedInputPattern)\n );\n\n // 3. Determine the pattern part relative to the absolute base directory\n // We extract the part of the normalized pattern that comes *after* the absoluteBaseDir\n let relativePattern = relative(absoluteBaseDir, normalizedInputPattern);\n\n // On Windows, relative() might return empty string if paths are identical,\n // or might need normalization if the original pattern didn't have `**`\n // Example: pattern = 'dir/file.md', absoluteBaseDir='.../dir', normalized='...\\dir\\file.md'\n // relative() -> 'file.md'\n // Example: pattern = 'dir/**/file.md', absoluteBaseDir='.../dir', normalized='...\\dir\\**\\file.md'\n // relative() -> '**\\file.md'\n // Convert separators in the relative pattern to forward slashes for glob\n relativePattern = relativePattern.replace(/\\\\/g, '/');\n\n const ignoreList = Array.isArray(ignore) ? ignore : [ignore];\n\n const files = globSync(relativePattern, {\n cwd: absoluteBaseDir,\n ignore: ['node_modules/**', ...ignoreList],\n absolute: true,\n nodir: true,\n });\n\n // 5. Normalize results for consistency before returning\n return files.map(normalize);\n } catch (error: any) {\n // Add more diagnostic info to the error\n const absoluteBaseDirForError = resolve(\n normalize(pattern).includes('**') ? normalize(pattern).split('**')[0] : dirname(normalize(pattern))\n );\n const relativePatternForError = relative(absoluteBaseDirForError, normalize(pattern)).replace(/\\\\/g, '/');\n throw new Error(\n `Error finding files for pattern \"${pattern}\" (using cwd: \"${absoluteBaseDirForError}\", globPattern: \"${relativePatternForError}\"): ${error.message}`\n );\n }\n};\n\nexport const readMdxFile = async (path: string) => {\n const { data } = matter.read(path);\n const { markdown, ...frontmatter } = data;\n return { ...frontmatter, markdown };\n};\n\nexport const searchFilesForId = async (files: string[], id: string, version?: string) => {\n const idRegex = new RegExp(`^id:\\\\s*(['\"]|>-)?\\\\s*${id}['\"]?\\\\s*$`, 'm');\n const versionRegex = new RegExp(`^version:\\\\s*['\"]?${version}['\"]?\\\\s*$`, 'm');\n\n const matches = files.map((file) => {\n const content = fsSync.readFileSync(file, 'utf-8');\n const hasIdMatch = content.match(idRegex);\n\n // Check version if provided\n if (version && !content.match(versionRegex)) {\n return undefined;\n }\n\n if (hasIdMatch) {\n return file;\n }\n });\n\n return matches.filter(Boolean).filter((file) => file !== undefined);\n};\n\n/**\n * Function to copy a directory from source to target, uses a tmp directory\n * @param catalogDir\n * @param source\n * @param target\n * @param filter\n */\nexport const copyDir = async (catalogDir: string, source: string, target: string, filter?: CopyFilterAsync | CopyFilterSync) => {\n const tmpDirectory = join(catalogDir, 'tmp');\n fsSync.mkdirSync(tmpDirectory, { recursive: true });\n\n // Copy everything over\n await copy(source, tmpDirectory, {\n overwrite: true,\n filter,\n });\n\n await copy(tmpDirectory, target, {\n overwrite: true,\n filter,\n });\n\n // Remove the tmp directory\n fsSync.rmSync(tmpDirectory, { recursive: true });\n};\n\n// Makes sure values in sends/recieves are unique\nexport const uniqueVersions = (messages: { id: string; version: string }[]): { id: string; version: string }[] => {\n const uniqueSet = new Set();\n\n return messages.filter((message) => {\n const key = `${message.id}-${message.version}`;\n if (!uniqueSet.has(key)) {\n uniqueSet.add(key);\n return true;\n }\n return false;\n });\n};\n","import fs from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { findFileById } from './internal/utils';\nimport type { Event } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\n\n/**\n * Returns an event from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the event\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getEvent } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the event\n * const event = await getEvent('InventoryAdjusted');\n *\n * // Gets a version of the event\n * const event = await getEvent('InventoryAdjusted', '0.0.1');\n *\n * // Get the event with the schema attached\n * const event = await getEvent('InventoryAdjusted', '0.0.1', { attachSchema: true });\n * ```\n */\nexport const getEvent =\n (directory: string) =>\n async (id: string, version?: string, options?: { attachSchema?: boolean }): Promise<Event> =>\n getResource(directory, id, version, { type: 'event', ...options }) as Promise<Event>;\n\n/**\n * Returns all events from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the events.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getEvents } = utils('/path/to/eventcatalog');\n *\n * // Gets all events (and versions) from the catalog\n * const events = await getEvents();\n *\n * // Gets all events (only latest version) from the catalog\n * const events = await getEvents({ latestOnly: true });\n *\n * // Get all events with the schema attached\n * const events = await getEvents({ attachSchema: true });\n * ```\n */\nexport const getEvents =\n (directory: string) =>\n async (options?: { latestOnly?: boolean; attachSchema?: boolean }): Promise<Event[]> =>\n getResources(directory, { type: 'events', ...options }) as Promise<Event[]>;\n\n/**\n * Write an event to EventCatalog.\n *\n * You can optionally overide the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeEvent } = utils('/path/to/eventcatalog');\n *\n * // Write an event to the catalog\n * // Event would be written to events/InventoryAdjusted\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write an event to the catalog but override the path\n * // Event would be written to events/Inventory/InventoryAdjusted\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Inventory/InventoryAdjusted\"});\n *\n * // Write a event to the catalog and override the existing content (if there is any)\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a event to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeEvent({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeEvent =\n (directory: string) =>\n async (\n event: Event,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...event }, { ...options, type: 'event' });\n/**\n * Write an event to a service in EventCatalog.\n *\n * You can optionally override the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeEventToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Inventory/events/InventoryAdjusted\n * await writeEventToService({\n * id: 'InventoryAdjusted',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Inventory' });\n * ```\n */\nexport const writeEventToService =\n (directory: string) =>\n async (\n event: Event,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n\n let pathForEvent =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/events`\n : `${resourcePath.directory}/events`;\n pathForEvent = join(pathForEvent, event.id);\n await writeResource(directory, { ...event }, { ...options, path: pathForEvent, type: 'event' });\n };\n\n/**\n * Delete an event at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmEvent } = utils('/path/to/eventcatalog');\n *\n * // removes an event at the given path (events dir is appended to the given path)\n * // Removes the event at events/InventoryAdjusted\n * await rmEvent('/InventoryAdjusted');\n * ```\n */\nexport const rmEvent = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete an event by it's id.\n *\n * Optionally specify a version to delete a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmEventById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryAdjusted event\n * await rmEventById('InventoryAdjusted');\n *\n * // deletes a specific version of the InventoryAdjusted event\n * await rmEventById('InventoryAdjusted', '0.0.1');\n * ```\n */\nexport const rmEventById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) => {\n await rmResourceById(directory, id, version, { type: 'event', persistFiles });\n};\n\n/**\n * Version an event by it's id.\n *\n * Takes the latest event and moves it to a versioned directory.\n * All files with this event are also versioned (e.g /events/InventoryAdjusted/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionEvent } = utils('/path/to/eventcatalog');\n *\n * // moves the latest InventoryAdjusted event to a versioned directory\n * // the version within that event is used as the version number.\n * await versionEvent('InventoryAdjusted');\n *\n * ```\n */\nexport const versionEvent = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to an event by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToEvent } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest InventoryAdjusted event\n * await addFileToEvent('InventoryAdjusted', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the InventoryAdjusted event\n * await addFileToEvent('InventoryAdjusted', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToEvent =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to an event by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToEvent } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest InventoryAdjusted event\n * await addSchemaToEvent('InventoryAdjusted', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the InventoryAdjusted event\n * await addSchemaToEvent('InventoryAdjusted', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToEvent =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToEvent(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { eventHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await eventHasVersion('InventoryAdjusted', '0.0.1');\n * await eventHasVersion('InventoryAdjusted', 'latest');\n * await eventHasVersion('InventoryAdjusted', '0.0.x');*\n *\n * ```\n */\nexport const eventHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n","import fs from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Command } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\nimport { findFileById } from './internal/utils';\nimport { addMessageToService } from './services';\n\n/**\n * Returns a command from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the command\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getCommand } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the command\n * const command = await getCommand('UpdateInventory');\n *\n * // Gets a version of the command\n * const command = await getCommand('UpdateInventory', '0.0.1');\n *\n * // Gets the command with the schema attached\n * const command = await getCommand('UpdateInventory', '0.0.1', { attachSchema: true });\n * ```\n */\nexport const getCommand =\n (directory: string) =>\n async (id: string, version?: string, options?: { attachSchema?: boolean }): Promise<Command> =>\n getResource(directory, id, version, { type: 'command', ...options }) as Promise<Command>;\n\n/**\n * Returns all commands from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the events.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getCommands } = utils('/path/to/eventcatalog');\n *\n * // Gets all commands (and versions) from the catalog\n * const commands = await getCommands();\n *\n * // Gets all commands (only latest version) from the catalog\n * const commands = await getCommands({ latestOnly: true });\n *\n * // Gets all commands with the schema attached\n * const commands = await getCommands({ attachSchema: true });\n * ```\n */\nexport const getCommands =\n (directory: string) =>\n async (options?: { latestOnly?: boolean; attachSchema?: boolean }): Promise<Command[]> =>\n getResources(directory, { type: 'commands', ...options }) as Promise<Command[]>;\n\n/**\n * Write a command to EventCatalog.\n *\n * You can optionally override the path of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeCommand } = utils('/path/to/eventcatalog');\n *\n * // Write a command to the catalog\n * // Command would be written to commands/UpdateInventory\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write a command to the catalog but override the path\n * // Command would be written to commands/Inventory/UpdateInventory\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Inventory/UpdateInventory\"});\n *\n * // Write a command to the catalog and override the existing content (if there is any)\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a command to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeCommand({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeCommand =\n (directory: string) =>\n async (\n command: Command,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...command }, { ...options, type: 'command' });\n\n/**\n * Write an command to a service in EventCatalog.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeCommandToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Inventory/commands/UpdateInventory\n * await writeCommandToService({\n * id: 'UpdateInventory',\n * name: 'Update Inventory',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Inventory' });\n * ```\n */\nexport const writeCommandToService =\n (directory: string) =>\n async (\n command: Command,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n\n let pathForCommand =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/commands`\n : `${resourcePath.directory}/commands`;\n pathForCommand = join(pathForCommand, command.id);\n\n await writeResource(directory, { ...command }, { ...options, path: pathForCommand, type: 'command' });\n };\n\n/**\n * Delete a command at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmCommand } = utils('/path/to/eventcatalog');\n *\n * // removes a command at the given path (commands dir is appended to the given path)\n * // Removes the command at commands/UpdateInventory\n * await rmCommand('/UpdateInventory');\n * ```\n */\nexport const rmCommand = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a command by it's id.\n *\n * Optionally specify a version to delete a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmCommandById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest UpdateInventory command\n * await rmCommandById('UpdateInventory');\n *\n * // deletes a specific version of the UpdateInventory command\n * await rmCommandById('UpdateInventory', '0.0.1');\n * ```\n */\nexport const rmCommandById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) =>\n rmResourceById(directory, id, version, { type: 'command', persistFiles });\n\n/**\n * Version a command by it's id.\n *\n * Takes the latest command and moves it to a versioned directory.\n * All files with this command are also versioned (e.g /commands/UpdateInventory/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionCommand } = utils('/path/to/eventcatalog');\n *\n * // moves the latest UpdateInventory command to a versioned directory\n * // the version within that command is used as the version number.\n * await versionCommand('UpdateInventory');\n *\n * ```\n */\nexport const versionCommand = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to a command by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToCommand } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest UpdateInventory command\n * await addFileToCommand('UpdateInventory', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the UpdateInventory command\n * await addFileToCommand('UpdateInventory', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToCommand =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to a command by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToCommand } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest UpdateInventory command\n * await addSchemaToCommand('UpdateInventory', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the UpdateInventory command\n * await addSchemaToCommand('UpdateInventory', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToCommand =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToCommand(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given command.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { commandHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await commandHasVersion('InventoryAdjusted', '0.0.1');\n * await commandHasVersion('InventoryAdjusted', 'latest');\n * await commandHasVersion('InventoryAdjusted', '0.0.x');*\n *\n * ```\n */\nexport const commandHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n","import fs from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { findFileById } from './internal/utils';\nimport type { Query } from './types';\nimport {\n addFileToResource,\n getResource,\n getResourcePath,\n getResources,\n rmResourceById,\n versionResource,\n writeResource,\n} from './internal/resources';\n\n/**\n * Returns a query from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the query\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getQuery } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the event\n * const event = await getQuery('GetOrder');\n *\n * // Gets a version of the event\n * const event = await getQuery('GetOrder', '0.0.1');\n *\n * // Gets the query with the schema attached\n * const event = await getQuery('GetOrder', '0.0.1', { attachSchema: true });\n * ```\n */\nexport const getQuery =\n (directory: string) =>\n async (id: string, version?: string, options?: { attachSchema?: boolean }): Promise<Query> =>\n getResource(directory, id, version, { type: 'query', ...options }) as Promise<Query>;\n\n/**\n * Write a query to EventCatalog.\n *\n * You can optionally override the path of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeQuery } = utils('/path/to/eventcatalog');\n *\n * // Write an event to the catalog\n * // Event would be written to queries/GetOrder\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * });\n *\n * // Write an event to the catalog but override the path\n * // Event would be written to queries/Inventory/GetOrder\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Orders/GetOrder\"});\n *\n * // Write a query to the catalog and override the existing content (if there is any)\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { override: true });\n *\n * // Write a query to the catalog and version the previous version\n * // only works if the new version is greater than the previous version\n * await writeQuery({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { versionExistingContent: true });\n *\n * ```\n */\nexport const writeQuery =\n (directory: string) =>\n async (\n query: Query,\n options: { path?: string; override?: boolean; versionExistingContent?: boolean; format?: 'md' | 'mdx' } = {\n path: '',\n override: false,\n versionExistingContent: false,\n format: 'mdx',\n }\n ) =>\n writeResource(directory, { ...query }, { ...options, type: 'query' });\n\n/**\n * Returns all queries from EventCatalog.\n *\n * You can optionally specify if you want to get the latest version of the queries.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getQueries } = utils('/path/to/eventcatalog');\n *\n * // Gets all queries (and versions) from the catalog\n * const queries = await getQueries();\n *\n * // Gets all queries (only latest version) from the catalog\n * const queries = await getQueries({ latestOnly: true });\n *\n * // Gets all queries with the schema attached\n * const queries = await getQueries({ attachSchema: true });\n * ```\n */\nexport const getQueries =\n (directory: string) =>\n async (options?: { latestOnly?: boolean; attachSchema?: boolean }): Promise<Query[]> =>\n getResources(directory, { type: 'queries', ...options }) as Promise<Query[]>;\n\n/**\n * Write a query to a service in EventCatalog.\n *\n * You can optionally override the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeQueryToService } = utils('/path/to/eventcatalog');\n *\n * // Write an event to a given service in the catalog\n * // Event would be written to services/Orders/queries/GetOrder\n * await writeQueryToService({\n * id: 'GetOrder',\n * name: 'Get Order',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { id: 'Orders' });\n * ```\n */\nexport const writeQueryToService =\n (directory: string) =>\n async (\n query: Query,\n service: { id: string; version?: string },\n options: { path?: string; format?: 'md' | 'mdx'; override?: boolean } = { path: '', format: 'mdx', override: false }\n ) => {\n const resourcePath = await getResourcePath(directory, service.id, service.version);\n if (!resourcePath) {\n throw new Error('Service not found');\n }\n let pathForQuery =\n service.version && service.version !== 'latest'\n ? `${resourcePath.directory}/versioned/${service.version}/queries`\n : `${resourcePath.directory}/queries`;\n pathForQuery = join(pathForQuery, query.id);\n await writeResource(directory, { ...query }, { ...options, path: pathForQuery, type: 'query' });\n };\n\n/**\n * Delete a query at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmQuery } = utils('/path/to/eventcatalog');\n *\n * // removes an query at the given path (queries dir is appended to the given path)\n * // Removes the query at queries/GetOrders\n * await rmQuery('/GetOrders');\n * ```\n */\nexport const rmQuery = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a query by it's id.\n *\n * Optionally specify a version to delete a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmQueryById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryAdjusted query\n * await rmQueryById('GetOrder');\n *\n * // deletes a specific version of the GetOrder query\n * await rmQueryById('GetOrder', '0.0.1');\n * ```\n */\nexport const rmQueryById = (directory: string) => async (id: string, version?: string, persistFiles?: boolean) => {\n await rmResourceById(directory, id, version, { type: 'query', persistFiles });\n};\n\n/**\n * Version a query by it's id.\n *\n * Takes the latest query and moves it to a versioned directory.\n * All files with this query are also versioned (e.g /queries/GetOrder/schema.json)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionQuery } = utils('/path/to/eventcatalog');\n *\n * // moves the latest GetOrder query to a versioned directory\n * // the version within that query is used as the version number.\n * await versionQuery('GetOrder');\n *\n * ```\n */\nexport const versionQuery = (directory: string) => async (id: string) => versionResource(directory, id);\n\n/**\n * Add a file to a query by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToQuery } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest GetOrder query\n * await addFileToQuery('GetOrder', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the GetOrder query\n * await addFileToQuery('GetOrder', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToQuery =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) =>\n addFileToResource(directory, id, file, version);\n\n/**\n * Add a schema to a query by it's id.\n *\n * Optionally specify a version to add a schema to a specific version of the query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addSchemaToQuery } = utils('/path/to/eventcatalog');\n *\n * // JSON schema example\n * const schema = {\n * \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n * \"type\": \"object\",\n * \"properties\": {\n * \"name\": {\n * \"type\": \"string\"\n * },\n * \"age\": {\n * \"type\": \"number\"\n * }\n * },\n * \"required\": [\"name\", \"age\"]\n * };\n *\n * // adds a schema to the latest GetOrder query\n * await addSchemaToQuery('GetOrder', { schema, fileName: 'schema.json' });\n *\n * // adds a file to a specific version of the GetOrder query\n * await addSchemaToQuery('GetOrder', { schema, fileName: 'schema.json' }, '0.0.1');\n *\n * ```\n */\nexport const addSchemaToQuery =\n (directory: string) => async (id: string, schema: { schema: string; fileName: string }, version?: string) => {\n await addFileToQuery(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);\n };\n\n/**\n * Check to see if the catalog has a version for the given query.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { queryHasVersion } = utils('/path/to/eventcatalog');\n *\n * // returns true if version is found for the given event and version (supports semver)\n * await queryHasVersion('GetOrder', '0.0.1');\n * await queryHasVersion('GetOrder', 'latest');\n * await queryHasVersion('GetOrder', '0.0.x');*\n *\n * ```\n */\nexport const queryHasVersion = (directory: string) => async (id: string, version?: string) => {\n const file = await findFileById(directory, id, version);\n return !!file;\n};\n"],"mappings":"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","names":["import_promises","import_node_path","matter","match","fsSync","import_gray_matter","import_node_fs","import_semver","matter","fsSync","fs","file","import_promises","import_node_path","import_promises","import_node_path","import_promises","import_node_path","fs"]}
|
package/dist/channels.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// src/channels.ts
|
|
2
|
-
import
|
|
3
|
-
import { join as
|
|
2
|
+
import fs5 from "fs/promises";
|
|
3
|
+
import { join as join6, extname } from "path";
|
|
4
4
|
|
|
5
5
|
// src/internal/resources.ts
|
|
6
6
|
import { dirname as dirname2, join as join2 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/internal/utils.ts
|
|
9
9
|
import { globSync } from "glob";
|
|
10
|
-
import fsSync from "
|
|
10
|
+
import fsSync from "fs";
|
|
11
11
|
import { copy } from "fs-extra";
|
|
12
|
-
import { join, dirname, normalize, resolve, relative } from "
|
|
12
|
+
import { join, dirname, normalize, resolve, relative } from "path";
|
|
13
13
|
import matter from "gray-matter";
|
|
14
14
|
import { satisfies, validRange, valid } from "semver";
|
|
15
15
|
var versionExists = async (catalogDir, id, version) => {
|
|
@@ -98,8 +98,8 @@ var copyDir = async (catalogDir, source, target, filter) => {
|
|
|
98
98
|
|
|
99
99
|
// src/internal/resources.ts
|
|
100
100
|
import matter2 from "gray-matter";
|
|
101
|
-
import fs from "
|
|
102
|
-
import fsSync2 from "
|
|
101
|
+
import fs from "fs/promises";
|
|
102
|
+
import fsSync2 from "fs";
|
|
103
103
|
import { satisfies as satisfies2 } from "semver";
|
|
104
104
|
import { lock, unlock } from "proper-lockfile";
|
|
105
105
|
var versionResource = async (catalogDir, id) => {
|
|
@@ -170,9 +170,22 @@ var writeResource = async (catalogDir, resource, options = {
|
|
|
170
170
|
}
|
|
171
171
|
};
|
|
172
172
|
var getResource = async (catalogDir, id, version, options) => {
|
|
173
|
+
const attachSchema = options?.attachSchema || false;
|
|
173
174
|
const file = await findFileById(catalogDir, id, version);
|
|
174
175
|
if (!file) return;
|
|
175
176
|
const { data, content } = matter2.read(file);
|
|
177
|
+
if (attachSchema && data?.schemaPath) {
|
|
178
|
+
const resourceDirectory = dirname2(file);
|
|
179
|
+
const pathToSchema = join2(resourceDirectory, data.schemaPath);
|
|
180
|
+
if (fsSync2.existsSync(pathToSchema)) {
|
|
181
|
+
const schema = fsSync2.readFileSync(pathToSchema, "utf8");
|
|
182
|
+
try {
|
|
183
|
+
data.schema = JSON.parse(schema);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
data.schema = schema;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
176
189
|
return {
|
|
177
190
|
...data,
|
|
178
191
|
markdown: content.trim()
|
|
@@ -191,7 +204,8 @@ var getResources = async (catalogDir, {
|
|
|
191
204
|
type,
|
|
192
205
|
latestOnly = false,
|
|
193
206
|
ignore = [],
|
|
194
|
-
pattern = ""
|
|
207
|
+
pattern = "",
|
|
208
|
+
attachSchema = false
|
|
195
209
|
}) => {
|
|
196
210
|
const ignoreList = latestOnly ? `**/versioned/**` : "";
|
|
197
211
|
const filePattern = pattern || `${catalogDir}/**/${type}/**/index.{md,mdx}`;
|
|
@@ -199,6 +213,18 @@ var getResources = async (catalogDir, {
|
|
|
199
213
|
if (files.length === 0) return;
|
|
200
214
|
return files.map((file) => {
|
|
201
215
|
const { data, content } = matter2.read(file);
|
|
216
|
+
if (attachSchema && data?.schemaPath) {
|
|
217
|
+
const resourceDirectory = dirname2(file);
|
|
218
|
+
const pathToSchema = join2(resourceDirectory, data.schemaPath);
|
|
219
|
+
if (fsSync2.existsSync(pathToSchema)) {
|
|
220
|
+
const schema = fsSync2.readFileSync(pathToSchema, "utf8");
|
|
221
|
+
try {
|
|
222
|
+
data.schema = JSON.parse(schema);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
data.schema = schema;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
202
228
|
return {
|
|
203
229
|
...data,
|
|
204
230
|
markdown: content.trim()
|
|
@@ -231,7 +257,9 @@ var getVersionedDirectory = (sourceDirectory, version) => {
|
|
|
231
257
|
};
|
|
232
258
|
|
|
233
259
|
// src/events.ts
|
|
234
|
-
|
|
260
|
+
import fs2 from "fs/promises";
|
|
261
|
+
import { join as join3 } from "path";
|
|
262
|
+
var getEvent = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "event", ...options });
|
|
235
263
|
var writeEvent = (directory) => async (event, options = {
|
|
236
264
|
path: "",
|
|
237
265
|
override: false,
|
|
@@ -242,7 +270,9 @@ var rmEventById = (directory) => async (id, version, persistFiles) => {
|
|
|
242
270
|
};
|
|
243
271
|
|
|
244
272
|
// src/commands.ts
|
|
245
|
-
|
|
273
|
+
import fs3 from "fs/promises";
|
|
274
|
+
import { join as join4 } from "path";
|
|
275
|
+
var getCommand = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "command", ...options });
|
|
246
276
|
var writeCommand = (directory) => async (command, options = {
|
|
247
277
|
path: "",
|
|
248
278
|
override: false,
|
|
@@ -252,7 +282,9 @@ var writeCommand = (directory) => async (command, options = {
|
|
|
252
282
|
var rmCommandById = (directory) => async (id, version, persistFiles) => rmResourceById(directory, id, version, { type: "command", persistFiles });
|
|
253
283
|
|
|
254
284
|
// src/queries.ts
|
|
255
|
-
|
|
285
|
+
import fs4 from "fs/promises";
|
|
286
|
+
import { join as join5 } from "path";
|
|
287
|
+
var getQuery = (directory) => async (id, version, options) => getResource(directory, id, version, { type: "query", ...options });
|
|
256
288
|
var writeQuery = (directory) => async (query, options = {
|
|
257
289
|
path: "",
|
|
258
290
|
override: false,
|
|
@@ -268,7 +300,7 @@ var getChannel = (directory) => async (id, version) => getResource(directory, id
|
|
|
268
300
|
var getChannels = (directory) => async (options) => getResources(directory, { type: "channels", ...options });
|
|
269
301
|
var writeChannel = (directory) => async (channel, options = { path: "" }) => writeResource(directory, { ...channel }, { ...options, type: "channel" });
|
|
270
302
|
var rmChannel = (directory) => async (path) => {
|
|
271
|
-
await
|
|
303
|
+
await fs5.rm(join6(directory, path), { recursive: true });
|
|
272
304
|
};
|
|
273
305
|
var rmChannelById = (directory) => async (id, version, persistFiles) => rmResourceById(directory, id, version, { type: "channel", persistFiles });
|
|
274
306
|
var versionChannel = (directory) => async (id) => versionResource(directory, id);
|
|
@@ -310,7 +342,7 @@ var addMessageToChannel = (directory, collection) => async (id, _message, versio
|
|
|
310
342
|
throw new Error(`Cannot find message ${id} in the catalog`);
|
|
311
343
|
}
|
|
312
344
|
const path = existingResource.split(`/${collection}`)[0];
|
|
313
|
-
const pathToResource =
|
|
345
|
+
const pathToResource = join6(path, collection);
|
|
314
346
|
await rmMessageById(directory)(_message.id, _message.version, true);
|
|
315
347
|
await writeMessage(pathToResource)(message, { format: extension === ".md" ? "md" : "mdx" });
|
|
316
348
|
};
|