@hazeljs/data 0.2.0-alpha.1

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 (171) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +308 -0
  3. package/dist/connectors/connector.interface.d.ts +29 -0
  4. package/dist/connectors/connector.interface.d.ts.map +1 -0
  5. package/dist/connectors/connector.interface.js +6 -0
  6. package/dist/connectors/csv.connector.d.ts +63 -0
  7. package/dist/connectors/csv.connector.d.ts.map +1 -0
  8. package/dist/connectors/csv.connector.js +147 -0
  9. package/dist/connectors/http.connector.d.ts +68 -0
  10. package/dist/connectors/http.connector.d.ts.map +1 -0
  11. package/dist/connectors/http.connector.js +131 -0
  12. package/dist/connectors/index.d.ts +7 -0
  13. package/dist/connectors/index.d.ts.map +1 -0
  14. package/dist/connectors/index.js +12 -0
  15. package/dist/connectors/memory.connector.d.ts +38 -0
  16. package/dist/connectors/memory.connector.d.ts.map +1 -0
  17. package/dist/connectors/memory.connector.js +56 -0
  18. package/dist/connectors/memory.connector.test.d.ts +2 -0
  19. package/dist/connectors/memory.connector.test.d.ts.map +1 -0
  20. package/dist/connectors/memory.connector.test.js +43 -0
  21. package/dist/data.module.d.ts +30 -0
  22. package/dist/data.module.d.ts.map +1 -0
  23. package/dist/data.module.js +120 -0
  24. package/dist/data.module.test.d.ts +2 -0
  25. package/dist/data.module.test.d.ts.map +1 -0
  26. package/dist/data.module.test.js +28 -0
  27. package/dist/data.types.d.ts +67 -0
  28. package/dist/data.types.d.ts.map +1 -0
  29. package/dist/data.types.js +5 -0
  30. package/dist/decorators/index.d.ts +6 -0
  31. package/dist/decorators/index.d.ts.map +1 -0
  32. package/dist/decorators/index.js +24 -0
  33. package/dist/decorators/pii.decorator.d.ts +59 -0
  34. package/dist/decorators/pii.decorator.d.ts.map +1 -0
  35. package/dist/decorators/pii.decorator.js +197 -0
  36. package/dist/decorators/pii.decorator.test.d.ts +2 -0
  37. package/dist/decorators/pii.decorator.test.d.ts.map +1 -0
  38. package/dist/decorators/pii.decorator.test.js +150 -0
  39. package/dist/decorators/pipeline.decorator.d.ts +22 -0
  40. package/dist/decorators/pipeline.decorator.d.ts.map +1 -0
  41. package/dist/decorators/pipeline.decorator.js +42 -0
  42. package/dist/decorators/pipeline.decorator.test.d.ts +2 -0
  43. package/dist/decorators/pipeline.decorator.test.d.ts.map +1 -0
  44. package/dist/decorators/pipeline.decorator.test.js +104 -0
  45. package/dist/decorators/stream.decorator.d.ts +31 -0
  46. package/dist/decorators/stream.decorator.d.ts.map +1 -0
  47. package/dist/decorators/stream.decorator.js +48 -0
  48. package/dist/decorators/transform.decorator.d.ts +29 -0
  49. package/dist/decorators/transform.decorator.d.ts.map +1 -0
  50. package/dist/decorators/transform.decorator.js +41 -0
  51. package/dist/decorators/validate.decorator.d.ts +34 -0
  52. package/dist/decorators/validate.decorator.d.ts.map +1 -0
  53. package/dist/decorators/validate.decorator.js +49 -0
  54. package/dist/flink.service.d.ts +80 -0
  55. package/dist/flink.service.d.ts.map +1 -0
  56. package/dist/flink.service.js +134 -0
  57. package/dist/flink.service.test.d.ts +2 -0
  58. package/dist/flink.service.test.d.ts.map +1 -0
  59. package/dist/flink.service.test.js +60 -0
  60. package/dist/index.d.ts +32 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +96 -0
  63. package/dist/pipelines/etl.service.d.ts +59 -0
  64. package/dist/pipelines/etl.service.d.ts.map +1 -0
  65. package/dist/pipelines/etl.service.js +223 -0
  66. package/dist/pipelines/etl.service.test.d.ts +2 -0
  67. package/dist/pipelines/etl.service.test.d.ts.map +1 -0
  68. package/dist/pipelines/etl.service.test.js +319 -0
  69. package/dist/pipelines/pipeline.base.d.ts +24 -0
  70. package/dist/pipelines/pipeline.base.d.ts.map +1 -0
  71. package/dist/pipelines/pipeline.base.js +29 -0
  72. package/dist/pipelines/pipeline.base.test.d.ts +2 -0
  73. package/dist/pipelines/pipeline.base.test.d.ts.map +1 -0
  74. package/dist/pipelines/pipeline.base.test.js +38 -0
  75. package/dist/pipelines/pipeline.builder.d.ts +95 -0
  76. package/dist/pipelines/pipeline.builder.d.ts.map +1 -0
  77. package/dist/pipelines/pipeline.builder.js +212 -0
  78. package/dist/pipelines/pipeline.builder.test.d.ts +2 -0
  79. package/dist/pipelines/pipeline.builder.test.d.ts.map +1 -0
  80. package/dist/pipelines/pipeline.builder.test.js +185 -0
  81. package/dist/pipelines/stream.service.d.ts +12 -0
  82. package/dist/pipelines/stream.service.d.ts.map +1 -0
  83. package/dist/pipelines/stream.service.js +58 -0
  84. package/dist/pipelines/stream.service.test.d.ts +2 -0
  85. package/dist/pipelines/stream.service.test.d.ts.map +1 -0
  86. package/dist/pipelines/stream.service.test.js +103 -0
  87. package/dist/quality/quality.service.d.ts +87 -0
  88. package/dist/quality/quality.service.d.ts.map +1 -0
  89. package/dist/quality/quality.service.js +326 -0
  90. package/dist/quality/quality.service.test.d.ts +2 -0
  91. package/dist/quality/quality.service.test.d.ts.map +1 -0
  92. package/dist/quality/quality.service.test.js +128 -0
  93. package/dist/schema/schema.d.ts +127 -0
  94. package/dist/schema/schema.d.ts.map +1 -0
  95. package/dist/schema/schema.js +487 -0
  96. package/dist/schema/schema.test.d.ts +2 -0
  97. package/dist/schema/schema.test.d.ts.map +1 -0
  98. package/dist/schema/schema.test.js +411 -0
  99. package/dist/streaming/flink/flink.client.d.ts +96 -0
  100. package/dist/streaming/flink/flink.client.d.ts.map +1 -0
  101. package/dist/streaming/flink/flink.client.js +267 -0
  102. package/dist/streaming/flink/flink.client.test.d.ts +2 -0
  103. package/dist/streaming/flink/flink.client.test.d.ts.map +1 -0
  104. package/dist/streaming/flink/flink.client.test.js +59 -0
  105. package/dist/streaming/flink/flink.job.d.ts +29 -0
  106. package/dist/streaming/flink/flink.job.d.ts.map +1 -0
  107. package/dist/streaming/flink/flink.job.js +27 -0
  108. package/dist/streaming/flink/flink.job.test.d.ts +2 -0
  109. package/dist/streaming/flink/flink.job.test.d.ts.map +1 -0
  110. package/dist/streaming/flink/flink.job.test.js +37 -0
  111. package/dist/streaming/flink/flink.operators.d.ts +35 -0
  112. package/dist/streaming/flink/flink.operators.d.ts.map +1 -0
  113. package/dist/streaming/flink/flink.operators.js +43 -0
  114. package/dist/streaming/flink/flink.operators.test.d.ts +2 -0
  115. package/dist/streaming/flink/flink.operators.test.d.ts.map +1 -0
  116. package/dist/streaming/flink/flink.operators.test.js +38 -0
  117. package/dist/streaming/stream.builder.d.ts +22 -0
  118. package/dist/streaming/stream.builder.d.ts.map +1 -0
  119. package/dist/streaming/stream.builder.js +50 -0
  120. package/dist/streaming/stream.builder.test.d.ts +2 -0
  121. package/dist/streaming/stream.builder.test.d.ts.map +1 -0
  122. package/dist/streaming/stream.builder.test.js +59 -0
  123. package/dist/streaming/stream.processor.d.ts +66 -0
  124. package/dist/streaming/stream.processor.d.ts.map +1 -0
  125. package/dist/streaming/stream.processor.js +178 -0
  126. package/dist/streaming/stream.processor.test.d.ts +2 -0
  127. package/dist/streaming/stream.processor.test.d.ts.map +1 -0
  128. package/dist/streaming/stream.processor.test.js +151 -0
  129. package/dist/streaming/stream.processor.windowing.test.d.ts +2 -0
  130. package/dist/streaming/stream.processor.windowing.test.d.ts.map +1 -0
  131. package/dist/streaming/stream.processor.windowing.test.js +69 -0
  132. package/dist/telemetry/telemetry.d.ts +124 -0
  133. package/dist/telemetry/telemetry.d.ts.map +1 -0
  134. package/dist/telemetry/telemetry.js +259 -0
  135. package/dist/telemetry/telemetry.test.d.ts +2 -0
  136. package/dist/telemetry/telemetry.test.d.ts.map +1 -0
  137. package/dist/telemetry/telemetry.test.js +51 -0
  138. package/dist/testing/index.d.ts +12 -0
  139. package/dist/testing/index.d.ts.map +1 -0
  140. package/dist/testing/index.js +18 -0
  141. package/dist/testing/pipeline-test-harness.d.ts +40 -0
  142. package/dist/testing/pipeline-test-harness.d.ts.map +1 -0
  143. package/dist/testing/pipeline-test-harness.js +55 -0
  144. package/dist/testing/pipeline-test-harness.test.d.ts +2 -0
  145. package/dist/testing/pipeline-test-harness.test.d.ts.map +1 -0
  146. package/dist/testing/pipeline-test-harness.test.js +102 -0
  147. package/dist/testing/schema-faker.d.ts +32 -0
  148. package/dist/testing/schema-faker.d.ts.map +1 -0
  149. package/dist/testing/schema-faker.js +91 -0
  150. package/dist/testing/schema-faker.test.d.ts +2 -0
  151. package/dist/testing/schema-faker.test.d.ts.map +1 -0
  152. package/dist/testing/schema-faker.test.js +66 -0
  153. package/dist/transformers/built-in.transformers.d.ts +12 -0
  154. package/dist/transformers/built-in.transformers.d.ts.map +1 -0
  155. package/dist/transformers/built-in.transformers.js +75 -0
  156. package/dist/transformers/built-in.transformers.test.d.ts +2 -0
  157. package/dist/transformers/built-in.transformers.test.d.ts.map +1 -0
  158. package/dist/transformers/built-in.transformers.test.js +85 -0
  159. package/dist/transformers/transformer.service.d.ts +14 -0
  160. package/dist/transformers/transformer.service.d.ts.map +1 -0
  161. package/dist/transformers/transformer.service.js +65 -0
  162. package/dist/transformers/transformer.service.test.d.ts +2 -0
  163. package/dist/transformers/transformer.service.test.d.ts.map +1 -0
  164. package/dist/transformers/transformer.service.test.js +42 -0
  165. package/dist/validators/schema.validator.d.ts +21 -0
  166. package/dist/validators/schema.validator.d.ts.map +1 -0
  167. package/dist/validators/schema.validator.js +40 -0
  168. package/dist/validators/schema.validator.test.d.ts +2 -0
  169. package/dist/validators/schema.validator.test.d.ts.map +1 -0
  170. package/dist/validators/schema.validator.test.js +42 -0
  171. package/package.json +53 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data.module.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.module.test.d.ts","sourceRoot":"","sources":["../src/data.module.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const data_module_1 = require("./data.module");
4
+ describe('DataModule', () => {
5
+ describe('forRoot', () => {
6
+ it('returns dynamic module structure', () => {
7
+ const result = data_module_1.DataModule.forRoot();
8
+ expect(result).toHaveProperty('module', data_module_1.DataModule);
9
+ expect(result).toHaveProperty('providers');
10
+ expect(result).toHaveProperty('exports');
11
+ expect(Array.isArray(result.providers)).toBe(true);
12
+ });
13
+ it('includes flink config when specified', () => {
14
+ const result = data_module_1.DataModule.forRoot({
15
+ flink: { url: 'http://flink:8081', timeout: 5000 },
16
+ });
17
+ const flinkConfig = result.providers.find((p) => p && typeof p === 'object' && 'provide' in p);
18
+ expect(flinkConfig).toBeDefined();
19
+ });
20
+ });
21
+ describe('getOptions', () => {
22
+ it('returns last forRoot options', () => {
23
+ data_module_1.DataModule.forRoot({ flink: { url: 'http://custom:8081' } });
24
+ const opts = data_module_1.DataModule.getOptions();
25
+ expect(opts.flink?.url).toBe('http://custom:8081');
26
+ });
27
+ });
28
+ });
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @hazeljs/data - Type definitions for ETL and streaming
3
+ */
4
+ export interface RetryConfig {
5
+ attempts: number;
6
+ delay?: number;
7
+ backoff?: 'fixed' | 'exponential';
8
+ }
9
+ export interface DLQConfig {
10
+ handler: (item: unknown, error: Error, stepName: string) => void | Promise<void>;
11
+ }
12
+ export interface PipelineStepMetadata {
13
+ step: number;
14
+ name: string;
15
+ type: 'transform' | 'validate';
16
+ schema?: unknown;
17
+ /** Run step only when predicate returns true */
18
+ when?: (data: unknown) => boolean;
19
+ /** Retry configuration for this step */
20
+ retry?: RetryConfig;
21
+ /** Per-step timeout in milliseconds */
22
+ timeoutMs?: number;
23
+ /** Dead letter queue handler - called instead of throwing on failure */
24
+ dlq?: DLQConfig;
25
+ }
26
+ export interface StreamMetadata {
27
+ name: string;
28
+ source: string;
29
+ sink: string;
30
+ parallelism?: number;
31
+ }
32
+ export interface FlinkJobConfig {
33
+ jobName?: string;
34
+ parallelism?: number;
35
+ checkpointInterval?: number;
36
+ restartStrategy?: {
37
+ type: string;
38
+ attempts?: number;
39
+ delay?: number;
40
+ };
41
+ resources?: {
42
+ taskManagerMemory?: string;
43
+ jobManagerMemory?: string;
44
+ cpuCores?: number;
45
+ };
46
+ stateBackend?: {
47
+ type: string;
48
+ checkpointPath?: string;
49
+ savepointPath?: string;
50
+ };
51
+ highAvailability?: {
52
+ type: string;
53
+ zookeeperQuorum?: string;
54
+ clusterId?: string;
55
+ };
56
+ metrics?: {
57
+ reporters?: string[];
58
+ interval?: number;
59
+ };
60
+ }
61
+ export interface FlinkAuthConfig {
62
+ type: 'basic' | 'token' | 'oauth';
63
+ username?: string;
64
+ password?: string;
65
+ token?: string;
66
+ }
67
+ //# sourceMappingURL=data.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.types.d.ts","sourceRoot":"","sources":["../src/data.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IAClC,wCAAwC;IACxC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,gBAAgB,CAAC,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * @hazeljs/data - Type definitions for ETL and streaming
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export { Pipeline, getPipelineMetadata, hasPipelineMetadata, type PipelineOptions, } from './pipeline.decorator';
2
+ export { Transform, getTransformMetadata, type TransformOptions } from './transform.decorator';
3
+ export { Validate, getValidateMetadata, type ValidateOptions } from './validate.decorator';
4
+ export { Stream, getStreamMetadata, hasStreamMetadata, type StreamOptions, } from './stream.decorator';
5
+ export { Mask, Redact, Encrypt, Decrypt, getMaskMetadata, getRedactMetadata, type MaskOptions, type RedactOptions, type EncryptOptions, type DecryptOptions, } from './pii.decorator';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EACL,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,IAAI,EACJ,MAAM,EACN,OAAO,EACP,OAAO,EACP,eAAe,EACf,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRedactMetadata = exports.getMaskMetadata = exports.Decrypt = exports.Encrypt = exports.Redact = exports.Mask = exports.hasStreamMetadata = exports.getStreamMetadata = exports.Stream = exports.getValidateMetadata = exports.Validate = exports.getTransformMetadata = exports.Transform = exports.hasPipelineMetadata = exports.getPipelineMetadata = exports.Pipeline = void 0;
4
+ var pipeline_decorator_1 = require("./pipeline.decorator");
5
+ Object.defineProperty(exports, "Pipeline", { enumerable: true, get: function () { return pipeline_decorator_1.Pipeline; } });
6
+ Object.defineProperty(exports, "getPipelineMetadata", { enumerable: true, get: function () { return pipeline_decorator_1.getPipelineMetadata; } });
7
+ Object.defineProperty(exports, "hasPipelineMetadata", { enumerable: true, get: function () { return pipeline_decorator_1.hasPipelineMetadata; } });
8
+ var transform_decorator_1 = require("./transform.decorator");
9
+ Object.defineProperty(exports, "Transform", { enumerable: true, get: function () { return transform_decorator_1.Transform; } });
10
+ Object.defineProperty(exports, "getTransformMetadata", { enumerable: true, get: function () { return transform_decorator_1.getTransformMetadata; } });
11
+ var validate_decorator_1 = require("./validate.decorator");
12
+ Object.defineProperty(exports, "Validate", { enumerable: true, get: function () { return validate_decorator_1.Validate; } });
13
+ Object.defineProperty(exports, "getValidateMetadata", { enumerable: true, get: function () { return validate_decorator_1.getValidateMetadata; } });
14
+ var stream_decorator_1 = require("./stream.decorator");
15
+ Object.defineProperty(exports, "Stream", { enumerable: true, get: function () { return stream_decorator_1.Stream; } });
16
+ Object.defineProperty(exports, "getStreamMetadata", { enumerable: true, get: function () { return stream_decorator_1.getStreamMetadata; } });
17
+ Object.defineProperty(exports, "hasStreamMetadata", { enumerable: true, get: function () { return stream_decorator_1.hasStreamMetadata; } });
18
+ var pii_decorator_1 = require("./pii.decorator");
19
+ Object.defineProperty(exports, "Mask", { enumerable: true, get: function () { return pii_decorator_1.Mask; } });
20
+ Object.defineProperty(exports, "Redact", { enumerable: true, get: function () { return pii_decorator_1.Redact; } });
21
+ Object.defineProperty(exports, "Encrypt", { enumerable: true, get: function () { return pii_decorator_1.Encrypt; } });
22
+ Object.defineProperty(exports, "Decrypt", { enumerable: true, get: function () { return pii_decorator_1.Decrypt; } });
23
+ Object.defineProperty(exports, "getMaskMetadata", { enumerable: true, get: function () { return pii_decorator_1.getMaskMetadata; } });
24
+ Object.defineProperty(exports, "getRedactMetadata", { enumerable: true, get: function () { return pii_decorator_1.getRedactMetadata; } });
@@ -0,0 +1,59 @@
1
+ import 'reflect-metadata';
2
+ export interface MaskOptions {
3
+ /** Fields to mask */
4
+ fields: string[];
5
+ /** Replacement string (default: "****") */
6
+ replacement?: string;
7
+ /** Show last N characters of the value (default: 0) */
8
+ showLast?: number;
9
+ }
10
+ /**
11
+ * Mask specified fields before the method runs.
12
+ *
13
+ * @example
14
+ * @Transform({ step: 1, name: 'sanitize' })
15
+ * @Mask({ fields: ['email', 'ssn'] })
16
+ * sanitize(data: User) { return data; }
17
+ */
18
+ export declare function Mask(fieldsOrOptions: string[] | MaskOptions): MethodDecorator;
19
+ export declare function getMaskMetadata(target: object, key: string | symbol): MaskOptions | undefined;
20
+ export interface RedactOptions {
21
+ fields: string[];
22
+ }
23
+ /**
24
+ * Remove specified fields entirely before the method runs.
25
+ *
26
+ * @example
27
+ * @Transform({ step: 2, name: 'redact' })
28
+ * @Redact({ fields: ['password', 'secretToken'] })
29
+ * redactSecrets(data: User) { return data; }
30
+ */
31
+ export declare function Redact(fieldsOrOptions: string[] | RedactOptions): MethodDecorator;
32
+ export declare function getRedactMetadata(target: object, key: string | symbol): RedactOptions | undefined;
33
+ export interface EncryptOptions {
34
+ fields: string[];
35
+ /** 32-byte AES-256-GCM key (hex string or Buffer) */
36
+ key: string | Buffer;
37
+ /** Optional AAD (additional authenticated data) for GCM */
38
+ aad?: string;
39
+ }
40
+ export interface DecryptOptions {
41
+ fields: string[];
42
+ key: string | Buffer;
43
+ aad?: string;
44
+ }
45
+ /**
46
+ * AES-256-GCM encrypt specified fields before the method runs.
47
+ * Encrypted values are stored as "iv:authTag:ciphertext" (all hex-encoded).
48
+ *
49
+ * @example
50
+ * @Transform({ step: 3, name: 'encrypt-pii' })
51
+ * @Encrypt({ fields: ['ssn', 'dob'], key: process.env.FIELD_ENCRYPTION_KEY! })
52
+ * encryptPii(data: User) { return data; }
53
+ */
54
+ export declare function Encrypt(options: EncryptOptions): MethodDecorator;
55
+ /**
56
+ * Decrypt fields that were encrypted with @Encrypt.
57
+ */
58
+ export declare function Decrypt(options: DecryptOptions): MethodDecorator;
59
+ //# sourceMappingURL=pii.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/pii.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAoB1B,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,WAAW,GAAG,eAAe,CAc7E;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAE7F;AAqCD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,aAAa,GAAG,eAAe,CAcjF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,SAAS,CAEjG;AAaD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,qDAAqD;IACrD,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAUhE;AA4BD;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAQhE"}
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Mask = Mask;
4
+ exports.getMaskMetadata = getMaskMetadata;
5
+ exports.Redact = Redact;
6
+ exports.getRedactMetadata = getRedactMetadata;
7
+ exports.Encrypt = Encrypt;
8
+ exports.Decrypt = Decrypt;
9
+ require("reflect-metadata");
10
+ /**
11
+ * PII-safety decorators for pipeline methods.
12
+ *
13
+ * These decorators run **before** the decorated method executes,
14
+ * modifying the data according to the specified operation.
15
+ *
16
+ * @Mask — replaces field values with "****"
17
+ * @Redact — removes fields entirely
18
+ * @Encrypt — AES-256-GCM encrypts field values (Node.js crypto required)
19
+ * @Decrypt — decrypts previously encrypted values
20
+ */
21
+ const MASK_METADATA_KEY = 'hazel:data:pii:mask';
22
+ const REDACT_METADATA_KEY = 'hazel:data:pii:redact';
23
+ const ENCRYPT_METADATA_KEY = 'hazel:data:pii:encrypt';
24
+ /**
25
+ * Mask specified fields before the method runs.
26
+ *
27
+ * @example
28
+ * @Transform({ step: 1, name: 'sanitize' })
29
+ * @Mask({ fields: ['email', 'ssn'] })
30
+ * sanitize(data: User) { return data; }
31
+ */
32
+ function Mask(fieldsOrOptions) {
33
+ const options = Array.isArray(fieldsOrOptions)
34
+ ? { fields: fieldsOrOptions }
35
+ : fieldsOrOptions;
36
+ return (target, propertyKey, descriptor) => {
37
+ Reflect.defineMetadata(MASK_METADATA_KEY, options, target, propertyKey);
38
+ const original = descriptor.value;
39
+ descriptor.value = function (data, ...rest) {
40
+ return original.call(this, applyMask(data, options), ...rest);
41
+ };
42
+ return descriptor;
43
+ };
44
+ }
45
+ function getMaskMetadata(target, key) {
46
+ return Reflect.getMetadata(MASK_METADATA_KEY, target, key);
47
+ }
48
+ function applyMask(data, options) {
49
+ const { fields, replacement = '****', showLast = 0 } = options;
50
+ if (!data || typeof data !== 'object')
51
+ return data;
52
+ const result = { ...data };
53
+ for (const field of fields) {
54
+ const parts = field.split('.');
55
+ maskNested(result, parts, replacement, showLast);
56
+ }
57
+ return result;
58
+ }
59
+ function maskNested(obj, path, replacement, showLast) {
60
+ if (path.length === 1) {
61
+ const val = obj[path[0]];
62
+ if (typeof val === 'string' && showLast > 0) {
63
+ obj[path[0]] = replacement + val.slice(-showLast);
64
+ }
65
+ else if (val !== undefined && val !== null) {
66
+ obj[path[0]] = replacement;
67
+ }
68
+ return;
69
+ }
70
+ const nested = obj[path[0]];
71
+ if (nested && typeof nested === 'object' && !Array.isArray(nested)) {
72
+ maskNested(nested, path.slice(1), replacement, showLast);
73
+ }
74
+ }
75
+ /**
76
+ * Remove specified fields entirely before the method runs.
77
+ *
78
+ * @example
79
+ * @Transform({ step: 2, name: 'redact' })
80
+ * @Redact({ fields: ['password', 'secretToken'] })
81
+ * redactSecrets(data: User) { return data; }
82
+ */
83
+ function Redact(fieldsOrOptions) {
84
+ const options = Array.isArray(fieldsOrOptions)
85
+ ? { fields: fieldsOrOptions }
86
+ : fieldsOrOptions;
87
+ return (target, propertyKey, descriptor) => {
88
+ Reflect.defineMetadata(REDACT_METADATA_KEY, options, target, propertyKey);
89
+ const original = descriptor.value;
90
+ descriptor.value = function (data, ...rest) {
91
+ return original.call(this, applyRedact(data, options), ...rest);
92
+ };
93
+ return descriptor;
94
+ };
95
+ }
96
+ function getRedactMetadata(target, key) {
97
+ return Reflect.getMetadata(REDACT_METADATA_KEY, target, key);
98
+ }
99
+ function applyRedact(data, options) {
100
+ if (!data || typeof data !== 'object')
101
+ return data;
102
+ const result = { ...data };
103
+ for (const field of options.fields) {
104
+ delete result[field];
105
+ }
106
+ return result;
107
+ }
108
+ /**
109
+ * AES-256-GCM encrypt specified fields before the method runs.
110
+ * Encrypted values are stored as "iv:authTag:ciphertext" (all hex-encoded).
111
+ *
112
+ * @example
113
+ * @Transform({ step: 3, name: 'encrypt-pii' })
114
+ * @Encrypt({ fields: ['ssn', 'dob'], key: process.env.FIELD_ENCRYPTION_KEY! })
115
+ * encryptPii(data: User) { return data; }
116
+ */
117
+ function Encrypt(options) {
118
+ return (target, propertyKey, descriptor) => {
119
+ Reflect.defineMetadata(ENCRYPT_METADATA_KEY, options, target, propertyKey);
120
+ const original = descriptor.value;
121
+ descriptor.value = function (data, ...rest) {
122
+ return original.call(this, applyEncrypt(data, options), ...rest);
123
+ };
124
+ return descriptor;
125
+ };
126
+ }
127
+ function applyEncrypt(data, options) {
128
+ if (!data || typeof data !== 'object')
129
+ return data;
130
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
131
+ const crypto = require('crypto');
132
+ const keyBuf = typeof options.key === 'string' ? Buffer.from(options.key, 'hex') : options.key;
133
+ const result = { ...data };
134
+ for (const field of options.fields) {
135
+ const val = result[field];
136
+ if (val === undefined || val === null)
137
+ continue;
138
+ const iv = crypto.randomBytes(12);
139
+ const cipher = crypto.createCipheriv('aes-256-gcm', keyBuf, iv);
140
+ if (options.aad)
141
+ cipher.setAAD(Buffer.from(options.aad));
142
+ const plaintext = typeof val === 'string' ? val : JSON.stringify(val);
143
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
144
+ const authTag = cipher.getAuthTag();
145
+ result[field] = `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;
146
+ }
147
+ return result;
148
+ }
149
+ /**
150
+ * Decrypt fields that were encrypted with @Encrypt.
151
+ */
152
+ function Decrypt(options) {
153
+ return (_target, _propertyKey, descriptor) => {
154
+ const original = descriptor.value;
155
+ descriptor.value = function (data, ...rest) {
156
+ return original.call(this, applyDecrypt(data, options), ...rest);
157
+ };
158
+ return descriptor;
159
+ };
160
+ }
161
+ function applyDecrypt(data, options) {
162
+ if (!data || typeof data !== 'object')
163
+ return data;
164
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
165
+ const crypto = require('crypto');
166
+ const keyBuf = typeof options.key === 'string' ? Buffer.from(options.key, 'hex') : options.key;
167
+ const result = { ...data };
168
+ for (const field of options.fields) {
169
+ const val = result[field];
170
+ if (typeof val !== 'string')
171
+ continue;
172
+ const parts = val.split(':');
173
+ if (parts.length !== 3)
174
+ continue;
175
+ try {
176
+ const [ivHex, authTagHex, ciphertextHex] = parts;
177
+ const iv = Buffer.from(ivHex, 'hex');
178
+ const authTag = Buffer.from(authTagHex, 'hex');
179
+ const ciphertext = Buffer.from(ciphertextHex, 'hex');
180
+ const decipher = crypto.createDecipheriv('aes-256-gcm', keyBuf, iv);
181
+ decipher.setAuthTag(authTag);
182
+ if (options.aad)
183
+ decipher.setAAD(Buffer.from(options.aad));
184
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('utf8');
185
+ try {
186
+ result[field] = JSON.parse(decrypted);
187
+ }
188
+ catch {
189
+ result[field] = decrypted;
190
+ }
191
+ }
192
+ catch {
193
+ // Leave as-is if decryption fails
194
+ }
195
+ }
196
+ return result;
197
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pii.decorator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii.decorator.test.d.ts","sourceRoot":"","sources":["../../src/decorators/pii.decorator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,150 @@
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
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const pipeline_decorator_1 = require("./pipeline.decorator");
13
+ const transform_decorator_1 = require("./transform.decorator");
14
+ const pii_decorator_1 = require("./pii.decorator");
15
+ const etl_service_1 = require("../pipelines/etl.service");
16
+ const schema_validator_1 = require("../validators/schema.validator");
17
+ let MaskPipeline = class MaskPipeline {
18
+ mask(data) {
19
+ return data;
20
+ }
21
+ };
22
+ __decorate([
23
+ (0, transform_decorator_1.Transform)({ step: 1, name: 'mask' }),
24
+ (0, pii_decorator_1.Mask)({ fields: ['email', 'ssn'] }),
25
+ __metadata("design:type", Function),
26
+ __metadata("design:paramtypes", [Object]),
27
+ __metadata("design:returntype", void 0)
28
+ ], MaskPipeline.prototype, "mask", null);
29
+ MaskPipeline = __decorate([
30
+ (0, pipeline_decorator_1.Pipeline)('mask-pipeline')
31
+ ], MaskPipeline);
32
+ let MaskShowLastPipeline = class MaskShowLastPipeline {
33
+ mask(data) {
34
+ return data;
35
+ }
36
+ };
37
+ __decorate([
38
+ (0, transform_decorator_1.Transform)({ step: 1, name: 'mask' }),
39
+ (0, pii_decorator_1.Mask)({ fields: ['phone'], replacement: '***', showLast: 4 }),
40
+ __metadata("design:type", Function),
41
+ __metadata("design:paramtypes", [Object]),
42
+ __metadata("design:returntype", void 0)
43
+ ], MaskShowLastPipeline.prototype, "mask", null);
44
+ MaskShowLastPipeline = __decorate([
45
+ (0, pipeline_decorator_1.Pipeline)('mask-showlast')
46
+ ], MaskShowLastPipeline);
47
+ let RedactPipeline = class RedactPipeline {
48
+ redact(data) {
49
+ return data;
50
+ }
51
+ };
52
+ __decorate([
53
+ (0, transform_decorator_1.Transform)({ step: 1, name: 'redact' }),
54
+ (0, pii_decorator_1.Redact)({ fields: ['password', 'secret'] }),
55
+ __metadata("design:type", Function),
56
+ __metadata("design:paramtypes", [Object]),
57
+ __metadata("design:returntype", void 0)
58
+ ], RedactPipeline.prototype, "redact", null);
59
+ RedactPipeline = __decorate([
60
+ (0, pipeline_decorator_1.Pipeline)('redact-pipeline')
61
+ ], RedactPipeline);
62
+ describe('@Mask decorator', () => {
63
+ it('masks specified fields', async () => {
64
+ const etl = new etl_service_1.ETLService(new schema_validator_1.SchemaValidator());
65
+ const pipeline = new MaskPipeline();
66
+ const result = await etl.execute(pipeline, {
67
+ email: 'user@example.com',
68
+ ssn: '123-45-6789',
69
+ name: 'John',
70
+ });
71
+ expect(result.email).toBe('****');
72
+ expect(result.ssn).toBe('****');
73
+ expect(result.name).toBe('John');
74
+ });
75
+ it('showLast shows last N chars', async () => {
76
+ const etl = new etl_service_1.ETLService(new schema_validator_1.SchemaValidator());
77
+ const pipeline = new MaskShowLastPipeline();
78
+ const result = await etl.execute(pipeline, {
79
+ phone: '1234567890',
80
+ });
81
+ expect(result.phone).toBe('***7890');
82
+ });
83
+ it('getMaskMetadata returns options', () => {
84
+ const meta = (0, pii_decorator_1.getMaskMetadata)(MaskPipeline.prototype, 'mask');
85
+ expect(meta?.fields).toContain('email');
86
+ expect(meta?.fields).toContain('ssn');
87
+ });
88
+ });
89
+ describe('@Redact decorator', () => {
90
+ it('removes specified fields', async () => {
91
+ const etl = new etl_service_1.ETLService(new schema_validator_1.SchemaValidator());
92
+ const pipeline = new RedactPipeline();
93
+ const result = await etl.execute(pipeline, {
94
+ password: 'secret123',
95
+ secret: 'key',
96
+ name: 'John',
97
+ });
98
+ expect(result.password).toBeUndefined();
99
+ expect(result.secret).toBeUndefined();
100
+ expect(result.name).toBe('John');
101
+ });
102
+ it('getRedactMetadata returns options', () => {
103
+ const meta = (0, pii_decorator_1.getRedactMetadata)(RedactPipeline.prototype, 'redact');
104
+ expect(meta?.fields).toContain('password');
105
+ });
106
+ it('Mask with array shorthand', async () => {
107
+ let MaskArrayPipeline = class MaskArrayPipeline {
108
+ mask(data) {
109
+ return data;
110
+ }
111
+ };
112
+ __decorate([
113
+ (0, transform_decorator_1.Transform)({ step: 1, name: 'mask' }),
114
+ (0, pii_decorator_1.Mask)(['secret']),
115
+ __metadata("design:type", Function),
116
+ __metadata("design:paramtypes", [Object]),
117
+ __metadata("design:returntype", void 0)
118
+ ], MaskArrayPipeline.prototype, "mask", null);
119
+ MaskArrayPipeline = __decorate([
120
+ (0, pipeline_decorator_1.Pipeline)('mask-array')
121
+ ], MaskArrayPipeline);
122
+ const etl = new etl_service_1.ETLService(new schema_validator_1.SchemaValidator());
123
+ const result = await etl.execute(new MaskArrayPipeline(), {
124
+ secret: 'x',
125
+ ok: 1,
126
+ });
127
+ expect(result.secret).toBe('****');
128
+ expect(result.ok).toBe(1);
129
+ });
130
+ it('Mask leaves non-object unchanged', async () => {
131
+ let MaskNonObjPipeline = class MaskNonObjPipeline {
132
+ mask(data) {
133
+ return data;
134
+ }
135
+ };
136
+ __decorate([
137
+ (0, transform_decorator_1.Transform)({ step: 1, name: 'mask' }),
138
+ (0, pii_decorator_1.Mask)(['x']),
139
+ __metadata("design:type", Function),
140
+ __metadata("design:paramtypes", [Object]),
141
+ __metadata("design:returntype", void 0)
142
+ ], MaskNonObjPipeline.prototype, "mask", null);
143
+ MaskNonObjPipeline = __decorate([
144
+ (0, pipeline_decorator_1.Pipeline)('mask-nonobj')
145
+ ], MaskNonObjPipeline);
146
+ const etl = new etl_service_1.ETLService(new schema_validator_1.SchemaValidator());
147
+ const result = await etl.execute(new MaskNonObjPipeline(), 'string');
148
+ expect(result).toBe('string');
149
+ });
150
+ });
@@ -0,0 +1,22 @@
1
+ import 'reflect-metadata';
2
+ export interface PipelineOptions {
3
+ name?: string;
4
+ }
5
+ /**
6
+ * @Pipeline decorator - Mark a class as an ETL pipeline with sequential step execution
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * @Pipeline('user-enrichment')
11
+ * @Injectable()
12
+ * export class UserEnrichmentPipeline {
13
+ * @Transform({ step: 1, name: 'normalize' }) async normalize(data) { ... }
14
+ * @Validate({ step: 2, name: 'validate', schema: Schema.object({...}) }) async validate(data) { ... }
15
+ * @Transform({ step: 3, name: 'enrich' }) async enrich(data) { ... }
16
+ * }
17
+ * ```
18
+ */
19
+ export declare function Pipeline(nameOrOptions?: string | PipelineOptions): ClassDecorator;
20
+ export declare function getPipelineMetadata(target: object): PipelineOptions | undefined;
21
+ export declare function hasPipelineMetadata(target: object): boolean;
22
+ //# sourceMappingURL=pipeline.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/pipeline.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAK1B,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,cAAc,CAWjF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAE/E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3D"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Pipeline = Pipeline;
7
+ exports.getPipelineMetadata = getPipelineMetadata;
8
+ exports.hasPipelineMetadata = hasPipelineMetadata;
9
+ require("reflect-metadata");
10
+ const core_1 = __importDefault(require("@hazeljs/core"));
11
+ const PIPELINE_METADATA_KEY = 'hazel:data:pipeline';
12
+ /**
13
+ * @Pipeline decorator - Mark a class as an ETL pipeline with sequential step execution
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * @Pipeline('user-enrichment')
18
+ * @Injectable()
19
+ * export class UserEnrichmentPipeline {
20
+ * @Transform({ step: 1, name: 'normalize' }) async normalize(data) { ... }
21
+ * @Validate({ step: 2, name: 'validate', schema: Schema.object({...}) }) async validate(data) { ... }
22
+ * @Transform({ step: 3, name: 'enrich' }) async enrich(data) { ... }
23
+ * }
24
+ * ```
25
+ */
26
+ function Pipeline(nameOrOptions) {
27
+ return (target) => {
28
+ const options = typeof nameOrOptions === 'string' ? { name: nameOrOptions } : nameOrOptions || {};
29
+ const metadata = {
30
+ name: options.name ?? target.name ?? 'unknown',
31
+ ...options,
32
+ };
33
+ Reflect.defineMetadata(PIPELINE_METADATA_KEY, metadata, target);
34
+ core_1.default.debug(`Pipeline decorator applied: ${metadata.name}`);
35
+ };
36
+ }
37
+ function getPipelineMetadata(target) {
38
+ return Reflect.getMetadata(PIPELINE_METADATA_KEY, target);
39
+ }
40
+ function hasPipelineMetadata(target) {
41
+ return Reflect.hasMetadata(PIPELINE_METADATA_KEY, target);
42
+ }
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ //# sourceMappingURL=pipeline.decorator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.decorator.test.d.ts","sourceRoot":"","sources":["../../src/decorators/pipeline.decorator.test.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC"}