UNPKG

arvo-core

Version:

The core Arvo package which provides application tier core primitives and contract system for building production-grade event-driven application. Provides ArvoEvent (CloudEvents-compliant), ArvoContract for type-safe service interfaces, event factories, O

240 lines (239 loc) 9.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var OpenTelemetry_1 = require("../OpenTelemetry"); var schema_1 = require("../schema"); var utils_1 = require("../utils"); var VersionedArvoContract_1 = require("./VersionedArvoContract"); var WildCardArvoSemanticVersion_1 = require("./WildCardArvoSemanticVersion"); var validators_1 = require("./validators"); /** * Represents a contract with defined input and output schemas for event-driven architectures. * The ArvoContract class provides type-safe validation and versioning capabilities for event handling, * ensuring consistency in message passing between different parts of the system. * * @example * ```typescript * const contract = createArvoContract({ * uri: '#/my/service/data', * type: 'com.process.data', * description: 'An example contract', * metadata: { * visibility: "public" * } * versions: { * '1.0.0': { * accepts: z.object({ data: z.string() }), * emits: { * 'data.processed': z.object({ result: z.string() }) * } * }, * '2.0.0': { * accepts: z.object({ data: z.number() }), * emits: { * 'data.processed': z.object({ result: z.number() }) * } * } * } * }); * ``` */ var ArvoContract = /** @class */ (function () { /** * Creates a new ArvoContract instance with validated parameters. * * @param params - Contract configuration parameters * * @throws {Error} When URI format is invalid * @throws {Error} When event type format is invalid * @throws {Error} When version string is not valid semantic version * @throws {Error} When version is a reserved wildcard version * @throws {Error} When emit type format is invalid * @throws {Error} When no versions are provided * @throws {Error} When domain does not have follow the condition Domain must contain only lowercase letters, numbers, and dots */ function ArvoContract(params) { var _a; validators_1.ArvoContractValidators.contract.uri.parse(params.uri); validators_1.ArvoContractValidators.record.type.parse(params.type); validators_1.ArvoContractValidators.contract.domain.parse(params.domain); this._uri = params.uri; this._type = params.type; this._versions = params.versions; this._description = (_a = params.description) !== null && _a !== void 0 ? _a : null; this._metadata = params.metadata; this._domain = params.domain; for (var _i = 0, _b = Object.entries(params.versions); _i < _b.length; _i++) { var _c = _b[_i], version = _c[0], versionContract = _c[1]; schema_1.ArvoSemanticVersionSchema.parse(version); if ((0, WildCardArvoSemanticVersion_1.isWildCardArvoSematicVersion)(version)) { throw new Error("For contract (uri=".concat(params.uri, "), the version cannot be '").concat(WildCardArvoSemanticVersion_1.WildCardArvoSemanticVersion, "'. It is a reserved version type.")); } for (var _d = 0, _e = Object.keys(versionContract.emits); _d < _e.length; _d++) { var emitType = _e[_d]; validators_1.ArvoContractValidators.record.type.parse(emitType); } } if (!Object.keys(this._versions).length) { throw new Error("An ArvoContract (uri=".concat(this._uri, ") must have at least one version")); } } Object.defineProperty(ArvoContract.prototype, "uri", { get: function () { return this._uri; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "type", { get: function () { return this._type; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "versions", { get: function () { return this._versions; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "description", { get: function () { return this._description; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "metadata", { get: function () { return this._metadata; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "domain", { get: function () { return this._domain; }, enumerable: false, configurable: true }); Object.defineProperty(ArvoContract.prototype, "systemError", { /** * Gets the system error event specification for this contract. * System errors follow a standardized format to handle exceptional conditions * and failures in a consistent way across all contracts. * * The error schema includes: * - errorName: The name/type of the error * - errorMessage: A descriptive message about what went wrong * - errorStack: Optional stack trace information (null if not available) * * System errors are special events that: * - Are automatically prefixed with 'sys.' and suffixed with '.error' * - Use a standardized schema across all contracts * - Can capture error details, messages, and stack traces * - Are version-independent (work the same across all contract versions) */ get: function () { return { type: "sys.".concat(this._type, ".error"), schema: schema_1.ArvoErrorSchema, }; }, enumerable: false, configurable: true }); /** * Retrieves a specific version of the contract or resolves special version identifiers. * * @param option - Version identifier or special version string * - Specific version (e.g., "1.0.0") * - "latest" or "any" for the most recent version * - "oldest" for the first version * * @returns A versioned contract instance with type-safe schemas * * @throws {Error} When an invalid or non-existent version is requested */ ArvoContract.prototype.version = function (option) { var resolvedVersion; if (option === 'any' || option === 'latest') { resolvedVersion = this.getSortedVersionNumbers('DESC')[0]; } else if (option === 'oldest') { resolvedVersion = this.getSortedVersionNumbers('ASC')[0]; // @ts-ignore } else if (!this._versions[option]) { throw new Error("The contract (uri=".concat(this._uri, ") does not have version=").concat(option)); } else { resolvedVersion = option; } return new VersionedArvoContract_1.VersionedArvoContract({ contract: this, version: resolvedVersion, }); // needed due to TypeScript limitations with conditional types }; /** * Retrieves version numbers in sorted order based on semantic versioning rules. * @returns Array of semantic versions sorted according to specified ordering */ ArvoContract.prototype.getSortedVersionNumbers = function (ordering) { var sorted = Object.keys(this._versions).sort(function (a, b) { return (0, utils_1.compareSemanticVersions)(b, a); }); return ordering === 'DESC' ? sorted : sorted.reverse(); }; /** * Exports the ArvoContract instance as a plain object conforming to the IArvoContract interface. * This method can be used to serialize the contract or to create a new instance with the same parameters. */ ArvoContract.prototype.export = function () { return { uri: this._uri, type: this._type, domain: this._domain, description: this._description, versions: this._versions, metadata: this._metadata, }; }; /** * Converts the ArvoContract instance to a JSON Schema representation. * This method provides a way to represent the contract's structure and validation rules * in a format that conforms to the JSON Schema specification. */ ArvoContract.prototype.toJsonSchema = function () { var _this = this; try { return { uri: this._uri, domain: this._domain, description: this._description, metadata: this._metadata, versions: Object.keys(this._versions).map(function (version) { var jsonSchema = _this.version(version).toJsonSchema(); return { domain: jsonSchema.domain, version: jsonSchema.version, accepts: jsonSchema.accepts, systemError: jsonSchema.systemError, emits: jsonSchema.emits, metadata: jsonSchema.metadata, }; }), }; } catch (e) { var errorMessage = "ArvoContract.toJsonSchema failed: ".concat(e.message); (0, OpenTelemetry_1.logToSpan)({ level: 'ERROR', message: errorMessage, }); throw new Error(errorMessage); } }; return ArvoContract; }()); exports.default = ArvoContract;