@cqrs-ddd/pipeline-feature-flags 0.0.0-stage → 0.5.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 (44) hide show
  1. package/COMMERCIAL_LICENSE.txt +34 -0
  2. package/LICENSE +661 -0
  3. package/README.md +35 -2
  4. package/dist/errors/feature-disabled.error.d.ts +15 -0
  5. package/dist/errors/feature-disabled.error.d.ts.map +1 -0
  6. package/dist/errors/feature-disabled.error.js +21 -0
  7. package/dist/errors/feature-disabled.error.js.map +1 -0
  8. package/dist/errors/feature-flag-evaluation.error.d.ts +17 -0
  9. package/dist/errors/feature-flag-evaluation.error.d.ts.map +1 -0
  10. package/dist/errors/feature-flag-evaluation.error.js +24 -0
  11. package/dist/errors/feature-flag-evaluation.error.js.map +1 -0
  12. package/dist/feature-flag.behavior.d.ts +148 -0
  13. package/dist/feature-flag.behavior.d.ts.map +1 -0
  14. package/dist/feature-flag.behavior.js +261 -0
  15. package/dist/feature-flag.behavior.js.map +1 -0
  16. package/dist/helpers/build-attributes.d.ts +48 -0
  17. package/dist/helpers/build-attributes.d.ts.map +1 -0
  18. package/dist/helpers/build-attributes.js +63 -0
  19. package/dist/helpers/build-attributes.js.map +1 -0
  20. package/dist/helpers/evaluation-context.d.ts +17 -0
  21. package/dist/helpers/evaluation-context.d.ts.map +1 -0
  22. package/dist/helpers/evaluation-context.js +33 -0
  23. package/dist/helpers/evaluation-context.js.map +1 -0
  24. package/dist/helpers/feature-flag-client.d.ts +27 -0
  25. package/dist/helpers/feature-flag-client.d.ts.map +1 -0
  26. package/dist/helpers/feature-flag-client.js +57 -0
  27. package/dist/helpers/feature-flag-client.js.map +1 -0
  28. package/dist/helpers/feature-flag.intent.d.ts +22 -0
  29. package/dist/helpers/feature-flag.intent.d.ts.map +1 -0
  30. package/dist/helpers/feature-flag.intent.js +20 -0
  31. package/dist/helpers/feature-flag.intent.js.map +1 -0
  32. package/dist/http.d.ts +21 -0
  33. package/dist/http.d.ts.map +1 -0
  34. package/dist/http.js +31 -0
  35. package/dist/http.js.map +1 -0
  36. package/dist/index.d.ts +14 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +14 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/interfaces/feature-flags-options.interface.d.ts +154 -0
  41. package/dist/interfaces/feature-flags-options.interface.d.ts.map +1 -0
  42. package/dist/interfaces/feature-flags-options.interface.js +3 -0
  43. package/dist/interfaces/feature-flags-options.interface.js.map +1 -0
  44. package/package.json +67 -3
@@ -0,0 +1,63 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { getPipelineItem } from '@cqrs-ddd/pipeline';
3
+ import { FEATURE_FLAG_DECISION_ITEM_TOKEN } from '../feature-flag.behavior.js';
4
+ /**
5
+ * The feature-flag decision of one execution as flat attributes, named after
6
+ * the OpenTelemetry feature-flag conventions: `feature_flag.key` and
7
+ * `feature_flag.enabled`, plus `feature_flag.variant` and `feature_flag.reason`
8
+ * when the provider reported them, and `feature_flag.error_code` only when
9
+ * evaluation failed. `{}` when `FeatureFlagBehavior` did not run. The targeting
10
+ * key and the provider's error message are never included.
11
+ *
12
+ * The result is plain data and needs no telemetry package: put it on a span, a
13
+ * log line, an audit record or a metric label (bounded values only).
14
+ *
15
+ * @param context - The pipeline execution, read after `FeatureFlagBehavior` ran.
16
+ * @returns The attributes; empty when the behavior did not run.
17
+ *
18
+ * @example Span attributes
19
+ * With `AttributesBehavior` of `@cqrs-ddd/pipeline-opentelemetry`:
20
+ * ```ts
21
+ * createPipeline({
22
+ * globalBehaviors: {
23
+ * before: [TraceBehavior, [AttributesBehavior, { factories: [buildFeatureFlagAttributes] }]],
24
+ * },
25
+ * });
26
+ * ```
27
+ *
28
+ * @example Audit metadata
29
+ * `audit()` is declared outside `featureFlag()`, so the record is built after its decision:
30
+ * ```ts
31
+ * @pipeline.wrap(
32
+ * { kind: 'command' },
33
+ * audit({ action: 'order.create', metadata: buildFeatureFlagAttributes }),
34
+ * featureFlag({ flag: 'checkout' }),
35
+ * )
36
+ * ```
37
+ *
38
+ * @example A log line from a custom behavior, after the chain ran
39
+ * ```ts
40
+ * async handle(context: IPipelineContext, next: NextDelegate) {
41
+ * try {
42
+ * return await next();
43
+ * } finally {
44
+ * this.logger.log({ request: context.requestName, ...buildFeatureFlagAttributes(context) });
45
+ * }
46
+ * }
47
+ * ```
48
+ */
49
+ export function buildFeatureFlagAttributes(context) {
50
+ const decision = getPipelineItem(context, FEATURE_FLAG_DECISION_ITEM_TOKEN);
51
+ if (!decision)
52
+ return {};
53
+ return {
54
+ 'feature_flag.key': decision.flagKey,
55
+ 'feature_flag.enabled': decision.enabled,
56
+ ...(decision.variant ? { 'feature_flag.variant': decision.variant } : {}),
57
+ ...(decision.reason ? { 'feature_flag.reason': decision.reason } : {}),
58
+ ...(decision.errorCode
59
+ ? { 'feature_flag.error_code': decision.errorCode }
60
+ : {}),
61
+ };
62
+ }
63
+ //# sourceMappingURL=build-attributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-attributes.js","sourceRoot":"","sources":["../../src/helpers/build-attributes.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAAE,eAAe,EAAyB,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAyB;IAEzB,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC;IAC5E,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,OAAO;QACL,kBAAkB,EAAE,QAAQ,CAAC,OAAO;QACpC,sBAAsB,EAAE,QAAQ,CAAC,OAAO;QACxC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,GAAG,CAAC,QAAQ,CAAC,SAAS;YACpB,CAAC,CAAC,EAAE,yBAAyB,EAAE,QAAQ,CAAC,SAAS,EAAE;YACnD,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { IPipelineContext } from '@cqrs-ddd/pipeline';
2
+ import type { EvaluationContext } from '@openfeature/server-sdk';
3
+ import type { EvaluationContextFactory, TargetingKeyFactory } from '../interfaces/feature-flags-options.interface.js';
4
+ /**
5
+ * Base OpenFeature attributes derived from the live pipeline request. It sets no
6
+ * `targetingKey`; that comes from `targetingKeyFactory`.
7
+ */
8
+ export declare function baseEvaluationContext(context: IPipelineContext): EvaluationContext;
9
+ /**
10
+ * Builds an evaluation context in this order:
11
+ * base pipeline attributes → module context → handler context → targeting-key factory.
12
+ *
13
+ * A targeting key already provided by module/handler context is preserved when
14
+ * the factory returns `undefined`. A non-empty factory result wins when present.
15
+ */
16
+ export declare function buildEvaluationContext(context: IPipelineContext, moduleContext?: EvaluationContext, handlerContext?: EvaluationContextFactory, targetingKeyFactory?: TargetingKeyFactory): EvaluationContext;
17
+ //# sourceMappingURL=evaluation-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-context.d.ts","sourceRoot":"","sources":["../../src/helpers/evaluation-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EACV,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,kDAAkD,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,GACxB,iBAAiB,CAQnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,aAAa,CAAC,EAAE,iBAAiB,EACjC,cAAc,CAAC,EAAE,wBAAwB,EACzC,mBAAmB,CAAC,EAAE,mBAAmB,GACxC,iBAAiB,CAWnB"}
@@ -0,0 +1,33 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ /**
3
+ * Base OpenFeature attributes derived from the live pipeline request. It sets no
4
+ * `targetingKey`; that comes from `targetingKeyFactory`.
5
+ */
6
+ export function baseEvaluationContext(context) {
7
+ return {
8
+ 'pipeline.request.kind': context.requestKind,
9
+ 'pipeline.request.name': context.requestName,
10
+ 'pipeline.handler.name': context.handlerName,
11
+ 'pipeline.correlation_id': context.correlationId,
12
+ ...(context.tenantId ? { 'pipeline.tenant_id': context.tenantId } : {}),
13
+ };
14
+ }
15
+ /**
16
+ * Builds an evaluation context in this order:
17
+ * base pipeline attributes → module context → handler context → targeting-key factory.
18
+ *
19
+ * A targeting key already provided by module/handler context is preserved when
20
+ * the factory returns `undefined`. A non-empty factory result wins when present.
21
+ */
22
+ export function buildEvaluationContext(context, moduleContext, handlerContext, targetingKeyFactory) {
23
+ const result = {
24
+ ...baseEvaluationContext(context),
25
+ ...moduleContext,
26
+ ...handlerContext?.(context),
27
+ };
28
+ const targetingKey = targetingKeyFactory?.(context)?.trim();
29
+ if (targetingKey)
30
+ result.targetingKey = targetingKey;
31
+ return result;
32
+ }
33
+ //# sourceMappingURL=evaluation-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-context.js","sourceRoot":"","sources":["../../src/helpers/evaluation-context.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAStE;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAyB;IAEzB,OAAO;QACL,uBAAuB,EAAE,OAAO,CAAC,WAAW;QAC5C,uBAAuB,EAAE,OAAO,CAAC,WAAW;QAC5C,uBAAuB,EAAE,OAAO,CAAC,WAAW;QAC5C,yBAAyB,EAAE,OAAO,CAAC,aAAa;QAChD,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxE,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAyB,EACzB,aAAiC,EACjC,cAAyC,EACzC,mBAAyC;IAEzC,MAAM,MAAM,GAAsB;QAChC,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACjC,GAAG,aAAa;QAChB,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC;KAC7B,CAAC;IAEF,MAAM,YAAY,GAAG,mBAAmB,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC;IAC5D,IAAI,YAAY;QAAE,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;IAErD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type Client } from '@openfeature/server-sdk';
2
+ import type { FeatureFlagClientOptions } from '../interfaces/feature-flags-options.interface.js';
3
+ /**
4
+ * Resolves the OpenFeature client a {@link FeatureFlagBehavior} evaluates with: the given
5
+ * `client`, or the client of `domain` (the default client without one) after registering
6
+ * `provider`, waiting for it to be ready unless `waitForReady` is `false`.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const client = await createFeatureFlagClient({ provider: new UnleashProvider(config) });
11
+ * const behavior = new FeatureFlagBehavior(client);
12
+ * ```
13
+ */
14
+ export declare function createFeatureFlagClient(options?: FeatureFlagClientOptions): Promise<Client>;
15
+ /**
16
+ * Unregisters the provider that {@link createFeatureFlagClient} registered for the same
17
+ * `options`, for shutdown: the domain falls back to OpenFeature's no-op provider. Does
18
+ * nothing when `options` gave a `client`, gave no `provider`, or another provider has
19
+ * replaced it since.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * process.on('SIGTERM', () => releaseFeatureFlagProvider(options));
24
+ * ```
25
+ */
26
+ export declare function releaseFeatureFlagProvider(options?: FeatureFlagClientOptions): Promise<void>;
27
+ //# sourceMappingURL=feature-flag-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag-client.d.ts","sourceRoot":"","sources":["../../src/helpers/feature-flag-client.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kDAAkD,CAAC;AAEjG;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -0,0 +1,57 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { NOOP_PROVIDER, OpenFeature, } from '@openfeature/server-sdk';
3
+ /**
4
+ * Resolves the OpenFeature client a {@link FeatureFlagBehavior} evaluates with: the given
5
+ * `client`, or the client of `domain` (the default client without one) after registering
6
+ * `provider`, waiting for it to be ready unless `waitForReady` is `false`.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const client = await createFeatureFlagClient({ provider: new UnleashProvider(config) });
11
+ * const behavior = new FeatureFlagBehavior(client);
12
+ * ```
13
+ */
14
+ export async function createFeatureFlagClient(options = {}) {
15
+ if (options.client)
16
+ return options.client;
17
+ if (options.provider) {
18
+ if (options.waitForReady === false) {
19
+ options.domain
20
+ ? OpenFeature.setProvider(options.domain, options.provider)
21
+ : OpenFeature.setProvider(options.provider);
22
+ }
23
+ else {
24
+ await (options.domain
25
+ ? OpenFeature.setProviderAndWait(options.domain, options.provider)
26
+ : OpenFeature.setProviderAndWait(options.provider));
27
+ }
28
+ }
29
+ return options.domain
30
+ ? OpenFeature.getClient(options.domain)
31
+ : OpenFeature.getClient();
32
+ }
33
+ /**
34
+ * Unregisters the provider that {@link createFeatureFlagClient} registered for the same
35
+ * `options`, for shutdown: the domain falls back to OpenFeature's no-op provider. Does
36
+ * nothing when `options` gave a `client`, gave no `provider`, or another provider has
37
+ * replaced it since.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * process.on('SIGTERM', () => releaseFeatureFlagProvider(options));
42
+ * ```
43
+ */
44
+ export async function releaseFeatureFlagProvider(options = {}) {
45
+ const { client, provider, domain } = options;
46
+ if (client || !provider)
47
+ return;
48
+ const current = domain
49
+ ? OpenFeature.getProvider(domain)
50
+ : OpenFeature.getProvider();
51
+ if (current !== provider)
52
+ return;
53
+ await (domain
54
+ ? OpenFeature.setProviderAndWait(domain, NOOP_PROVIDER)
55
+ : OpenFeature.setProviderAndWait(NOOP_PROVIDER));
56
+ }
57
+ //# sourceMappingURL=feature-flag-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag-client.js","sourceRoot":"","sources":["../../src/helpers/feature-flag-client.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,OAAO,EAEL,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAO,GAA6B,EAAE;IAEtC,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC;IAC1C,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;YACnC,OAAO,CAAC,MAAM;gBACZ,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;gBAC3D,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,MAAM;gBACnB,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;gBAClE,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC,MAAM;QACnB,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QACvC,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAO,GAA6B,EAAE;IAEtC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC7C,IAAI,MAAM,IAAI,CAAC,QAAQ;QAAE,OAAO;IAChC,MAAM,OAAO,GAAG,MAAM;QACpB,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC;QACjC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IAC9B,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO;IACjC,MAAM,CAAC,MAAM;QACX,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,MAAM,EAAE,aAAa,CAAC;QACvD,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { PipelineBehaviorTuple } from '@cqrs-ddd/pipeline';
2
+ import { FeatureFlagBehavior } from '../feature-flag.behavior.js';
3
+ import type { FeatureFlagBehaviorOptions } from '../interfaces/feature-flags-options.interface.js';
4
+ export type FeatureFlagIntentOptions = FeatureFlagBehaviorOptions & {
5
+ flag: string;
6
+ };
7
+ /**
8
+ * Returns a feature-flag behavior entry for `pipeline.wrap()` or `createPipeline({ globalBehaviors })`.
9
+ * @param options Required flag key plus evaluation and fallback options.
10
+ * @returns The behavior class and options tuple. A disabled flag prevents handler
11
+ * execution; the behavior returns the configured fallback or throws FeatureDisabledError.
12
+ * @example
13
+ * ```ts
14
+ * @pipeline.wrap({ kind: 'command' }, featureFlag({
15
+ * flag: 'user-registration',
16
+ * defaultValue: false,
17
+ * fallback: () => ({ disabled: true }),
18
+ * }))
19
+ * ```
20
+ */
21
+ export declare function featureFlag(options: FeatureFlagIntentOptions): PipelineBehaviorTuple<FeatureFlagBehavior, FeatureFlagBehaviorOptions>;
22
+ //# sourceMappingURL=feature-flag.intent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.intent.d.ts","sourceRoot":"","sources":["../../src/helpers/feature-flag.intent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAEnG,MAAM,MAAM,wBAAwB,GAAG,0BAA0B,GAAG;IAClE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,wBAAwB,GAChC,qBAAqB,CAAC,mBAAmB,EAAE,0BAA0B,CAAC,CAExE"}
@@ -0,0 +1,20 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ import { FeatureFlagBehavior } from '../feature-flag.behavior.js';
3
+ /**
4
+ * Returns a feature-flag behavior entry for `pipeline.wrap()` or `createPipeline({ globalBehaviors })`.
5
+ * @param options Required flag key plus evaluation and fallback options.
6
+ * @returns The behavior class and options tuple. A disabled flag prevents handler
7
+ * execution; the behavior returns the configured fallback or throws FeatureDisabledError.
8
+ * @example
9
+ * ```ts
10
+ * @pipeline.wrap({ kind: 'command' }, featureFlag({
11
+ * flag: 'user-registration',
12
+ * defaultValue: false,
13
+ * fallback: () => ({ disabled: true }),
14
+ * }))
15
+ * ```
16
+ */
17
+ export function featureFlag(options) {
18
+ return [FeatureFlagBehavior, options];
19
+ }
20
+ //# sourceMappingURL=feature-flag.intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flag.intent.js","sourceRoot":"","sources":["../../src/helpers/feature-flag.intent.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAGtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAOlE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CACzB,OAAiC;IAEjC,OAAO,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { FeatureDisabledError } from './errors/feature-disabled.error.js';
2
+ /** An HTTP answer for an error: status, JSON body and headers. */
3
+ export interface HttpResponse {
4
+ status: number;
5
+ body: Record<string, unknown>;
6
+ headers: Record<string, string>;
7
+ }
8
+ /**
9
+ * The HTTP answer for a {@link FeatureDisabledError}: `403 Forbidden` naming the flag, or
10
+ * with `hideFeature` a plain `404 Not Found` that does not reveal the feature exists.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const { status, body } = toHttpResponse(error, { hideFeature: true });
15
+ * res.status(status).json(body);
16
+ * ```
17
+ */
18
+ export declare function toHttpResponse(error: FeatureDisabledError, options?: {
19
+ hideFeature?: boolean;
20
+ }): HttpResponse;
21
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAE/E,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,oBAAoB,EAC3B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,YAAY,CAkBd"}
package/dist/http.js ADDED
@@ -0,0 +1,31 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ /**
3
+ * The HTTP answer for a {@link FeatureDisabledError}: `403 Forbidden` naming the flag, or
4
+ * with `hideFeature` a plain `404 Not Found` that does not reveal the feature exists.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const { status, body } = toHttpResponse(error, { hideFeature: true });
9
+ * res.status(status).json(body);
10
+ * ```
11
+ */
12
+ export function toHttpResponse(error, options = {}) {
13
+ if (options.hideFeature) {
14
+ return {
15
+ status: 404,
16
+ body: { statusCode: 404, error: 'Not Found', message: 'Not Found' },
17
+ headers: {},
18
+ };
19
+ }
20
+ return {
21
+ status: 403,
22
+ body: {
23
+ statusCode: 403,
24
+ error: 'Forbidden',
25
+ message: error.message,
26
+ flag: error.flag,
27
+ },
28
+ headers: {},
29
+ };
30
+ }
31
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAWtE;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,KAA2B,EAC3B,OAAO,GAA8B,EAAE;IAEvC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE;YACnE,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IACD,OAAO;QACL,MAAM,EAAE,GAAG;QACX,IAAI,EAAE;YACJ,UAAU,EAAE,GAAG;YACf,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB;QACD,OAAO,EAAE,EAAE;KACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * OpenFeature gates for wrapped functions and methods: the behavior, the client factory and `featureFlag()`. The HTTP mapping of its errors is the `@cqrs-ddd/pipeline-feature-flags/http` entry point.
3
+ *
4
+ * @module main
5
+ */
6
+ export { FeatureDisabledError } from './errors/feature-disabled.error.js';
7
+ export { FeatureFlagEvaluationError } from './errors/feature-flag-evaluation.error.js';
8
+ export { FEATURE_FLAG_DECISION_ITEM, FEATURE_FLAG_DECISION_ITEM_TOKEN, FEATURE_FLAG_ITEM, FEATURE_FLAG_ITEM_TOKEN, FEATURE_FLAG_KEY_ITEM, FEATURE_FLAG_KEY_ITEM_TOKEN, FeatureFlagBehavior, } from './feature-flag.behavior.js';
9
+ export { buildFeatureFlagAttributes } from './helpers/build-attributes.js';
10
+ export { baseEvaluationContext, buildEvaluationContext, } from './helpers/evaluation-context.js';
11
+ export { type FeatureFlagIntentOptions, featureFlag, } from './helpers/feature-flag.intent.js';
12
+ export { createFeatureFlagClient, releaseFeatureFlagProvider, } from './helpers/feature-flag-client.js';
13
+ export type { EvaluationContextFactory, FeatureFallbackFactory, FeatureFlagBehaviorOptions, FeatureFlagClientOptions, FeatureFlagDecision, FeatureFlagErrorPolicy, TargetingKeyFactory, } from './interfaces/feature-flags-options.interface.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,wBAAwB,EAC7B,WAAW,GACZ,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EACV,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,iDAAiD,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ /**
3
+ * OpenFeature gates for wrapped functions and methods: the behavior, the client factory and `featureFlag()`. The HTTP mapping of its errors is the `@cqrs-ddd/pipeline-feature-flags/http` entry point.
4
+ *
5
+ * @module main
6
+ */
7
+ export { FeatureDisabledError } from './errors/feature-disabled.error.js';
8
+ export { FeatureFlagEvaluationError } from './errors/feature-flag-evaluation.error.js';
9
+ export { FEATURE_FLAG_DECISION_ITEM, FEATURE_FLAG_DECISION_ITEM_TOKEN, FEATURE_FLAG_ITEM, FEATURE_FLAG_ITEM_TOKEN, FEATURE_FLAG_KEY_ITEM, FEATURE_FLAG_KEY_ITEM_TOKEN, FeatureFlagBehavior, } from './feature-flag.behavior.js';
10
+ export { buildFeatureFlagAttributes } from './helpers/build-attributes.js';
11
+ export { baseEvaluationContext, buildEvaluationContext, } from './helpers/evaluation-context.js';
12
+ export { featureFlag, } from './helpers/feature-flag.intent.js';
13
+ export { createFeatureFlagClient, releaseFeatureFlagProvider, } from './helpers/feature-flag-client.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE;;;;GAIG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,EAChC,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,WAAW,GACZ,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,154 @@
1
+ import type { IPipelineContext } from '@cqrs-ddd/pipeline';
2
+ import type { Client, EvaluationContext, Provider } from '@openfeature/server-sdk';
3
+ /**
4
+ * Builds an OpenFeature {@link EvaluationContext} from the current pipeline
5
+ * request — letting flag targeting rules key off the live request/handler.
6
+ */
7
+ export type EvaluationContextFactory = (context: IPipelineContext) => EvaluationContext;
8
+ /**
9
+ * Resolves a stable OpenFeature targeting key from the current pipeline request.
10
+ *
11
+ * For percentage rollouts this should normally be a user, account, tenant or
12
+ * device identifier that stays stable across requests.
13
+ */
14
+ export type TargetingKeyFactory = (context: IPipelineContext) => string | undefined;
15
+ /**
16
+ * Returns a fallback value to emit when the gating flag is disabled, instead of
17
+ * throwing {@link FeatureDisabledError}. Receives the pipeline context so the
18
+ * fallback can be request-aware.
19
+ */
20
+ export type FeatureFallbackFactory = (context: IPipelineContext) => unknown | Promise<unknown>;
21
+ /** Controls how OpenFeature provider evaluation failures are handled. */
22
+ export type FeatureFlagErrorPolicy = 'use-default' | 'throw';
23
+ /**
24
+ * Detailed result of a feature-flag evaluation, recorded on the pipeline
25
+ * context so logging/audit/telemetry or later behaviors can inspect the exact
26
+ * provider decision without re-evaluating the flag.
27
+ */
28
+ export interface FeatureFlagDecision {
29
+ /** Evaluated OpenFeature flag key. */
30
+ flagKey: string;
31
+ /** Raw boolean value returned by OpenFeature (or its configured default value). */
32
+ value: boolean;
33
+ /** Final gate decision after optional variant filtering. */
34
+ enabled: boolean;
35
+ /** Provider-selected variant, when the provider reports one. */
36
+ variant?: string;
37
+ /** OpenFeature resolution reason, when reported by the provider. */
38
+ reason?: string;
39
+ /** OpenFeature provider error code, if evaluation failed. */
40
+ errorCode?: string;
41
+ /** Provider error message, if evaluation failed. */
42
+ errorMessage?: string;
43
+ /** Stable targeting key used for this evaluation, if one was supplied. */
44
+ targetingKey?: string;
45
+ }
46
+ /**
47
+ * Per-handler feature-flag options, supplied through
48
+ * `pipeline.wrap(options, [FeatureFlagBehavior, options])` and/or as defaults,
49
+ * the second argument of the {@link FeatureFlagBehavior} constructor.
50
+ */
51
+ export interface FeatureFlagBehaviorOptions {
52
+ /**
53
+ * Boolean flag key that gates the handler. When omitted the behavior is a
54
+ * no-op (the handler always runs) — useful for setting only constructor defaults.
55
+ */
56
+ flag?: string;
57
+ /**
58
+ * Value used when the flag cannot be resolved (provider error, unknown key,
59
+ * not yet ready). Defaults to `false` (fail-closed).
60
+ */
61
+ defaultValue?: boolean;
62
+ /**
63
+ * When the flag resolves to disabled, return this value instead of throwing
64
+ * {@link FeatureDisabledError}. Use it to degrade gracefully, for example by
65
+ * returning an empty read model or another explicitly supported fallback.
66
+ */
67
+ fallback?: FeatureFallbackFactory;
68
+ /**
69
+ * Builds extra OpenFeature targeting context for this handler, merged on top
70
+ * of the base context (derived from the request) and the constructor's context.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * @pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, {
75
+ * flag: 'new-checkout',
76
+ * context: (ctx) => ({
77
+ * plan: ctx.items.get('plan') as string,
78
+ * country: ctx.items.get('country') as string,
79
+ * }),
80
+ * }])
81
+ * ```
82
+ */
83
+ context?: EvaluationContextFactory;
84
+ /**
85
+ * Stable identity used for percentage rollouts / sticky targeting.
86
+ *
87
+ * Handler-level `targetingKeyFactory` overrides the constructor's resolver.
88
+ * Correlation IDs are intentionally **not** used automatically because they
89
+ * normally change on every request and can move the same user between rollout
90
+ * cohorts.
91
+ *
92
+ * @example User-sticky rollout
93
+ * ```ts
94
+ * @pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, {
95
+ * flag: 'new-checkout',
96
+ * targetingKeyFactory: (ctx) =>
97
+ * ctx.items.get('userId') as string | undefined,
98
+ * }])
99
+ * ```
100
+ */
101
+ targetingKeyFactory?: TargetingKeyFactory;
102
+ /**
103
+ * Optional allow-list of provider variants. When set, a boolean `true` only
104
+ * enables the handler if the provider also resolved one of these variants.
105
+ *
106
+ * This is useful when one boolean flag carries named cohorts such as
107
+ * `control`, `treatment-a`, and `treatment-b`.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * @pipeline.wrap({ kind: 'command' }, [FeatureFlagBehavior, {
112
+ * flag: 'checkout-experiment',
113
+ * allowedVariants: ['treatment-a'],
114
+ * }])
115
+ * ```
116
+ */
117
+ allowedVariants?: readonly string[];
118
+ /**
119
+ * Provider evaluation-error handling.
120
+ *
121
+ * - `use-default` — follow OpenFeature's default-value semantics and continue
122
+ * evaluating the final gate using `defaultValue` (default).
123
+ * - `throw` — surface {@link FeatureFlagEvaluationError} instead of silently
124
+ * treating a provider failure like an ordinary disabled flag.
125
+ *
126
+ * @default 'use-default'
127
+ */
128
+ errorPolicy?: FeatureFlagErrorPolicy;
129
+ }
130
+ /** Where {@link createFeatureFlagClient} takes the OpenFeature client from. */
131
+ export interface FeatureFlagClientOptions {
132
+ /**
133
+ * Escape hatch: a fully constructed OpenFeature {@link Client}. Takes
134
+ * precedence over {@link provider}.
135
+ */
136
+ client?: Client;
137
+ /**
138
+ * An OpenFeature {@link Provider} to register — e.g. an Unleash or Flagsmith
139
+ * provider. Registered with `setProviderAndWait`, or `setProvider` when
140
+ * {@link waitForReady} is `false`, before the client is resolved.
141
+ */
142
+ provider?: Provider;
143
+ /**
144
+ * OpenFeature domain (named client) to bind the provider/client to. Lets you
145
+ * run multiple providers side by side. Defaults to the unnamed default client.
146
+ */
147
+ domain?: string;
148
+ /**
149
+ * Whether to await provider readiness via `setProviderAndWait`. Defaults to
150
+ * `true`. Ignored when {@link client} is supplied.
151
+ */
152
+ waitForReady?: boolean;
153
+ }
154
+ //# sourceMappingURL=feature-flags-options.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flags-options.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/feature-flags-options.interface.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EACV,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACT,MAAM,yBAAyB,CAAC;AAEjC;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,gBAAgB,KACtB,iBAAiB,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,gBAAgB,KACtB,MAAM,GAAG,SAAS,CAAC;AAExB;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,OAAO,EAAE,gBAAgB,KACtB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,OAAO,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,KAAK,EAAE,OAAO,CAAC;IACf,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAElC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAEnC;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAE1C;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEpC;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAED,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ /* Copyright (C) 2026-present Aristotelis — see repository license. */
2
+ export {};
3
+ //# sourceMappingURL=feature-flags-options.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flags-options.interface.js","sourceRoot":"","sources":["../../src/interfaces/feature-flags-options.interface.ts"],"names":[],"mappings":"AAAA,sEAAsE"}
package/package.json CHANGED
@@ -1,6 +1,70 @@
1
1
  {
2
2
  "name": "@cqrs-ddd/pipeline-feature-flags",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.5.0",
4
+ "description": "Feature flags for @cqrs-ddd/pipeline through OpenFeature: an operation runs only while its flag is on",
5
+ "author": "Aristotelis",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "type": "module",
8
+ "engines": {
9
+ "node": ">=22.12.0"
10
+ },
11
+ "keywords": [
12
+ "pipeline",
13
+ "cqrs",
14
+ "feature-flags",
15
+ "feature-toggles",
16
+ "openfeature",
17
+ "unleash",
18
+ "flagsmith",
19
+ "behavior"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/aristoteliss/ddd-cqrs.git",
24
+ "directory": "packages/pipeline-feature-flags"
25
+ },
26
+ "homepage": "https://aristoteliss.github.io/ddd-cqrs/packages/pipeline-feature-flags/",
27
+ "bugs": {
28
+ "url": "https://github.com/aristoteliss/ddd-cqrs/issues"
29
+ },
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "./http": {
36
+ "types": "./dist/http.d.ts",
37
+ "default": "./dist/http.js"
38
+ },
39
+ "./package.json": "./package.json"
40
+ },
41
+ "main": "dist/index.js",
42
+ "types": "dist/index.d.ts",
43
+ "files": [
44
+ "dist",
45
+ "LICENSE",
46
+ "COMMERCIAL_LICENSE.txt"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "peerDependencies": {
52
+ "@openfeature/server-sdk": "^1.13.0",
53
+ "@cqrs-ddd/pipeline": "^0.5.0"
54
+ },
55
+ "devDependencies": {
56
+ "@openfeature/server-sdk": "^1.23.0",
57
+ "@vitest/coverage-v8": "^5.0.3",
58
+ "vitest": "^5.0.3",
59
+ "@cqrs-ddd/pipeline": "0.5.0"
60
+ },
61
+ "scripts": {
62
+ "build": "tsc -p tsconfig.build.json",
63
+ "build:watch": "tsc -p tsconfig.build.json --watch",
64
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
65
+ "rebuild": "pnpm run clean && pnpm run build",
66
+ "lint": "tsc --noEmit",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest"
69
+ }
6
70
  }