@hazeljs/data 0.2.3 → 0.3.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.
Files changed (33) hide show
  1. package/dist/connectors/__tests__/jsonl.connector.test.d.ts +2 -0
  2. package/dist/connectors/__tests__/jsonl.connector.test.d.ts.map +1 -0
  3. package/dist/connectors/__tests__/jsonl.connector.test.js +261 -0
  4. package/dist/connectors/jsonl.connector.d.ts +51 -0
  5. package/dist/connectors/jsonl.connector.d.ts.map +1 -0
  6. package/dist/connectors/jsonl.connector.js +100 -0
  7. package/dist/connectors/postgres.connector.d.ts +78 -0
  8. package/dist/connectors/postgres.connector.d.ts.map +1 -0
  9. package/dist/connectors/postgres.connector.js +224 -0
  10. package/dist/contracts/__tests__/contract-registry.test.d.ts +2 -0
  11. package/dist/contracts/__tests__/contract-registry.test.d.ts.map +1 -0
  12. package/dist/contracts/__tests__/contract-registry.test.js +770 -0
  13. package/dist/contracts/__tests__/contract.decorator.test.d.ts +2 -0
  14. package/dist/contracts/__tests__/contract.decorator.test.d.ts.map +1 -0
  15. package/dist/contracts/__tests__/contract.decorator.test.js +177 -0
  16. package/dist/contracts/contract-registry.d.ts +57 -0
  17. package/dist/contracts/contract-registry.d.ts.map +1 -0
  18. package/dist/contracts/contract-registry.js +285 -0
  19. package/dist/contracts/contract.decorator.d.ts +70 -0
  20. package/dist/contracts/contract.decorator.d.ts.map +1 -0
  21. package/dist/contracts/contract.decorator.js +55 -0
  22. package/dist/contracts/contract.types.d.ts +65 -0
  23. package/dist/contracts/contract.types.d.ts.map +1 -0
  24. package/dist/contracts/contract.types.js +5 -0
  25. package/dist/contracts/index.d.ts +9 -0
  26. package/dist/contracts/index.d.ts.map +1 -0
  27. package/dist/contracts/index.js +16 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +14 -2
  31. package/dist/testing/schema-faker.test.js +33 -0
  32. package/dist/transformers/transformer.service.test.js +40 -0
  33. package/package.json +2 -2
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contract.decorator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.decorator.test.d.ts","sourceRoot":"","sources":["../../../src/contracts/__tests__/contract.decorator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const contract_decorator_1 = require("../contract.decorator");
10
+ describe('DataContract decorator', () => {
11
+ it('should attach metadata to class', () => {
12
+ let TestContract = class TestContract {
13
+ };
14
+ TestContract = __decorate([
15
+ (0, contract_decorator_1.DataContract)({
16
+ name: 'test-contract',
17
+ version: '1.0.0',
18
+ description: 'Test contract',
19
+ owner: 'data-team',
20
+ schema: {
21
+ type: 'object',
22
+ properties: {
23
+ id: { type: 'string' },
24
+ name: { type: 'string' },
25
+ },
26
+ },
27
+ })
28
+ ], TestContract);
29
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(TestContract);
30
+ expect(metadata).toBeDefined();
31
+ expect(metadata?.name).toBe('test-contract');
32
+ expect(metadata?.version).toBe('1.0.0');
33
+ expect(metadata?.description).toBe('Test contract');
34
+ expect(metadata?.owner).toBe('data-team');
35
+ expect(metadata?.status).toBe('active');
36
+ expect(metadata?.createdAt).toBeInstanceOf(Date);
37
+ expect(metadata?.updatedAt).toBeInstanceOf(Date);
38
+ });
39
+ it('should handle optional fields', () => {
40
+ let MinimalContract = class MinimalContract {
41
+ };
42
+ MinimalContract = __decorate([
43
+ (0, contract_decorator_1.DataContract)({
44
+ name: 'minimal-contract',
45
+ version: '1.0.0',
46
+ owner: 'team-a',
47
+ schema: {
48
+ type: 'object',
49
+ properties: {},
50
+ },
51
+ })
52
+ ], MinimalContract);
53
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(MinimalContract);
54
+ expect(metadata).toBeDefined();
55
+ expect(metadata?.name).toBe('minimal-contract');
56
+ expect(metadata?.description).toBeUndefined();
57
+ });
58
+ it('should handle consumers and producers', () => {
59
+ let ConsumedContract = class ConsumedContract {
60
+ };
61
+ ConsumedContract = __decorate([
62
+ (0, contract_decorator_1.DataContract)({
63
+ name: 'consumed-contract',
64
+ version: '1.0.0',
65
+ owner: 'data-platform',
66
+ schema: { type: 'object', properties: {} },
67
+ consumers: ['service-a', 'service-b'],
68
+ producers: ['producer-1'],
69
+ })
70
+ ], ConsumedContract);
71
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(ConsumedContract);
72
+ expect(metadata?.consumers).toEqual(['service-a', 'service-b']);
73
+ expect(metadata?.producers).toEqual(['producer-1']);
74
+ });
75
+ it('should handle SLA configuration', () => {
76
+ let SLAContract = class SLAContract {
77
+ };
78
+ SLAContract = __decorate([
79
+ (0, contract_decorator_1.DataContract)({
80
+ name: 'sla-contract',
81
+ version: '1.0.0',
82
+ owner: 'analytics-team',
83
+ schema: { type: 'object', properties: {} },
84
+ sla: {
85
+ freshness: {
86
+ maxDelayMinutes: 60,
87
+ checkIntervalMinutes: 15,
88
+ },
89
+ completeness: {
90
+ minCompleteness: 0.95,
91
+ requiredFields: ['id', 'timestamp'],
92
+ },
93
+ quality: {
94
+ minQualityScore: 0.9,
95
+ checks: ['no-nulls', 'valid-format'],
96
+ },
97
+ availability: {
98
+ minUptime: 0.99,
99
+ },
100
+ },
101
+ })
102
+ ], SLAContract);
103
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(SLAContract);
104
+ expect(metadata?.sla?.freshness?.maxDelayMinutes).toBe(60);
105
+ expect(metadata?.sla?.completeness?.minCompleteness).toBe(0.95);
106
+ expect(metadata?.sla?.quality?.minQualityScore).toBe(0.9);
107
+ expect(metadata?.sla?.availability?.minUptime).toBe(0.99);
108
+ });
109
+ it('should return undefined for non-decorated class', () => {
110
+ class NotDecorated {
111
+ }
112
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(NotDecorated);
113
+ expect(metadata).toBeUndefined();
114
+ });
115
+ it('should handle complex schema', () => {
116
+ let ComplexContract = class ComplexContract {
117
+ };
118
+ ComplexContract = __decorate([
119
+ (0, contract_decorator_1.DataContract)({
120
+ name: 'complex-contract',
121
+ version: '2.0.0',
122
+ owner: 'ml-team',
123
+ schema: {
124
+ type: 'object',
125
+ properties: {
126
+ id: { type: 'string' },
127
+ metadata: {
128
+ type: 'object',
129
+ properties: {
130
+ tags: { type: 'array', items: { type: 'string' } },
131
+ },
132
+ },
133
+ },
134
+ required: ['id'],
135
+ },
136
+ })
137
+ ], ComplexContract);
138
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(ComplexContract);
139
+ expect(metadata?.schema.properties).toBeDefined();
140
+ expect(metadata?.schema.required).toEqual(['id']);
141
+ });
142
+ it('should handle tags', () => {
143
+ let TaggedContract = class TaggedContract {
144
+ };
145
+ TaggedContract = __decorate([
146
+ (0, contract_decorator_1.DataContract)({
147
+ name: 'tagged-contract',
148
+ version: '1.0.0',
149
+ owner: 'platform-team',
150
+ schema: { type: 'object', properties: {} },
151
+ tags: ['pii', 'critical', 'production'],
152
+ })
153
+ ], TaggedContract);
154
+ const metadata = (0, contract_decorator_1.getDataContractMetadata)(TaggedContract);
155
+ expect(metadata?.tags).toEqual(['pii', 'critical', 'production']);
156
+ });
157
+ describe('hasDataContractMetadata', () => {
158
+ it('should return true for decorated class', () => {
159
+ let DecoratedClass = class DecoratedClass {
160
+ };
161
+ DecoratedClass = __decorate([
162
+ (0, contract_decorator_1.DataContract)({
163
+ name: 'test',
164
+ version: '1.0.0',
165
+ owner: 'team',
166
+ schema: { type: 'object', properties: {} },
167
+ })
168
+ ], DecoratedClass);
169
+ expect((0, contract_decorator_1.hasDataContractMetadata)(DecoratedClass)).toBe(true);
170
+ });
171
+ it('should return false for non-decorated class', () => {
172
+ class NonDecoratedClass {
173
+ }
174
+ expect((0, contract_decorator_1.hasDataContractMetadata)(NonDecoratedClass)).toBe(false);
175
+ });
176
+ });
177
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Contract Registry - Manage data contracts and their versions
3
+ */
4
+ import type { DataContract, ContractViolation, ContractDiff, ContractValidationResult } from './contract.types';
5
+ export declare class ContractRegistry {
6
+ private contracts;
7
+ private violations;
8
+ /**
9
+ * Register a data contract
10
+ */
11
+ register(contract: DataContract): void;
12
+ /**
13
+ * Get a specific contract version
14
+ */
15
+ get(name: string, version?: string): DataContract | undefined;
16
+ /**
17
+ * List all versions of a contract
18
+ */
19
+ listVersions(name: string): string[];
20
+ /**
21
+ * List all contracts
22
+ */
23
+ listContracts(): Array<{
24
+ name: string;
25
+ versions: string[];
26
+ owner: string;
27
+ }>;
28
+ /**
29
+ * Deprecate a contract version
30
+ */
31
+ deprecate(name: string, version: string): void;
32
+ /**
33
+ * Compare two contract versions to detect breaking changes
34
+ */
35
+ diff(name: string, oldVersion: string, newVersion: string): ContractDiff;
36
+ /**
37
+ * Validate data against a contract
38
+ */
39
+ validate(name: string, data: unknown, version?: string): ContractValidationResult;
40
+ /**
41
+ * Record a contract violation
42
+ */
43
+ recordViolation(violation: ContractViolation): void;
44
+ /**
45
+ * Get violations for a contract
46
+ */
47
+ getViolations(name: string, version?: string): ContractViolation[];
48
+ /**
49
+ * Clear violations older than specified days
50
+ */
51
+ clearOldViolations(days: number): void;
52
+ private detectSchemaChanges;
53
+ private validateSchema;
54
+ private validateCompleteness;
55
+ private compareVersions;
56
+ }
57
+ //# sourceMappingURL=contract-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-registry.d.ts","sourceRoot":"","sources":["../../src/contracts/contract-registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAEjB,YAAY,EACZ,wBAAwB,EACzB,MAAM,kBAAkB,CAAC;AAE1B,qBACa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAqD;IACtE,OAAO,CAAC,UAAU,CAA2B;IAE7C;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAOtC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAa7D;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAMpC;;OAEG;IACH,aAAa,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAe3E;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAW9C;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY;IAqBxE;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,wBAAwB;IAwCjF;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IASnD;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAMlE;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQtC,OAAO,CAAC,mBAAmB;IAmD3B,OAAO,CAAC,cAAc;IAuCtB,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,eAAe;CAYxB"}
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ /**
3
+ * Contract Registry - Manage data contracts and their versions
4
+ */
5
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
6
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
7
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
8
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
9
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ContractRegistry = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const core_2 = __importDefault(require("@hazeljs/core"));
18
+ let ContractRegistry = class ContractRegistry {
19
+ constructor() {
20
+ this.contracts = new Map();
21
+ this.violations = [];
22
+ }
23
+ /**
24
+ * Register a data contract
25
+ */
26
+ register(contract) {
27
+ const versions = this.contracts.get(contract.name) ?? new Map();
28
+ versions.set(contract.version, contract);
29
+ this.contracts.set(contract.name, versions);
30
+ core_2.default.debug(`Registered contract: ${contract.name}@${contract.version}`);
31
+ }
32
+ /**
33
+ * Get a specific contract version
34
+ */
35
+ get(name, version) {
36
+ const versions = this.contracts.get(name);
37
+ if (!versions)
38
+ return undefined;
39
+ if (version) {
40
+ return versions.get(version);
41
+ }
42
+ // Return latest version
43
+ const sorted = Array.from(versions.entries()).sort((a, b) => this.compareVersions(b[0], a[0]));
44
+ return sorted[0]?.[1];
45
+ }
46
+ /**
47
+ * List all versions of a contract
48
+ */
49
+ listVersions(name) {
50
+ const versions = this.contracts.get(name);
51
+ if (!versions)
52
+ return [];
53
+ return Array.from(versions.keys()).sort((a, b) => this.compareVersions(b, a));
54
+ }
55
+ /**
56
+ * List all contracts
57
+ */
58
+ listContracts() {
59
+ const result = [];
60
+ for (const [name, versions] of this.contracts) {
61
+ const latest = this.get(name);
62
+ result.push({
63
+ name,
64
+ versions: Array.from(versions.keys()),
65
+ owner: latest?.owner ?? 'unknown',
66
+ });
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * Deprecate a contract version
72
+ */
73
+ deprecate(name, version) {
74
+ const contract = this.get(name, version);
75
+ if (!contract) {
76
+ throw new Error(`Contract not found: ${name}@${version}`);
77
+ }
78
+ contract.status = 'deprecated';
79
+ contract.updatedAt = new Date();
80
+ core_2.default.debug(`Deprecated contract: ${name}@${version}`);
81
+ }
82
+ /**
83
+ * Compare two contract versions to detect breaking changes
84
+ */
85
+ diff(name, oldVersion, newVersion) {
86
+ const oldContract = this.get(name, oldVersion);
87
+ const newContract = this.get(name, newVersion);
88
+ if (!oldContract || !newContract) {
89
+ throw new Error(`Cannot compare: contract versions not found`);
90
+ }
91
+ const changes = this.detectSchemaChanges(oldContract.schema, newContract.schema);
92
+ const breakingChanges = changes.filter((c) => c.breaking);
93
+ return {
94
+ contractName: name,
95
+ oldVersion,
96
+ newVersion,
97
+ changes,
98
+ breakingChanges,
99
+ isBreaking: breakingChanges.length > 0,
100
+ };
101
+ }
102
+ /**
103
+ * Validate data against a contract
104
+ */
105
+ validate(name, data, version) {
106
+ const contract = this.get(name, version);
107
+ if (!contract) {
108
+ return {
109
+ valid: false,
110
+ violations: [
111
+ {
112
+ contractName: name,
113
+ contractVersion: version ?? 'latest',
114
+ violationType: 'schema',
115
+ severity: 'error',
116
+ message: `Contract not found: ${name}@${version ?? 'latest'}`,
117
+ details: {},
118
+ timestamp: new Date(),
119
+ },
120
+ ],
121
+ warnings: [],
122
+ };
123
+ }
124
+ const violations = [];
125
+ const warnings = [];
126
+ // Schema validation
127
+ const schemaViolations = this.validateSchema(contract, data);
128
+ violations.push(...schemaViolations);
129
+ // SLA validation
130
+ if (contract.sla?.completeness) {
131
+ const completenessViolations = this.validateCompleteness(contract, data);
132
+ violations.push(...completenessViolations);
133
+ }
134
+ return {
135
+ valid: violations.length === 0,
136
+ violations,
137
+ warnings,
138
+ };
139
+ }
140
+ /**
141
+ * Record a contract violation
142
+ */
143
+ recordViolation(violation) {
144
+ this.violations.push(violation);
145
+ core_2.default.warn(`Contract violation: ${violation.contractName}@${violation.contractVersion}`, {
146
+ type: violation.violationType,
147
+ severity: violation.severity,
148
+ message: violation.message,
149
+ });
150
+ }
151
+ /**
152
+ * Get violations for a contract
153
+ */
154
+ getViolations(name, version) {
155
+ return this.violations.filter((v) => v.contractName === name && (!version || v.contractVersion === version));
156
+ }
157
+ /**
158
+ * Clear violations older than specified days
159
+ */
160
+ clearOldViolations(days) {
161
+ const cutoff = new Date();
162
+ cutoff.setDate(cutoff.getDate() - days);
163
+ this.violations = this.violations.filter((v) => v.timestamp > cutoff);
164
+ }
165
+ // ─── Private Helpers ─────────────────────────────────────────────────────────
166
+ detectSchemaChanges(oldSchema, newSchema) {
167
+ const changes = [];
168
+ const allFields = new Set([...Object.keys(oldSchema), ...Object.keys(newSchema)]);
169
+ for (const field of allFields) {
170
+ const oldValue = oldSchema[field];
171
+ const newValue = newSchema[field];
172
+ if (oldValue === undefined && newValue !== undefined) {
173
+ // Field added
174
+ changes.push({
175
+ field,
176
+ changeType: 'added',
177
+ newValue,
178
+ breaking: false,
179
+ });
180
+ }
181
+ else if (oldValue !== undefined && newValue === undefined) {
182
+ // Field removed - BREAKING
183
+ changes.push({
184
+ field,
185
+ changeType: 'removed',
186
+ oldValue,
187
+ breaking: true,
188
+ });
189
+ }
190
+ else if (typeof oldValue !== typeof newValue) {
191
+ // Type changed - BREAKING
192
+ changes.push({
193
+ field,
194
+ changeType: 'type_changed',
195
+ oldValue,
196
+ newValue,
197
+ breaking: true,
198
+ });
199
+ }
200
+ else if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
201
+ // Field modified
202
+ changes.push({
203
+ field,
204
+ changeType: 'modified',
205
+ oldValue,
206
+ newValue,
207
+ breaking: false,
208
+ });
209
+ }
210
+ }
211
+ return changes;
212
+ }
213
+ validateSchema(contract, data) {
214
+ const violations = [];
215
+ if (typeof data !== 'object' || data === null) {
216
+ violations.push({
217
+ contractName: contract.name,
218
+ contractVersion: contract.version,
219
+ violationType: 'schema',
220
+ severity: 'error',
221
+ message: 'Data must be an object',
222
+ details: { data },
223
+ timestamp: new Date(),
224
+ });
225
+ return violations;
226
+ }
227
+ const record = data;
228
+ // Check required fields from schema
229
+ for (const [field, fieldSchema] of Object.entries(contract.schema)) {
230
+ if (typeof fieldSchema === 'object' && fieldSchema !== null) {
231
+ const schema = fieldSchema;
232
+ if (schema.required === true && record[field] === undefined) {
233
+ violations.push({
234
+ contractName: contract.name,
235
+ contractVersion: contract.version,
236
+ violationType: 'schema',
237
+ severity: 'error',
238
+ message: `Required field missing: ${field}`,
239
+ details: { field, schema },
240
+ timestamp: new Date(),
241
+ });
242
+ }
243
+ }
244
+ }
245
+ return violations;
246
+ }
247
+ validateCompleteness(contract, data) {
248
+ const violations = [];
249
+ const sla = contract.sla?.completeness;
250
+ if (!sla)
251
+ return violations;
252
+ const record = data;
253
+ const missingFields = sla.requiredFields.filter((f) => record[f] === undefined || record[f] === null);
254
+ if (missingFields.length > 0) {
255
+ const completeness = 1 - missingFields.length / sla.requiredFields.length;
256
+ if (completeness < sla.minCompleteness) {
257
+ violations.push({
258
+ contractName: contract.name,
259
+ contractVersion: contract.version,
260
+ violationType: 'sla',
261
+ severity: 'warning',
262
+ message: `Completeness ${(completeness * 100).toFixed(1)}% below SLA ${(sla.minCompleteness * 100).toFixed(1)}%`,
263
+ details: { missingFields, completeness, minCompleteness: sla.minCompleteness },
264
+ timestamp: new Date(),
265
+ });
266
+ }
267
+ }
268
+ return violations;
269
+ }
270
+ compareVersions(a, b) {
271
+ const aParts = a.split('.').map(Number);
272
+ const bParts = b.split('.').map(Number);
273
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
274
+ const aPart = aParts[i] ?? 0;
275
+ const bPart = bParts[i] ?? 0;
276
+ if (aPart !== bPart)
277
+ return aPart - bPart;
278
+ }
279
+ return 0;
280
+ }
281
+ };
282
+ exports.ContractRegistry = ContractRegistry;
283
+ exports.ContractRegistry = ContractRegistry = __decorate([
284
+ (0, core_1.Service)()
285
+ ], ContractRegistry);
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @DataContract decorator - Define a data contract for a pipeline or dataset
3
+ */
4
+ import 'reflect-metadata';
5
+ export declare const DATA_CONTRACT_METADATA_KEY: unique symbol;
6
+ export interface DataContractOptions {
7
+ name: string;
8
+ version: string;
9
+ description?: string;
10
+ owner: string;
11
+ schema: Record<string, unknown>;
12
+ sla?: {
13
+ freshness?: {
14
+ maxDelayMinutes: number;
15
+ checkIntervalMinutes?: number;
16
+ };
17
+ completeness?: {
18
+ minCompleteness: number;
19
+ requiredFields: string[];
20
+ };
21
+ quality?: {
22
+ minQualityScore: number;
23
+ checks: string[];
24
+ };
25
+ availability?: {
26
+ minUptime: number;
27
+ };
28
+ };
29
+ consumers?: string[];
30
+ producers?: string[];
31
+ tags?: string[];
32
+ }
33
+ export interface DataContractMetadata extends DataContractOptions {
34
+ status: 'active' | 'deprecated' | 'breaking';
35
+ createdAt: Date;
36
+ updatedAt: Date;
37
+ }
38
+ /**
39
+ * Mark a pipeline or class as having a data contract.
40
+ * The contract defines the schema, SLA, and ownership of the data.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * @DataContract({
45
+ * name: 'user-events',
46
+ * version: '1.0.0',
47
+ * owner: 'analytics-team',
48
+ * schema: {
49
+ * userId: { type: 'string', required: true },
50
+ * eventType: { type: 'string', required: true },
51
+ * timestamp: { type: 'date', required: true },
52
+ * },
53
+ * sla: {
54
+ * freshness: { maxDelayMinutes: 5 },
55
+ * completeness: { minCompleteness: 0.95, requiredFields: ['userId', 'eventType'] }
56
+ * },
57
+ * consumers: ['recommendation-service', 'analytics-dashboard']
58
+ * })
59
+ * @Pipeline('user-events-pipeline')
60
+ * class UserEventsPipeline extends PipelineBase {
61
+ * // ...
62
+ * }
63
+ * ```
64
+ */
65
+ export declare function DataContract(options: DataContractOptions): <T extends {
66
+ new (...args: unknown[]): object;
67
+ }>(target: T) => void;
68
+ export declare function getDataContractMetadata(target: object): DataContractMetadata | undefined;
69
+ export declare function hasDataContractMetadata(target: object): boolean;
70
+ //# sourceMappingURL=contract.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.decorator.d.ts","sourceRoot":"","sources":["../../src/contracts/contract.decorator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,kBAAkB,CAAC;AAE1B,eAAO,MAAM,0BAA0B,eAAyC,CAAC;AAEjF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,GAAG,CAAC,EAAE;QACJ,SAAS,CAAC,EAAE;YACV,eAAe,EAAE,MAAM,CAAC;YACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;SAC/B,CAAC;QACF,YAAY,CAAC,EAAE;YACb,eAAe,EAAE,MAAM,CAAC;YACxB,cAAc,EAAE,MAAM,EAAE,CAAC;SAC1B,CAAC;QACF,OAAO,CAAC,EAAE;YACR,eAAe,EAAE,MAAM,CAAC;YACxB,MAAM,EAAE,MAAM,EAAE,CAAC;SAClB,CAAC;QACF,YAAY,CAAC,EAAE;YACb,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,MAAM,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,CAAC;IAC7C,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,IACtC,CAAC,SAAS;IAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAA;CAAE,EAAE,QAAQ,CAAC,KAAG,IAAI,CAUlF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAExF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE/D"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * @DataContract decorator - Define a data contract for a pipeline or dataset
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DATA_CONTRACT_METADATA_KEY = void 0;
7
+ exports.DataContract = DataContract;
8
+ exports.getDataContractMetadata = getDataContractMetadata;
9
+ exports.hasDataContractMetadata = hasDataContractMetadata;
10
+ require("reflect-metadata");
11
+ exports.DATA_CONTRACT_METADATA_KEY = Symbol('hazel:data-contract:metadata');
12
+ /**
13
+ * Mark a pipeline or class as having a data contract.
14
+ * The contract defines the schema, SLA, and ownership of the data.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * @DataContract({
19
+ * name: 'user-events',
20
+ * version: '1.0.0',
21
+ * owner: 'analytics-team',
22
+ * schema: {
23
+ * userId: { type: 'string', required: true },
24
+ * eventType: { type: 'string', required: true },
25
+ * timestamp: { type: 'date', required: true },
26
+ * },
27
+ * sla: {
28
+ * freshness: { maxDelayMinutes: 5 },
29
+ * completeness: { minCompleteness: 0.95, requiredFields: ['userId', 'eventType'] }
30
+ * },
31
+ * consumers: ['recommendation-service', 'analytics-dashboard']
32
+ * })
33
+ * @Pipeline('user-events-pipeline')
34
+ * class UserEventsPipeline extends PipelineBase {
35
+ * // ...
36
+ * }
37
+ * ```
38
+ */
39
+ function DataContract(options) {
40
+ return function (target) {
41
+ const metadata = {
42
+ ...options,
43
+ status: 'active',
44
+ createdAt: new Date(),
45
+ updatedAt: new Date(),
46
+ };
47
+ Reflect.defineMetadata(exports.DATA_CONTRACT_METADATA_KEY, metadata, target);
48
+ };
49
+ }
50
+ function getDataContractMetadata(target) {
51
+ return Reflect.getMetadata(exports.DATA_CONTRACT_METADATA_KEY, target);
52
+ }
53
+ function hasDataContractMetadata(target) {
54
+ return Reflect.hasMetadata(exports.DATA_CONTRACT_METADATA_KEY, target);
55
+ }