arvo-core 1.2.2 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/ArvoContract/helpers.d.ts +119 -20
  3. package/dist/ArvoContract/helpers.js +150 -32
  4. package/dist/ArvoContract/index.d.ts +32 -26
  5. package/dist/ArvoContract/index.js +69 -60
  6. package/dist/ArvoContract/types.d.ts +49 -35
  7. package/dist/ArvoEvent/schema.d.ts +2 -2
  8. package/dist/ArvoEventFactory/helpers.d.ts +39 -9
  9. package/dist/ArvoEventFactory/helpers.js +50 -8
  10. package/dist/ArvoEventFactory/index.d.ts +60 -33
  11. package/dist/ArvoEventFactory/index.js +62 -36
  12. package/dist/ArvoOrchestrationSubject/index.d.ts +5 -4
  13. package/dist/ArvoOrchestrationSubject/index.js +2 -2
  14. package/dist/ArvoOrchestrationSubject/schema.d.ts +1 -2
  15. package/dist/ArvoOrchestrationSubject/schema.js +4 -11
  16. package/dist/ArvoOrchestrationSubject/type.d.ts +2 -12
  17. package/dist/ArvoOrchestratorContract/index.d.ts +62 -56
  18. package/dist/ArvoOrchestratorContract/index.js +99 -93
  19. package/dist/ArvoOrchestratorContract/types.d.ts +64 -71
  20. package/dist/index.d.ts +14 -18
  21. package/dist/index.js +12 -14
  22. package/dist/schema.d.ts +1 -0
  23. package/dist/schema.js +6 -1
  24. package/dist/types.d.ts +107 -81
  25. package/dist/utils.d.ts +21 -0
  26. package/dist/utils.js +33 -0
  27. package/package.json +1 -1
  28. package/dist/ArvoContractLibrary/helpers.d.ts +0 -10
  29. package/dist/ArvoContractLibrary/helpers.js +0 -22
  30. package/dist/ArvoContractLibrary/index.d.ts +0 -61
  31. package/dist/ArvoContractLibrary/index.js +0 -87
  32. package/dist/ArvoOrchestratorContract/helpers.d.ts +0 -67
  33. package/dist/ArvoOrchestratorContract/helpers.js +0 -101
package/CHANGELOG.md CHANGED
@@ -68,3 +68,7 @@
68
68
 
69
69
  - Added mandatory parent chaining in orchestration events so the process chaining and orchestration chaining can be traced
70
70
 
71
+ ## [2.0.0] - 2024-11-24
72
+
73
+ - Added version support for contracts and simplified orchestrator contracts
74
+
@@ -1,33 +1,132 @@
1
1
  import { IArvoContract } from './types';
2
2
  import ArvoContract from '.';
3
+ import { ArvoSemanticVersion } from '../types';
4
+ import { z } from 'zod';
3
5
  /**
4
- * Infers the ArvoContract type from a given IArvoContract.
6
+ * Infers the ArvoContract type from a given IArvoContract interface.
7
+ *
8
+ * @template T - The IArvoContract interface to infer from
5
9
  */
6
- export type InferArvoContract<T> = T extends IArvoContract<infer S, infer U, infer V, infer W> ? ArvoContract<S, U, V, W> : never;
10
+ type InferArvoContract<T> = T extends IArvoContract<infer Uri, infer Type, infer Versions> ? ArvoContract<Uri, Type, Versions> : never;
7
11
  /**
8
- * Creates an ArvoContract instance from the given contract specification.
12
+ * Creates and validates an ArvoContract instance from a contract specification.
9
13
  *
10
- * This function provides a convenient way to create and initialize an ArvoContract
11
- * with proper type inference.
14
+ * @template TContract - The contract specification type, must extend IArvoContract
15
+ * @param contract - The contract specification object containing URI, type, and versioned schemas
16
+ * @throws {Error} If any event type uses the reserved orchestrator prefix
17
+ * @throws {Error} If URI or event types fail validation
18
+ * @returns A properly typed ArvoContract instance
12
19
  *
13
- * @template TContract - The type of the contract specification.
20
+ * @example
21
+ * ```typescript
22
+ * const contract = createArvoContract({
23
+ * uri: 'com.example.contract',
24
+ * type: 'input.event',
25
+ * versions: {
26
+ * '0.0.1': {
27
+ * accepts: z.object({ data: z.string() }),
28
+ * emits: {
29
+ * 'output.event': z.object({ result: z.number() })
30
+ * }
31
+ * }
32
+ * }
33
+ * });
34
+ * ```
35
+ */
36
+ export declare const createArvoContract: <const TContract extends IArvoContract>(contract: TContract, isOrchestrationContract?: boolean) => InferArvoContract<TContract>;
37
+ /**
38
+ * Creates a simplified ArvoContract with standardized type prefixes and emit patterns.
39
+ * This is a convenience function that automatically formats event types according to conventions:
40
+ * - Accept types are prefixed with "com."
41
+ * - Emit types are prefixed with "evt." and suffixed with ".success"
42
+ *
43
+ * @template TUri - The URI type for the contract
44
+ * @template TType - The base type name (without prefixes) for the contract
45
+ * @template TVersions - Record of versions containing accept and emit schemas
14
46
  *
15
- * @param contract - The contract specification object.
16
- * This should include the URI, accepts, and emits properties as defined in IArvoContract.
47
+ * @param param - The configuration object for creating the contract
48
+ * @param param.uri - The URI identifying the contract
49
+ * @param param.type - The base type name (will be prefixed with "com.")
50
+ * @param param.versions - Version-specific schema definitions
51
+ * @param param.versions[version].accepts - Zod schema for validating incoming events
52
+ * @param param.versions[version].emits - Zod schema for validating outgoing events
17
53
  *
18
- * @returns The created ArvoContract instance.
19
- * The returned type is inferred from the input contract specification.
54
+ * @returns An ArvoContract instance with standardized type formatting:
55
+ * - Accept type will be "com.[type]"
56
+ * - Emit type will be "evt.[type].success"
20
57
  *
21
58
  * @example
22
- * const myContract = createArvoContract({
23
- * uri: 'https://example.com/contracts/myContract',
24
- * accepts: {
25
- * type: 'com.example.input',
26
- * schema: z.object({ name: z.string() }),
27
- * },
28
- * emits: {
29
- * 'com.example.output': z.object({ result: z.number() }),
30
- * },
59
+ * ```typescript
60
+ * const contract = createSimpleArvoContract({
61
+ * uri: 'example.com/contracts/processor',
62
+ * type: 'document.process',
63
+ * versions: {
64
+ * '1.0.0': {
65
+ * accepts: z.object({
66
+ * documentId: z.string(),
67
+ * options: z.object({ format: z.string() })
68
+ * }),
69
+ * emits: z.object({
70
+ * processedDocument: z.string(),
71
+ * metadata: z.object({ size: z.number() })
72
+ * })
73
+ * }
74
+ * }
31
75
  * });
76
+ *
77
+ * // Results in a contract where:
78
+ * // - Accept type is "com.document.process"
79
+ * // - Emit type is "evt.document.process.success"
80
+ * ```
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // Multiple versions example
85
+ * const contract = createSimpleArvoContract({
86
+ * uri: 'api.example/contracts/user',
87
+ * type: 'user.create',
88
+ * versions: {
89
+ * '1.0.0': {
90
+ * accepts: z.object({ name: z.string() }),
91
+ * emits: z.object({ id: z.string() })
92
+ * },
93
+ * '2.0.0': {
94
+ * accepts: z.object({
95
+ * name: z.string(),
96
+ * email: z.string().email()
97
+ * }),
98
+ * emits: z.object({
99
+ * id: z.string(),
100
+ * created: z.date()
101
+ * })
102
+ * }
103
+ * }
104
+ * });
105
+ * ```
106
+ *
107
+ * @remarks
108
+ * This function simplifies contract creation by:
109
+ * 1. Automatically prefixing accept types with "com."
110
+ * 2. Creating a single emit type prefixed with "evt." and suffixed with ".success"
111
+ * 3. Maintaining type safety and schema validation
112
+ *
113
+ * Use this when you have a simple contract pattern with:
114
+ * - A single accept type
115
+ * - A single success emit type
116
+ * - Standard type naming conventions
117
+ *
118
+ * For more complex contracts with multiple emit types or custom type naming,
119
+ * use {@link createArvoContract} instead.
32
120
  */
33
- export declare const createArvoContract: <const TContract extends IArvoContract>(contract: TContract) => InferArvoContract<TContract>;
121
+ export declare const createSimpleArvoContract: <TUri extends string, TType extends string, TVersions extends Record<ArvoSemanticVersion, {
122
+ accepts: z.ZodTypeAny;
123
+ emits: z.ZodTypeAny;
124
+ }>>(param: {
125
+ uri: TUri;
126
+ type: TType;
127
+ versions: TVersions;
128
+ }) => ArvoContract<TUri, `com.${TType}`, { [V in ArvoSemanticVersion & keyof TVersions]: {
129
+ accepts: TVersions[V]["accepts"];
130
+ emits: { [K in `evt.${TType}.succes`]: TVersions[V]["emits"]; };
131
+ }; }>;
132
+ export {};
@@ -3,52 +3,170 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createArvoContract = void 0;
6
+ exports.createSimpleArvoContract = exports.createArvoContract = void 0;
7
7
  var _1 = __importDefault(require("."));
8
8
  var typegen_1 = require("../ArvoOrchestratorContract/typegen");
9
9
  var utils_1 = require("../utils");
10
+ var validators_1 = require("./validators");
11
+ var schema_1 = require("../schema");
12
+ var ArvoOrchestrationSubject_1 = __importDefault(require("../ArvoOrchestrationSubject"));
10
13
  /**
11
- * Creates an ArvoContract instance from the given contract specification.
14
+ * Creates and validates an ArvoContract instance from a contract specification.
12
15
  *
13
- * This function provides a convenient way to create and initialize an ArvoContract
14
- * with proper type inference.
15
- *
16
- * @template TContract - The type of the contract specification.
17
- *
18
- * @param contract - The contract specification object.
19
- * This should include the URI, accepts, and emits properties as defined in IArvoContract.
20
- *
21
- * @returns The created ArvoContract instance.
22
- * The returned type is inferred from the input contract specification.
16
+ * @template TContract - The contract specification type, must extend IArvoContract
17
+ * @param contract - The contract specification object containing URI, type, and versioned schemas
18
+ * @throws {Error} If any event type uses the reserved orchestrator prefix
19
+ * @throws {Error} If URI or event types fail validation
20
+ * @returns A properly typed ArvoContract instance
23
21
  *
24
22
  * @example
25
- * const myContract = createArvoContract({
26
- * uri: 'https://example.com/contracts/myContract',
27
- * accepts: {
28
- * type: 'com.example.input',
29
- * schema: z.object({ name: z.string() }),
30
- * },
31
- * emits: {
32
- * 'com.example.output': z.object({ result: z.number() }),
33
- * },
23
+ * ```typescript
24
+ * const contract = createArvoContract({
25
+ * uri: 'com.example.contract',
26
+ * type: 'input.event',
27
+ * versions: {
28
+ * '0.0.1': {
29
+ * accepts: z.object({ data: z.string() }),
30
+ * emits: {
31
+ * 'output.event': z.object({ result: z.number() })
32
+ * }
33
+ * }
34
+ * }
34
35
  * });
36
+ * ```
35
37
  */
36
- var createArvoContract = function (contract) {
37
- var createErrorMessage = function (source, type) {
38
- return (0, utils_1.cleanString)("\n In contract (uri=".concat(contract.uri, "), the '").concat(source, "' event (type=").concat(type, ") must not start \n with '").concat(typegen_1.ArvoOrchestratorEventTypeGen.prefix, "' becuase this a reserved pattern \n for Arvo orchestrators.\n "));
38
+ var createArvoContract = function (contract, isOrchestrationContract) {
39
+ if (isOrchestrationContract === void 0) { isOrchestrationContract = false; }
40
+ var createErrorMessage = function (source, type, version) {
41
+ var versionString = version ? ", version=".concat(version) : '';
42
+ return (0, utils_1.cleanString)("\n In contract (uri=".concat(contract.uri).concat(versionString, "), the '").concat(source, "' event (type=").concat(type, ") must not start\n with '").concat(typegen_1.ArvoOrchestratorEventTypeGen.prefix, "' because this is a reserved pattern\n for Arvo orchestrators.\n "));
39
43
  };
40
- var validator = function (value) {
41
- return value.startsWith(typegen_1.ArvoOrchestratorEventTypeGen.prefix);
44
+ var isReservedPrefix = function (value) {
45
+ return !isOrchestrationContract &&
46
+ value.startsWith(typegen_1.ArvoOrchestratorEventTypeGen.prefix);
42
47
  };
43
- if (validator(contract.accepts.type)) {
44
- throw new Error(createErrorMessage('accepts', contract.accepts.type));
48
+ if (isReservedPrefix(contract.type)) {
49
+ throw new Error(createErrorMessage('accepts', contract.type, null));
45
50
  }
46
- for (var _i = 0, _a = Object.keys(contract.emits); _i < _a.length; _i++) {
47
- var item = _a[_i];
48
- if (validator(item)) {
49
- throw new Error(createErrorMessage('emits', item));
51
+ validators_1.ArvoContractValidators.contract.uri.parse(contract.uri);
52
+ for (var _i = 0, _a = Object.entries(contract.versions); _i < _a.length; _i++) {
53
+ var _b = _a[_i], version = _b[0], versionContract = _b[1];
54
+ schema_1.ArvoSemanticVersionSchema.parse(version);
55
+ if (version === ArvoOrchestrationSubject_1.default.WildCardMachineVersion) {
56
+ throw new Error("The version cannot be ".concat(ArvoOrchestrationSubject_1.default.WildCardMachineVersion));
57
+ }
58
+ for (var _c = 0, _d = Object.keys(versionContract.emits); _c < _d.length; _c++) {
59
+ var emitType = _d[_c];
60
+ validators_1.ArvoContractValidators.record.type.parse(emitType);
61
+ if (isReservedPrefix(emitType)) {
62
+ throw new Error(createErrorMessage('emits', emitType, version));
63
+ }
50
64
  }
51
65
  }
52
66
  return new _1.default(contract);
53
67
  };
54
68
  exports.createArvoContract = createArvoContract;
69
+ /**
70
+ * Creates a simplified ArvoContract with standardized type prefixes and emit patterns.
71
+ * This is a convenience function that automatically formats event types according to conventions:
72
+ * - Accept types are prefixed with "com."
73
+ * - Emit types are prefixed with "evt." and suffixed with ".success"
74
+ *
75
+ * @template TUri - The URI type for the contract
76
+ * @template TType - The base type name (without prefixes) for the contract
77
+ * @template TVersions - Record of versions containing accept and emit schemas
78
+ *
79
+ * @param param - The configuration object for creating the contract
80
+ * @param param.uri - The URI identifying the contract
81
+ * @param param.type - The base type name (will be prefixed with "com.")
82
+ * @param param.versions - Version-specific schema definitions
83
+ * @param param.versions[version].accepts - Zod schema for validating incoming events
84
+ * @param param.versions[version].emits - Zod schema for validating outgoing events
85
+ *
86
+ * @returns An ArvoContract instance with standardized type formatting:
87
+ * - Accept type will be "com.[type]"
88
+ * - Emit type will be "evt.[type].success"
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const contract = createSimpleArvoContract({
93
+ * uri: 'example.com/contracts/processor',
94
+ * type: 'document.process',
95
+ * versions: {
96
+ * '1.0.0': {
97
+ * accepts: z.object({
98
+ * documentId: z.string(),
99
+ * options: z.object({ format: z.string() })
100
+ * }),
101
+ * emits: z.object({
102
+ * processedDocument: z.string(),
103
+ * metadata: z.object({ size: z.number() })
104
+ * })
105
+ * }
106
+ * }
107
+ * });
108
+ *
109
+ * // Results in a contract where:
110
+ * // - Accept type is "com.document.process"
111
+ * // - Emit type is "evt.document.process.success"
112
+ * ```
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // Multiple versions example
117
+ * const contract = createSimpleArvoContract({
118
+ * uri: 'api.example/contracts/user',
119
+ * type: 'user.create',
120
+ * versions: {
121
+ * '1.0.0': {
122
+ * accepts: z.object({ name: z.string() }),
123
+ * emits: z.object({ id: z.string() })
124
+ * },
125
+ * '2.0.0': {
126
+ * accepts: z.object({
127
+ * name: z.string(),
128
+ * email: z.string().email()
129
+ * }),
130
+ * emits: z.object({
131
+ * id: z.string(),
132
+ * created: z.date()
133
+ * })
134
+ * }
135
+ * }
136
+ * });
137
+ * ```
138
+ *
139
+ * @remarks
140
+ * This function simplifies contract creation by:
141
+ * 1. Automatically prefixing accept types with "com."
142
+ * 2. Creating a single emit type prefixed with "evt." and suffixed with ".success"
143
+ * 3. Maintaining type safety and schema validation
144
+ *
145
+ * Use this when you have a simple contract pattern with:
146
+ * - A single accept type
147
+ * - A single success emit type
148
+ * - Standard type naming conventions
149
+ *
150
+ * For more complex contracts with multiple emit types or custom type naming,
151
+ * use {@link createArvoContract} instead.
152
+ */
153
+ var createSimpleArvoContract = function (param) {
154
+ return (0, exports.createArvoContract)({
155
+ uri: param.uri,
156
+ type: "com.".concat(param.type),
157
+ versions: Object.fromEntries(Object.entries(param.versions).map(function (_a) {
158
+ var _b;
159
+ var version = _a[0], contract = _a[1];
160
+ return [
161
+ version,
162
+ {
163
+ accepts: contract.accepts,
164
+ emits: (_b = {},
165
+ _b["evt.".concat(param.type, ".success")] = contract.emits,
166
+ _b),
167
+ },
168
+ ];
169
+ })),
170
+ });
171
+ };
172
+ exports.createSimpleArvoContract = createSimpleArvoContract;
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { ArvoContractJSONSchema, ArvoContractRecord, IArvoContract } from './types';
3
3
  import { ArvoErrorSchema } from '../schema';
4
+ import { ArvoSemanticVersion } from '../types';
4
5
  /**
5
6
  * ArvoContract class represents a contract with defined input and output schemas.
6
7
  * It provides methods for validating inputs and outputs based on the contract's specifications.
@@ -9,45 +10,64 @@ import { ArvoErrorSchema } from '../schema';
9
10
  *
10
11
  * @template TUri - The URI of the contract
11
12
  * @template TType - The accept type, defaults to string.
12
- * @template TAcceptSchema - The of the data which the contract bound can accept
13
- * @template TEmits - The type of records the contract bound handler emits.
13
+ * @template TVersion - The contract versions
14
14
  */
15
- export default class ArvoContract<TUri extends string = string, TType extends string = string, TAcceptSchema extends z.ZodTypeAny = z.ZodTypeAny, TEmits extends Record<string, z.ZodTypeAny> = Record<string, z.ZodTypeAny>> {
15
+ export default class ArvoContract<TUri extends string = string, TType extends string = string, TVersions extends Record<ArvoSemanticVersion, {
16
+ accepts: z.ZodTypeAny;
17
+ emits: Record<string, z.ZodTypeAny>;
18
+ }> = Record<ArvoSemanticVersion, {
19
+ accepts: z.ZodTypeAny;
20
+ emits: Record<string, z.ZodTypeAny>;
21
+ }>> {
16
22
  private readonly _uri;
17
- private readonly _accepts;
18
- private readonly _emits;
19
- /** (Optional) The Contract description */
23
+ private readonly _type;
24
+ private readonly _versions;
20
25
  readonly description: string | null;
21
26
  /**
22
27
  * Creates an instance of ArvoContract.
23
28
  * @param params - The contract parameters.
24
29
  */
25
- constructor(params: IArvoContract<TUri, TType, TAcceptSchema, TEmits>);
30
+ constructor(params: IArvoContract<TUri, TType, TVersions>);
26
31
  /**
27
32
  * Gets the URI of the contract.
28
33
  */
29
34
  get uri(): TUri;
35
+ /**
36
+ * Get the type of the event the handler
37
+ * bound to the contract accepts
38
+ */
39
+ get type(): TType;
40
+ /**
41
+ * Gets the version of the contract
42
+ */
43
+ get versions(): TVersions;
44
+ /**
45
+ * Get the latest version of the contract
46
+ */
47
+ get latestVersion(): ArvoSemanticVersion | undefined;
30
48
  /**
31
49
  * Gets the type and schema of the event that the contact
32
50
  * bound handler listens to.
33
51
  */
34
- get accepts(): ArvoContractRecord<TType, TAcceptSchema>;
52
+ accepts<V extends ArvoSemanticVersion & keyof TVersions>(version: V): ArvoContractRecord<TType, TVersions[V]['accepts']>;
35
53
  /**
36
54
  * Gets all event types and schemas that can be emitted by the
37
55
  * contract bound handler.
38
56
  */
39
- get emits(): TEmits;
57
+ emits<V extends ArvoSemanticVersion & keyof TVersions>(version: V): TVersions[V]['emits'];
40
58
  get systemError(): ArvoContractRecord<`sys.${TType}.error`, typeof ArvoErrorSchema>;
41
59
  /**
42
60
  * Validates the contract bound handler's input/ accept event against the
43
61
  * contract's accept schema.
44
62
  * @template U - The type of the input to validate.
63
+ * @template V - The version to use
64
+ * @param version - The version to use
45
65
  * @param type - The type of the input event.
46
66
  * @param input - The input data to validate.
47
67
  * @returns The validation result.
48
68
  * @throws If the accept type is not found in the contract.
49
69
  */
50
- validateAccepts<U>(type: TType, input: U): z.SafeParseReturnType<any, any>;
70
+ validateAccepts<V extends ArvoSemanticVersion & keyof TVersions, U>(version: V, type: TType, input: U): z.SafeParseReturnType<any, any>;
51
71
  /**
52
72
  * Validates the contract bound handler's output/ emits against the
53
73
  * contract's emit schema.
@@ -57,28 +77,14 @@ export default class ArvoContract<TUri extends string = string, TType extends st
57
77
  * @returns The validation result.
58
78
  * @throws If the emit type is not found in the contract.
59
79
  */
60
- validateEmits<U extends keyof TEmits>(type: U, output: unknown): z.SafeParseReturnType<any, any>;
61
- /**
62
- * Validates the accepts record.
63
- * @param accepts - The accepts record to validate.
64
- * @returns The validated accepts record.
65
- * @private
66
- */
67
- private _validateAccepts;
68
- /**
69
- * Validates the emits records.
70
- * @param emits - The emits records to validate.
71
- * @returns The validated emits records.
72
- * @private
73
- */
74
- private _validateEmits;
80
+ validateEmits<V extends ArvoSemanticVersion & keyof TVersions, E extends string & keyof TVersions[V]['emits'], U>(version: V, type: E, output: U): z.SafeParseReturnType<any, any>;
75
81
  /**
76
82
  * Exports the ArvoContract instance as a plain object conforming to the IArvoContract interface.
77
83
  * This method can be used to serialize the contract or to create a new instance with the same parameters.
78
84
  *
79
85
  * @returns An object representing the contract, including its URI, accepts, and emits properties.
80
86
  */
81
- export(): IArvoContract<TUri, TType, TAcceptSchema, TEmits>;
87
+ export(): IArvoContract<TUri, TType, TVersions>;
82
88
  /**
83
89
  * Converts the ArvoContract instance to a JSON Schema representation.
84
90
  * This method provides a way to represent the contract's structure and validation rules