@cqrs-ddd/core 0.2.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.
- package/COMMERCIAL_LICENSE.txt +34 -0
- package/LICENSE +661 -0
- package/README.md +707 -0
- package/dist/application/base.command.d.ts +44 -0
- package/dist/application/base.command.d.ts.map +1 -0
- package/dist/application/base.command.js +58 -0
- package/dist/application/base.command.js.map +1 -0
- package/dist/application/base.query.d.ts +42 -0
- package/dist/application/base.query.d.ts.map +1 -0
- package/dist/application/base.query.js +52 -0
- package/dist/application/base.query.js.map +1 -0
- package/dist/application/command-base.handler.d.ts +106 -0
- package/dist/application/command-base.handler.d.ts.map +1 -0
- package/dist/application/command-base.handler.js +119 -0
- package/dist/application/command-base.handler.js.map +1 -0
- package/dist/application/index.d.ts +16 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +33 -0
- package/dist/application/index.js.map +1 -0
- package/dist/application/ports/cache.port.d.ts +104 -0
- package/dist/application/ports/cache.port.d.ts.map +1 -0
- package/dist/application/ports/cache.port.js +17 -0
- package/dist/application/ports/cache.port.js.map +1 -0
- package/dist/application/ports/command-repository.port.d.ts +28 -0
- package/dist/application/ports/command-repository.port.d.ts.map +1 -0
- package/dist/application/ports/command-repository.port.js +4 -0
- package/dist/application/ports/command-repository.port.js.map +1 -0
- package/dist/application/ports/domain-event-publisher.port.d.ts +18 -0
- package/dist/application/ports/domain-event-publisher.port.d.ts.map +1 -0
- package/dist/application/ports/domain-event-publisher.port.js +4 -0
- package/dist/application/ports/domain-event-publisher.port.js.map +1 -0
- package/dist/application/ports/query-repository.port.d.ts +26 -0
- package/dist/application/ports/query-repository.port.d.ts.map +1 -0
- package/dist/application/ports/query-repository.port.js +4 -0
- package/dist/application/ports/query-repository.port.js.map +1 -0
- package/dist/application/ports/write-side-aggregate-repository.port.d.ts +33 -0
- package/dist/application/ports/write-side-aggregate-repository.port.d.ts.map +1 -0
- package/dist/application/ports/write-side-aggregate-repository.port.js +4 -0
- package/dist/application/ports/write-side-aggregate-repository.port.js.map +1 -0
- package/dist/application/query.options.d.ts +22 -0
- package/dist/application/query.options.d.ts.map +1 -0
- package/dist/application/query.options.js +4 -0
- package/dist/application/query.options.js.map +1 -0
- package/dist/application/request-fields.helper.d.ts +5 -0
- package/dist/application/request-fields.helper.d.ts.map +1 -0
- package/dist/application/request-fields.helper.js +20 -0
- package/dist/application/request-fields.helper.js.map +1 -0
- package/dist/application/tenant-resolver.d.ts +56 -0
- package/dist/application/tenant-resolver.d.ts.map +1 -0
- package/dist/application/tenant-resolver.js +60 -0
- package/dist/application/tenant-resolver.js.map +1 -0
- package/dist/domain/decorators/apply-mutation.decorator.d.ts +64 -0
- package/dist/domain/decorators/apply-mutation.decorator.d.ts.map +1 -0
- package/dist/domain/decorators/apply-mutation.decorator.js +86 -0
- package/dist/domain/decorators/apply-mutation.decorator.js.map +1 -0
- package/dist/domain/decorators/mutable.decorator.d.ts +54 -0
- package/dist/domain/decorators/mutable.decorator.d.ts.map +1 -0
- package/dist/domain/decorators/mutable.decorator.js +76 -0
- package/dist/domain/decorators/mutable.decorator.js.map +1 -0
- package/dist/domain/events/domain.event.d.ts +13 -0
- package/dist/domain/events/domain.event.d.ts.map +1 -0
- package/dist/domain/events/domain.event.js +20 -0
- package/dist/domain/events/domain.event.js.map +1 -0
- package/dist/domain/events/event.interface.d.ts +9 -0
- package/dist/domain/events/event.interface.d.ts.map +1 -0
- package/dist/domain/events/event.interface.js +4 -0
- package/dist/domain/events/event.interface.js.map +1 -0
- package/dist/domain/events/root-domain.event.d.ts +50 -0
- package/dist/domain/events/root-domain.event.d.ts.map +1 -0
- package/dist/domain/events/root-domain.event.js +156 -0
- package/dist/domain/events/root-domain.event.js.map +1 -0
- package/dist/domain/exceptions/concurrency-conflict.error.d.ts +20 -0
- package/dist/domain/exceptions/concurrency-conflict.error.d.ts.map +1 -0
- package/dist/domain/exceptions/concurrency-conflict.error.js +32 -0
- package/dist/domain/exceptions/concurrency-conflict.error.js.map +1 -0
- package/dist/domain/exceptions/domain.exception.d.ts +30 -0
- package/dist/domain/exceptions/domain.exception.d.ts.map +1 -0
- package/dist/domain/exceptions/domain.exception.js +39 -0
- package/dist/domain/exceptions/domain.exception.js.map +1 -0
- package/dist/domain/exceptions/entity-not-found.exception.d.ts +14 -0
- package/dist/domain/exceptions/entity-not-found.exception.d.ts.map +1 -0
- package/dist/domain/exceptions/entity-not-found.exception.js +23 -0
- package/dist/domain/exceptions/entity-not-found.exception.js.map +1 -0
- package/dist/domain/exceptions/invalid-value.exception.d.ts +35 -0
- package/dist/domain/exceptions/invalid-value.exception.d.ts.map +1 -0
- package/dist/domain/exceptions/invalid-value.exception.js +67 -0
- package/dist/domain/exceptions/invalid-value.exception.js.map +1 -0
- package/dist/domain/exceptions/missing-tenant-context.exception.d.ts +24 -0
- package/dist/domain/exceptions/missing-tenant-context.exception.d.ts.map +1 -0
- package/dist/domain/exceptions/missing-tenant-context.exception.js +33 -0
- package/dist/domain/exceptions/missing-tenant-context.exception.js.map +1 -0
- package/dist/domain/exceptions/transient-operation.error.d.ts +17 -0
- package/dist/domain/exceptions/transient-operation.error.d.ts.map +1 -0
- package/dist/domain/exceptions/transient-operation.error.js +27 -0
- package/dist/domain/exceptions/transient-operation.error.js.map +1 -0
- package/dist/domain/exceptions/unknown-mutable-field.error.d.ts +14 -0
- package/dist/domain/exceptions/unknown-mutable-field.error.d.ts.map +1 -0
- package/dist/domain/exceptions/unknown-mutable-field.error.js +24 -0
- package/dist/domain/exceptions/unknown-mutable-field.error.js.map +1 -0
- package/dist/domain/index.d.ts +26 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +43 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/interfaces/root-entity-snapshot.interface.d.ts +7 -0
- package/dist/domain/interfaces/root-entity-snapshot.interface.d.ts.map +1 -0
- package/dist/domain/interfaces/root-entity-snapshot.interface.js +4 -0
- package/dist/domain/interfaces/root-entity-snapshot.interface.js.map +1 -0
- package/dist/domain/models/aggregate-root.d.ts +87 -0
- package/dist/domain/models/aggregate-root.d.ts.map +1 -0
- package/dist/domain/models/aggregate-root.js +122 -0
- package/dist/domain/models/aggregate-root.js.map +1 -0
- package/dist/domain/models/root.entity.d.ts +208 -0
- package/dist/domain/models/root.entity.d.ts.map +1 -0
- package/dist/domain/models/root.entity.js +350 -0
- package/dist/domain/models/root.entity.js.map +1 -0
- package/dist/domain/rules/number.rule.d.ts +81 -0
- package/dist/domain/rules/number.rule.d.ts.map +1 -0
- package/dist/domain/rules/number.rule.js +81 -0
- package/dist/domain/rules/number.rule.js.map +1 -0
- package/dist/domain/rules/rule-support.d.ts +6 -0
- package/dist/domain/rules/rule-support.d.ts.map +1 -0
- package/dist/domain/rules/rule-support.js +19 -0
- package/dist/domain/rules/rule-support.js.map +1 -0
- package/dist/domain/rules/text.rule.d.ts +98 -0
- package/dist/domain/rules/text.rule.d.ts.map +1 -0
- package/dist/domain/rules/text.rule.js +103 -0
- package/dist/domain/rules/text.rule.js.map +1 -0
- package/dist/domain/rules/value-violation.d.ts +44 -0
- package/dist/domain/rules/value-violation.d.ts.map +1 -0
- package/dist/domain/rules/value-violation.js +4 -0
- package/dist/domain/rules/value-violation.js.map +1 -0
- package/dist/http/domain-error-http-status.d.ts +43 -0
- package/dist/http/domain-error-http-status.d.ts.map +1 -0
- package/dist/http/domain-error-http-status.js +27 -0
- package/dist/http/domain-error-http-status.js.map +1 -0
- package/dist/http/index.d.ts +9 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +26 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/persistence/cache/cache-logger.d.ts +29 -0
- package/dist/persistence/cache/cache-logger.d.ts.map +1 -0
- package/dist/persistence/cache/cache-logger.js +23 -0
- package/dist/persistence/cache/cache-logger.js.map +1 -0
- package/dist/persistence/cache/memory.cache.d.ts +72 -0
- package/dist/persistence/cache/memory.cache.d.ts.map +1 -0
- package/dist/persistence/cache/memory.cache.js +183 -0
- package/dist/persistence/cache/memory.cache.js.map +1 -0
- package/dist/persistence/command-repository.abstract.d.ts +39 -0
- package/dist/persistence/command-repository.abstract.d.ts.map +1 -0
- package/dist/persistence/command-repository.abstract.js +43 -0
- package/dist/persistence/command-repository.abstract.js.map +1 -0
- package/dist/persistence/decorators/acknowledge-persisted.decorator.d.ts +82 -0
- package/dist/persistence/decorators/acknowledge-persisted.decorator.d.ts.map +1 -0
- package/dist/persistence/decorators/acknowledge-persisted.decorator.js +82 -0
- package/dist/persistence/decorators/acknowledge-persisted.decorator.js.map +1 -0
- package/dist/persistence/decorators/cache.decorator.d.ts +93 -0
- package/dist/persistence/decorators/cache.decorator.d.ts.map +1 -0
- package/dist/persistence/decorators/cache.decorator.js +200 -0
- package/dist/persistence/decorators/cache.decorator.js.map +1 -0
- package/dist/persistence/decorators/from-cache.decorator.d.ts +65 -0
- package/dist/persistence/decorators/from-cache.decorator.d.ts.map +1 -0
- package/dist/persistence/decorators/from-cache.decorator.js +165 -0
- package/dist/persistence/decorators/from-cache.decorator.js.map +1 -0
- package/dist/persistence/decorators/map-persistence-errors.decorator.d.ts +88 -0
- package/dist/persistence/decorators/map-persistence-errors.decorator.d.ts.map +1 -0
- package/dist/persistence/decorators/map-persistence-errors.decorator.js +89 -0
- package/dist/persistence/decorators/map-persistence-errors.decorator.js.map +1 -0
- package/dist/persistence/decorators/persisted-write.decorator.d.ts +61 -0
- package/dist/persistence/decorators/persisted-write.decorator.d.ts.map +1 -0
- package/dist/persistence/decorators/persisted-write.decorator.js +57 -0
- package/dist/persistence/decorators/persisted-write.decorator.js.map +1 -0
- package/dist/persistence/helpers/cache-barrier.helper.d.ts +70 -0
- package/dist/persistence/helpers/cache-barrier.helper.d.ts.map +1 -0
- package/dist/persistence/helpers/cache-barrier.helper.js +57 -0
- package/dist/persistence/helpers/cache-barrier.helper.js.map +1 -0
- package/dist/persistence/helpers/cache-key.helper.d.ts +73 -0
- package/dist/persistence/helpers/cache-key.helper.d.ts.map +1 -0
- package/dist/persistence/helpers/cache-key.helper.js +132 -0
- package/dist/persistence/helpers/cache-key.helper.js.map +1 -0
- package/dist/persistence/helpers/cache-owner.helper.d.ts +9 -0
- package/dist/persistence/helpers/cache-owner.helper.d.ts.map +1 -0
- package/dist/persistence/helpers/cache-owner.helper.js +22 -0
- package/dist/persistence/helpers/cache-owner.helper.js.map +1 -0
- package/dist/persistence/helpers/cache-snapshot.helper.d.ts +28 -0
- package/dist/persistence/helpers/cache-snapshot.helper.d.ts.map +1 -0
- package/dist/persistence/helpers/cache-snapshot.helper.js +42 -0
- package/dist/persistence/helpers/cache-snapshot.helper.js.map +1 -0
- package/dist/persistence/helpers/cache-version.helper.d.ts +29 -0
- package/dist/persistence/helpers/cache-version.helper.d.ts.map +1 -0
- package/dist/persistence/helpers/cache-version.helper.js +71 -0
- package/dist/persistence/helpers/cache-version.helper.js.map +1 -0
- package/dist/persistence/index.d.ts +23 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +40 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/persistence-dialect.d.ts +35 -0
- package/dist/persistence/persistence-dialect.d.ts.map +1 -0
- package/dist/persistence/persistence-dialect.js +31 -0
- package/dist/persistence/persistence-dialect.js.map +1 -0
- package/dist/persistence/query-repository.abstract.d.ts +76 -0
- package/dist/persistence/query-repository.abstract.d.ts.map +1 -0
- package/dist/persistence/query-repository.abstract.js +67 -0
- package/dist/persistence/query-repository.abstract.js.map +1 -0
- package/dist/types/Method.type.d.ts +2 -0
- package/dist/types/Method.type.d.ts.map +1 -0
- package/dist/types/Method.type.js +4 -0
- package/dist/types/Method.type.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { IPersistenceDialect } from '../persistence-dialect';
|
|
2
|
+
import { type PersistedAggregate } from './acknowledge-persisted.decorator';
|
|
3
|
+
import { type CacheOptions } from './cache.decorator';
|
|
4
|
+
import { type UniqueErrors } from './map-persistence-errors.decorator';
|
|
5
|
+
/**
|
|
6
|
+
* Options for {@link PersistedWrite}. The aggregate is always the method's
|
|
7
|
+
* first argument.
|
|
8
|
+
*/
|
|
9
|
+
export interface PersistedWriteOptions<TEntity, TConstraint extends string = never> {
|
|
10
|
+
/**
|
|
11
|
+
* Write-through, eviction and barrier/CAS settings, as accepted by
|
|
12
|
+
* `@Cache({...})`. Omit for a repository without a cache.
|
|
13
|
+
*/
|
|
14
|
+
cache?: CacheOptions<TEntity>;
|
|
15
|
+
/**
|
|
16
|
+
* Domain errors per violated unique constraint, keyed by entity property, as
|
|
17
|
+
* accepted by `@MapPersistenceErrors({ unique })`.
|
|
18
|
+
*/
|
|
19
|
+
unique?: UniqueErrors<TEntity, TConstraint>;
|
|
20
|
+
/** Dialect overriding the registered one, for a repository on another store. */
|
|
21
|
+
dialect?: IPersistenceDialect;
|
|
22
|
+
/**
|
|
23
|
+
* Translator for errors that match no unique mapping, as accepted by
|
|
24
|
+
* `@MapPersistenceErrors({ otherwise })`.
|
|
25
|
+
*/
|
|
26
|
+
otherwise?: (error: unknown, entity: TEntity) => unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Applies the canonical persistence write lifecycle to a repository method
|
|
30
|
+
* whose first argument is the aggregate being written.
|
|
31
|
+
*
|
|
32
|
+
* Equivalent to stacking, outermost to innermost:
|
|
33
|
+
* `@Cache(options.cache)` → `@AcknowledgePersisted(...)` →
|
|
34
|
+
* `@MapPersistenceErrors(...)`, each selecting the first argument.
|
|
35
|
+
*
|
|
36
|
+
* - A rejected write translates known constraint errors, leaves the persisted
|
|
37
|
+
* version baseline unchanged and performs no cache maintenance.
|
|
38
|
+
* - A resolved write acknowledges the persisted version first, then runs
|
|
39
|
+
* best-effort cache maintenance.
|
|
40
|
+
*
|
|
41
|
+
* It provides no transaction or event-delivery guarantee beyond those
|
|
42
|
+
* decorators: promise resolution must mean a durable autocommitted write.
|
|
43
|
+
* Use the individual decorators for other signatures, for writes that must not
|
|
44
|
+
* acknowledge (such as deletes), or for caller-owned ordering.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* @PersistedWrite<User>({
|
|
49
|
+
* cache: {
|
|
50
|
+
* setKey: (user) => cacheKey(User.aggregateName, { id: user.id }),
|
|
51
|
+
* invalidateKeys: (user) => [
|
|
52
|
+
* cacheKey(User.aggregateName, { email: user.email }),
|
|
53
|
+
* ],
|
|
54
|
+
* },
|
|
55
|
+
* unique: { email: (user) => new UniqueEmailException(user) },
|
|
56
|
+
* })
|
|
57
|
+
* async save(user: User): Promise<UserSnapshot> { ... }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function PersistedWrite<TEntity extends PersistedAggregate, TConstraint extends string = never>(options?: PersistedWriteOptions<TEntity, TConstraint>): <TResult>(target: object, key: string | symbol, descriptor: TypedPropertyDescriptor<(entity: TEntity) => Promise<TResult>>) => void;
|
|
61
|
+
//# sourceMappingURL=persisted-write.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persisted-write.decorator.d.ts","sourceRoot":"","sources":["../../../persistence/decorators/persisted-write.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CACpC,OAAO,EACP,WAAW,SAAS,MAAM,GAAG,KAAK;IAElC;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAE9B;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAE5C,gFAAgF;IAChF,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAE9B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,cAAc,CAC5B,OAAO,SAAS,kBAAkB,EAClC,WAAW,SAAS,MAAM,GAAG,KAAK,EAClC,OAAO,GAAE,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAM,IAYjD,OAAO,EACb,QAAQ,MAAM,EACd,KAAK,MAAM,GAAG,MAAM,EACpB,YAAY,uBAAuB,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,KACzE,IAAI,CAKR"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.PersistedWrite = PersistedWrite;
|
|
5
|
+
const acknowledge_persisted_decorator_1 = require("./acknowledge-persisted.decorator");
|
|
6
|
+
const cache_decorator_1 = require("./cache.decorator");
|
|
7
|
+
const map_persistence_errors_decorator_1 = require("./map-persistence-errors.decorator");
|
|
8
|
+
/**
|
|
9
|
+
* Applies the canonical persistence write lifecycle to a repository method
|
|
10
|
+
* whose first argument is the aggregate being written.
|
|
11
|
+
*
|
|
12
|
+
* Equivalent to stacking, outermost to innermost:
|
|
13
|
+
* `@Cache(options.cache)` → `@AcknowledgePersisted(...)` →
|
|
14
|
+
* `@MapPersistenceErrors(...)`, each selecting the first argument.
|
|
15
|
+
*
|
|
16
|
+
* - A rejected write translates known constraint errors, leaves the persisted
|
|
17
|
+
* version baseline unchanged and performs no cache maintenance.
|
|
18
|
+
* - A resolved write acknowledges the persisted version first, then runs
|
|
19
|
+
* best-effort cache maintenance.
|
|
20
|
+
*
|
|
21
|
+
* It provides no transaction or event-delivery guarantee beyond those
|
|
22
|
+
* decorators: promise resolution must mean a durable autocommitted write.
|
|
23
|
+
* Use the individual decorators for other signatures, for writes that must not
|
|
24
|
+
* acknowledge (such as deletes), or for caller-owned ordering.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* @PersistedWrite<User>({
|
|
29
|
+
* cache: {
|
|
30
|
+
* setKey: (user) => cacheKey(User.aggregateName, { id: user.id }),
|
|
31
|
+
* invalidateKeys: (user) => [
|
|
32
|
+
* cacheKey(User.aggregateName, { email: user.email }),
|
|
33
|
+
* ],
|
|
34
|
+
* },
|
|
35
|
+
* unique: { email: (user) => new UniqueEmailException(user) },
|
|
36
|
+
* })
|
|
37
|
+
* async save(user: User): Promise<UserSnapshot> { ... }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function PersistedWrite(options = {}) {
|
|
41
|
+
const cache = options.cache ? (0, cache_decorator_1.Cache)(options.cache) : undefined;
|
|
42
|
+
const acknowledge = (0, acknowledge_persisted_decorator_1.AcknowledgePersisted)({
|
|
43
|
+
entity: ([entity]) => entity,
|
|
44
|
+
});
|
|
45
|
+
const mapErrors = (0, map_persistence_errors_decorator_1.MapPersistenceErrors)({
|
|
46
|
+
entity: ([entity]) => entity,
|
|
47
|
+
unique: options.unique,
|
|
48
|
+
dialect: options.dialect,
|
|
49
|
+
otherwise: options.otherwise,
|
|
50
|
+
});
|
|
51
|
+
return (target, key, descriptor) => {
|
|
52
|
+
mapErrors(target, key, descriptor);
|
|
53
|
+
acknowledge(target, key, descriptor);
|
|
54
|
+
cache?.(target, key, descriptor);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=persisted-write.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persisted-write.decorator.js","sourceRoot":"","sources":["../../../persistence/decorators/persisted-write.decorator.ts"],"names":[],"mappings":";AAAA,sEAAsE;;AA2EtE,wCAwBC;AAhGD,uFAG2C;AAC3C,uDAA6D;AAC7D,yFAG4C;AAgC5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,SAAgB,cAAc,CAG5B,UAAuD,EAAE;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,uBAAK,EAAU,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,MAAM,WAAW,GAAG,IAAA,sDAAoB,EAAY;QAClD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM;KAC7B,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAA,uDAAoB,EAAkC;QACtE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IAEH,OAAO,CACL,MAAc,EACd,GAAoB,EACpB,UAA0E,EACpE,EAAE;QACR,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACnC,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACrC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IACnC,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation reason associated with a {@link CacheMutationBarrier}.
|
|
3
|
+
*/
|
|
4
|
+
export type CacheBarrierReason = 'deleted' | 'invalidated';
|
|
5
|
+
/**
|
|
6
|
+
* Sentinel marker installed in cache during mutations (deletion or invalidation)
|
|
7
|
+
* to record that a cache key changed while a concurrent read may have been in flight.
|
|
8
|
+
*
|
|
9
|
+
* {@link FromCache} treats a barrier as a miss, never as a snapshot. The
|
|
10
|
+
* protection against stale data comes from {@link isCacheNewer}, the default
|
|
11
|
+
* `isNewer` of the {@link Cache} write-through: it ranks a barrier above any
|
|
12
|
+
* snapshot, so a write-through that started before the mutation cannot
|
|
13
|
+
* overwrite it.
|
|
14
|
+
*/
|
|
15
|
+
export interface CacheMutationBarrier {
|
|
16
|
+
readonly __cacheBarrier: true;
|
|
17
|
+
/**
|
|
18
|
+
* Unique per barrier (UUIDv7); diagnostic only.
|
|
19
|
+
*/
|
|
20
|
+
readonly token: string;
|
|
21
|
+
/**
|
|
22
|
+
* Reason for the barrier installation.
|
|
23
|
+
*/
|
|
24
|
+
readonly reason: CacheBarrierReason;
|
|
25
|
+
/**
|
|
26
|
+
* Epoch timestamp when the barrier was installed.
|
|
27
|
+
*/
|
|
28
|
+
readonly createdAt: number;
|
|
29
|
+
/**
|
|
30
|
+
* Diagnostic aggregate identifier if available on the mutated entity.
|
|
31
|
+
*/
|
|
32
|
+
readonly aggregateId?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Diagnostic version number if available on the mutated entity.
|
|
35
|
+
*/
|
|
36
|
+
readonly version?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Union representing values persisted in the cache infrastructure layer.
|
|
40
|
+
*/
|
|
41
|
+
export type CacheStoredValue<TSnapshot> = TSnapshot | CacheMutationBarrier;
|
|
42
|
+
/**
|
|
43
|
+
* Factory creating a new {@link CacheMutationBarrier} with a unique token.
|
|
44
|
+
*
|
|
45
|
+
* @param reason - Whether the barrier represents an entity deletion or secondary invalidation.
|
|
46
|
+
* @param entity - Optional entity or snapshot providing diagnostic id or version metadata.
|
|
47
|
+
* @returns Pure serializable {@link CacheMutationBarrier}.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const barrier = createCacheMutationBarrier('deleted', user);
|
|
52
|
+
* await cache.set(key, barrier, { ttl: DEFAULT_BARRIER_TTL_MS });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createCacheMutationBarrier(reason: CacheBarrierReason, entity?: unknown): CacheMutationBarrier;
|
|
56
|
+
/**
|
|
57
|
+
* Type guard verifying whether an arbitrary value is a {@link CacheMutationBarrier}.
|
|
58
|
+
*
|
|
59
|
+
* @param value - Candidate value retrieved from cache.
|
|
60
|
+
* @returns `true` if value is a {@link CacheMutationBarrier}, `false` otherwise.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* if (isCacheMutationBarrier(cached)) {
|
|
65
|
+
* // Barrier encountered; treat as a miss
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function isCacheMutationBarrier(value: unknown): value is CacheMutationBarrier;
|
|
70
|
+
//# sourceMappingURL=cache-barrier.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-barrier.helper.d.ts","sourceRoot":"","sources":["../../../persistence/helpers/cache-barrier.helper.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,aAAa,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,SAAS,IAAI,SAAS,GAAG,oBAAoB,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,CAAC,EAAE,OAAO,GACf,oBAAoB,CAsBtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,oBAAoB,CAM/B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createCacheMutationBarrier = createCacheMutationBarrier;
|
|
5
|
+
exports.isCacheMutationBarrier = isCacheMutationBarrier;
|
|
6
|
+
const uuidv7_1 = require("@cqrs-ddd/uuidv7");
|
|
7
|
+
/**
|
|
8
|
+
* Factory creating a new {@link CacheMutationBarrier} with a unique token.
|
|
9
|
+
*
|
|
10
|
+
* @param reason - Whether the barrier represents an entity deletion or secondary invalidation.
|
|
11
|
+
* @param entity - Optional entity or snapshot providing diagnostic id or version metadata.
|
|
12
|
+
* @returns Pure serializable {@link CacheMutationBarrier}.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const barrier = createCacheMutationBarrier('deleted', user);
|
|
17
|
+
* await cache.set(key, barrier, { ttl: DEFAULT_BARRIER_TTL_MS });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function createCacheMutationBarrier(reason, entity) {
|
|
21
|
+
const e = typeof entity === 'object' && entity !== null
|
|
22
|
+
? entity
|
|
23
|
+
: undefined;
|
|
24
|
+
const aggregateId = typeof e?.id === 'string' ? e.id : undefined;
|
|
25
|
+
const version = typeof e?.version === 'number'
|
|
26
|
+
? e.version
|
|
27
|
+
: typeof e?._version === 'number'
|
|
28
|
+
? e._version
|
|
29
|
+
: undefined;
|
|
30
|
+
return {
|
|
31
|
+
__cacheBarrier: true,
|
|
32
|
+
token: (0, uuidv7_1.uuidv7)(),
|
|
33
|
+
reason,
|
|
34
|
+
createdAt: Date.now(),
|
|
35
|
+
...(aggregateId !== undefined ? { aggregateId } : {}),
|
|
36
|
+
...(version !== undefined ? { version } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Type guard verifying whether an arbitrary value is a {@link CacheMutationBarrier}.
|
|
41
|
+
*
|
|
42
|
+
* @param value - Candidate value retrieved from cache.
|
|
43
|
+
* @returns `true` if value is a {@link CacheMutationBarrier}, `false` otherwise.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* if (isCacheMutationBarrier(cached)) {
|
|
48
|
+
* // Barrier encountered; treat as a miss
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
function isCacheMutationBarrier(value) {
|
|
53
|
+
return (typeof value === 'object' &&
|
|
54
|
+
value !== null &&
|
|
55
|
+
value.__cacheBarrier === true);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=cache-barrier.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-barrier.helper.js","sourceRoot":"","sources":["../../../persistence/helpers/cache-barrier.helper.ts"],"names":[],"mappings":";AAAA,sEAAsE;;AAkEtE,gEAyBC;AAeD,wDAQC;AAhHD,6CAA0C;AAmD1C;;;;;;;;;;;;GAYG;AACH,SAAgB,0BAA0B,CACxC,MAA0B,EAC1B,MAAgB;IAEhB,MAAM,CAAC,GACL,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAC3C,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,WAAW,GAAG,OAAO,CAAC,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,OAAO,GACX,OAAO,CAAC,EAAE,OAAO,KAAK,QAAQ;QAC5B,CAAC,CAAC,CAAC,CAAC,OAAO;QACX,CAAC,CAAC,OAAQ,CAA4B,EAAE,QAAQ,KAAK,QAAQ;YAC3D,CAAC,CAAG,CAA0B,CAAC,QAAmB;YAClD,CAAC,CAAC,SAAS,CAAC;IAElB,OAAO;QACL,cAAc,EAAE,IAAI;QACpB,KAAK,EAAE,IAAA,eAAM,GAAE;QACf,MAAM;QACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB,CACpC,KAAc;IAEd,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAiC,CAAC,cAAc,KAAK,IAAI,CAC3D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type TenantSource } from '../../application/tenant-resolver';
|
|
2
|
+
/**
|
|
3
|
+
* Types supported as cache key resource specifiers:
|
|
4
|
+
* - A raw resource string (e.g., `'user'` or `'user:'`)
|
|
5
|
+
* - An entity constructor declaring `static readonly aggregateName = 'user'`
|
|
6
|
+
*/
|
|
7
|
+
export type CacheResourceSpecifier = string | {
|
|
8
|
+
aggregateName?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* An explicit tenant for a cache key: a tenant id string, or an object carrying
|
|
12
|
+
* `tenantId`, such as a request or job context.
|
|
13
|
+
*
|
|
14
|
+
* When it is omitted, or an object carries no `tenantId`, the tenant of the
|
|
15
|
+
* registered {@link setTenantResolver} resolver applies. A missing or empty tenant always throws
|
|
16
|
+
* {@link MissingTenantContextError}; there is no shared fallback namespace.
|
|
17
|
+
*/
|
|
18
|
+
export type CacheKeyTenantSource = TenantSource;
|
|
19
|
+
/**
|
|
20
|
+
* A request-bearing source accepted by the factories of {@link cacheKeyTemplate},
|
|
21
|
+
* such as a request or job context.
|
|
22
|
+
*/
|
|
23
|
+
export interface CacheKeyRequestContext {
|
|
24
|
+
readonly request: unknown;
|
|
25
|
+
readonly tenantId?: string | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Derives a deterministic, collision-safe cache key from a canonical structured
|
|
29
|
+
* tuple `[tenant, resource, normalizedFilter]`, versioned and hashed with SHA-256.
|
|
30
|
+
*
|
|
31
|
+
* Guarantees:
|
|
32
|
+
* - **Deterministic ordering**: object keys are sorted recursively.
|
|
33
|
+
* - **Type preservation**: numbers, booleans, strings, and nulls produce distinct representations.
|
|
34
|
+
* - **Null retention**: explicit `null` conditions are preserved, distinct from omitted/undefined keys.
|
|
35
|
+
* - **Fail-safe boundaries**: non-serializable types and cyclic structures are rejected.
|
|
36
|
+
* - **Versioned namespace**: keys are namespaced as `${tenant}:${resource}:v1:${hash}`.
|
|
37
|
+
*
|
|
38
|
+
* @param resourceOrEntity - Logical resource name or object exposing `aggregateName`.
|
|
39
|
+
* @param conditions - Filter values that identify the cached record/query.
|
|
40
|
+
* @param tenantOrContext - An explicit tenant id, or an object carrying `tenantId` (such
|
|
41
|
+
* as a request or job context). When omitted, the tenant of the registered
|
|
42
|
+
* {@link setTenantResolver} resolver is used. See {@link CacheKeyTenantSource}.
|
|
43
|
+
* @returns A versioned, hashed deterministic cache key.
|
|
44
|
+
* @throws {MissingTenantContextError} When tenant identity cannot be resolved.
|
|
45
|
+
* @throws {TypeError} When conditions contain non-serializable values.
|
|
46
|
+
*/
|
|
47
|
+
export declare function cacheKey(resourceOrEntity: CacheResourceSpecifier, conditions: Record<string, unknown>, tenantOrContext?: CacheKeyTenantSource): string;
|
|
48
|
+
/**
|
|
49
|
+
* Resolves a template string (e.g. `user:{userId}`) against a query/command payload,
|
|
50
|
+
* namespaced by the active tenant schema.
|
|
51
|
+
*
|
|
52
|
+
* Required placeholders throw when absent; optional `{prop?}` placeholders resolve
|
|
53
|
+
* to an empty string. Object placeholder values use the same canonical serializer
|
|
54
|
+
* as `cacheKey`.
|
|
55
|
+
*
|
|
56
|
+
* @param template - Key template containing required `{prop}` or optional `{prop?}` placeholders.
|
|
57
|
+
* @param tenantOrContext - An explicit tenant used to namespace produced keys. When
|
|
58
|
+
* omitted, a context source's `tenantId` is used, and otherwise the tenant of the
|
|
59
|
+
* registered {@link setTenantResolver} resolver.
|
|
60
|
+
* @returns A key factory accepting either a request object or a
|
|
61
|
+
* {@link CacheKeyRequestContext} (such as a request or job context).
|
|
62
|
+
* @throws {MissingTenantContextError} When tenant identity cannot be resolved.
|
|
63
|
+
* @throws {Error} When a required placeholder is absent.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const byId = cacheKeyTemplate<{ userId: string }>('user:{userId}');
|
|
68
|
+
* const key = byId({ userId: '019...' });
|
|
69
|
+
* // tenant-a:user:019...
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function cacheKeyTemplate<T = Record<string, unknown>>(template: string, tenantOrContext?: CacheKeyTenantSource): (source: T | CacheKeyRequestContext) => string;
|
|
73
|
+
//# sourceMappingURL=cache-key.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-key.helper.d.ts","sourceRoot":"","sources":["../../../persistence/helpers/cache-key.helper.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,mCAAmC,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAmCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CACtB,gBAAgB,EAAE,sBAAsB,EACxC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,eAAe,CAAC,EAAE,oBAAoB,GACrC,MAAM,CA0BR;AAiBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,QAAQ,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,oBAAoB,GACrC,CAAC,MAAM,EAAE,CAAC,GAAG,sBAAsB,KAAK,MAAM,CA8BhD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.cacheKey = cacheKey;
|
|
5
|
+
exports.cacheKeyTemplate = cacheKeyTemplate;
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
const safe_stringify_1 = require("@cqrs-ddd/safe-stringify");
|
|
8
|
+
const tenant_resolver_1 = require("../../application/tenant-resolver");
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes filter conditions for canonical tuple construction:
|
|
11
|
+
* - Omits undefined properties.
|
|
12
|
+
* - Retains null values.
|
|
13
|
+
* - Preserves scalar and structured types.
|
|
14
|
+
* - Rejects non-serializable types (functions, symbols, BigInt).
|
|
15
|
+
*/
|
|
16
|
+
function normalizeFilterConditions(conditions) {
|
|
17
|
+
const sortedKeys = Object.keys(conditions).sort();
|
|
18
|
+
const normalized = {};
|
|
19
|
+
for (const key of sortedKeys) {
|
|
20
|
+
const val = conditions[key];
|
|
21
|
+
if (val === undefined) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (typeof val === 'function' ||
|
|
25
|
+
typeof val === 'symbol' ||
|
|
26
|
+
typeof val === 'bigint') {
|
|
27
|
+
throw new TypeError(`cacheKey does not support values of type ${typeof val}.`);
|
|
28
|
+
}
|
|
29
|
+
normalized[key] = val;
|
|
30
|
+
}
|
|
31
|
+
return normalized;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Derives a deterministic, collision-safe cache key from a canonical structured
|
|
35
|
+
* tuple `[tenant, resource, normalizedFilter]`, versioned and hashed with SHA-256.
|
|
36
|
+
*
|
|
37
|
+
* Guarantees:
|
|
38
|
+
* - **Deterministic ordering**: object keys are sorted recursively.
|
|
39
|
+
* - **Type preservation**: numbers, booleans, strings, and nulls produce distinct representations.
|
|
40
|
+
* - **Null retention**: explicit `null` conditions are preserved, distinct from omitted/undefined keys.
|
|
41
|
+
* - **Fail-safe boundaries**: non-serializable types and cyclic structures are rejected.
|
|
42
|
+
* - **Versioned namespace**: keys are namespaced as `${tenant}:${resource}:v1:${hash}`.
|
|
43
|
+
*
|
|
44
|
+
* @param resourceOrEntity - Logical resource name or object exposing `aggregateName`.
|
|
45
|
+
* @param conditions - Filter values that identify the cached record/query.
|
|
46
|
+
* @param tenantOrContext - An explicit tenant id, or an object carrying `tenantId` (such
|
|
47
|
+
* as a request or job context). When omitted, the tenant of the registered
|
|
48
|
+
* {@link setTenantResolver} resolver is used. See {@link CacheKeyTenantSource}.
|
|
49
|
+
* @returns A versioned, hashed deterministic cache key.
|
|
50
|
+
* @throws {MissingTenantContextError} When tenant identity cannot be resolved.
|
|
51
|
+
* @throws {TypeError} When conditions contain non-serializable values.
|
|
52
|
+
*/
|
|
53
|
+
function cacheKey(resourceOrEntity, conditions, tenantOrContext) {
|
|
54
|
+
const schema = (0, tenant_resolver_1.requireTenantId)(tenantOrContext, 'cache key derivation');
|
|
55
|
+
let resource;
|
|
56
|
+
if (typeof resourceOrEntity === 'string') {
|
|
57
|
+
resource = resourceOrEntity;
|
|
58
|
+
}
|
|
59
|
+
else if (resourceOrEntity &&
|
|
60
|
+
(typeof resourceOrEntity === 'object' ||
|
|
61
|
+
typeof resourceOrEntity === 'function')) {
|
|
62
|
+
resource = resourceOrEntity.aggregateName || undefined;
|
|
63
|
+
}
|
|
64
|
+
if (resource === undefined) {
|
|
65
|
+
throw new Error('Cannot resolve cache key prefix: resourceOrEntity must be a string or declare a static aggregateName.');
|
|
66
|
+
}
|
|
67
|
+
resource = resource.replace(/:+$/, '');
|
|
68
|
+
const normalizedFilter = normalizeFilterConditions(conditions);
|
|
69
|
+
const tuple = [schema, resource, normalizedFilter];
|
|
70
|
+
const serializedTuple = (0, safe_stringify_1.stableStringify)(tuple);
|
|
71
|
+
const hash = (0, node_crypto_1.createHash)('sha256').update(serializedTuple).digest('hex');
|
|
72
|
+
return `${schema}:${resource}:v1:${hash}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Serializes one template placeholder value into a key segment.
|
|
76
|
+
*
|
|
77
|
+
* Template keys stay human-readable rather than hashed, so `:` and `\\` remain
|
|
78
|
+
* structural characters here and are escaped with {@link escapeKeySegment};
|
|
79
|
+
* nested values delegate to the shared {@link stableStringify} for deterministic
|
|
80
|
+
* recursive ordering.
|
|
81
|
+
*/
|
|
82
|
+
function canonicalizeValue(val) {
|
|
83
|
+
if (typeof val === 'object') {
|
|
84
|
+
return (0, safe_stringify_1.stableStringify)(val);
|
|
85
|
+
}
|
|
86
|
+
return (0, safe_stringify_1.escapeKeySegment)(String(val));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolves a template string (e.g. `user:{userId}`) against a query/command payload,
|
|
90
|
+
* namespaced by the active tenant schema.
|
|
91
|
+
*
|
|
92
|
+
* Required placeholders throw when absent; optional `{prop?}` placeholders resolve
|
|
93
|
+
* to an empty string. Object placeholder values use the same canonical serializer
|
|
94
|
+
* as `cacheKey`.
|
|
95
|
+
*
|
|
96
|
+
* @param template - Key template containing required `{prop}` or optional `{prop?}` placeholders.
|
|
97
|
+
* @param tenantOrContext - An explicit tenant used to namespace produced keys. When
|
|
98
|
+
* omitted, a context source's `tenantId` is used, and otherwise the tenant of the
|
|
99
|
+
* registered {@link setTenantResolver} resolver.
|
|
100
|
+
* @returns A key factory accepting either a request object or a
|
|
101
|
+
* {@link CacheKeyRequestContext} (such as a request or job context).
|
|
102
|
+
* @throws {MissingTenantContextError} When tenant identity cannot be resolved.
|
|
103
|
+
* @throws {Error} When a required placeholder is absent.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* const byId = cacheKeyTemplate<{ userId: string }>('user:{userId}');
|
|
108
|
+
* const key = byId({ userId: '019...' });
|
|
109
|
+
* // tenant-a:user:019...
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
function cacheKeyTemplate(template, tenantOrContext) {
|
|
113
|
+
return (source) => {
|
|
114
|
+
const ctx = source && typeof source === 'object' && 'request' in source
|
|
115
|
+
? source
|
|
116
|
+
: undefined;
|
|
117
|
+
const data = (ctx ? ctx.request : source);
|
|
118
|
+
const schema = (0, tenant_resolver_1.requireTenantId)(tenantOrContext ?? ctx, 'cache key derivation');
|
|
119
|
+
const resolved = template.replace(/\{(\w+)(\?)?\}/g, (_, prop, optional) => {
|
|
120
|
+
const val = data?.[prop];
|
|
121
|
+
if (val !== undefined && val !== null) {
|
|
122
|
+
return canonicalizeValue(val);
|
|
123
|
+
}
|
|
124
|
+
if (optional) {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
throw new Error(`Cannot resolve cache key template: missing required placeholder "${prop}".`);
|
|
128
|
+
});
|
|
129
|
+
return `${schema}:${resolved}`;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=cache-key.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-key.helper.js","sourceRoot":"","sources":["../../../persistence/helpers/cache-key.helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ICacheLogger } from '../cache/cache-logger';
|
|
2
|
+
/**
|
|
3
|
+
* Reports, once per repository class, a cache decorator running on an instance
|
|
4
|
+
* that has no `cache` property. Such a repository is miswired: cache
|
|
5
|
+
* maintenance and read-through are skipped. An instance that declares `cache`
|
|
6
|
+
* and leaves it unset is intentionally uncached and is not reported.
|
|
7
|
+
*/
|
|
8
|
+
export declare function reportMissingCacheProperty(instance: object, decorator: '@Cache' | '@FromCache', logger?: ICacheLogger): void;
|
|
9
|
+
//# sourceMappingURL=cache-owner.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-owner.helper.d.ts","sourceRoot":"","sources":["../../../persistence/helpers/cache-owner.helper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,QAAQ,GAAG,YAAY,EAClC,MAAM,GAAE,YAA4B,GACnC,IAAI,CASN"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.reportMissingCacheProperty = reportMissingCacheProperty;
|
|
5
|
+
const cache_logger_1 = require("../cache/cache-logger");
|
|
6
|
+
const defaultLogger = (0, cache_logger_1.consoleCacheLogger)('CacheDecorators');
|
|
7
|
+
const reportedOwners = new WeakSet();
|
|
8
|
+
/**
|
|
9
|
+
* Reports, once per repository class, a cache decorator running on an instance
|
|
10
|
+
* that has no `cache` property. Such a repository is miswired: cache
|
|
11
|
+
* maintenance and read-through are skipped. An instance that declares `cache`
|
|
12
|
+
* and leaves it unset is intentionally uncached and is not reported.
|
|
13
|
+
*/
|
|
14
|
+
function reportMissingCacheProperty(instance, decorator, logger = defaultLogger) {
|
|
15
|
+
const owner = instance.constructor;
|
|
16
|
+
if ('cache' in instance || reportedOwners.has(owner))
|
|
17
|
+
return;
|
|
18
|
+
reportedOwners.add(owner);
|
|
19
|
+
(0, cache_logger_1.safeWarn)(logger, `${owner.name} uses ${decorator} but has no \`cache\` property, so caching is skipped. ` +
|
|
20
|
+
'Extend CommandRepository/QueryRepository or declare a `cache` property.');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=cache-owner.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-owner.helper.js","sourceRoot":"","sources":["../../../persistence/helpers/cache-owner.helper.ts"],"names":[],"mappings":";AAAA,sEAAsE;;AActE,gEAaC;AAxBD,wDAAqE;AAErE,MAAM,aAAa,GAAG,IAAA,iCAAkB,EAAC,iBAAiB,CAAC,CAAC;AAC5D,MAAM,cAAc,GAAG,IAAI,OAAO,EAAU,CAAC;AAE7C;;;;;GAKG;AACH,SAAgB,0BAA0B,CACxC,QAAgB,EAChB,SAAkC,EAClC,SAAuB,aAAa;IAEpC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC;IACnC,IAAI,OAAO,IAAI,QAAQ,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO;IAC7D,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAA,uBAAQ,EACN,MAAM,EACN,GAAG,KAAK,CAAC,IAAI,SAAS,SAAS,yDAAyD;QACtF,yEAAyE,CAC5E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts a detached, serializable snapshot from a domain entity, aggregate root,
|
|
3
|
+
* or arbitrary value before storing in cache or performing version comparisons.
|
|
4
|
+
*
|
|
5
|
+
* Serialization precedence:
|
|
6
|
+
* 1. Explicit `serializeFn`: Custom transformer passed by caller/decorator.
|
|
7
|
+
* 2. `value.toJSON()`: If the object provides a `toJSON()` method (e.g. `RootEntity.toJSON()`).
|
|
8
|
+
* 3. Deep JSON clone (`JSON.parse(JSON.stringify(value))`): Clones plain objects and strips
|
|
9
|
+
* live class references/methods if no `toJSON` exists, guaranteeing isolation parity.
|
|
10
|
+
* 4. Primitive / nullish pass-through: Returns primitives and null/undefined as-is.
|
|
11
|
+
*
|
|
12
|
+
* @example Extracting snapshot from domain entity with toJSON
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const snapshot = toCacheSnapshot(user);
|
|
15
|
+
* // Returns plain UserSnapshot object
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example Custom serializer function
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const snapshot = toCacheSnapshot(user, (u) => ({ id: u.id, custom: true }));
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @param value - The entity or value to snapshot.
|
|
24
|
+
* @param serializeFn - Optional custom serialization function.
|
|
25
|
+
* @returns Pure, detached serializable snapshot.
|
|
26
|
+
*/
|
|
27
|
+
export declare function toCacheSnapshot<T>(value: T, serializeFn?: ((value: T) => unknown) | null): unknown;
|
|
28
|
+
//# sourceMappingURL=cache-snapshot.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-snapshot.helper.d.ts","sourceRoot":"","sources":["../../../persistence/helpers/cache-snapshot.helper.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,EACR,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,IAAI,GAC3C,OAAO,CAYT"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (C) 2026-present Aristotelis — see repository license. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.toCacheSnapshot = toCacheSnapshot;
|
|
5
|
+
/**
|
|
6
|
+
* Extracts a detached, serializable snapshot from a domain entity, aggregate root,
|
|
7
|
+
* or arbitrary value before storing in cache or performing version comparisons.
|
|
8
|
+
*
|
|
9
|
+
* Serialization precedence:
|
|
10
|
+
* 1. Explicit `serializeFn`: Custom transformer passed by caller/decorator.
|
|
11
|
+
* 2. `value.toJSON()`: If the object provides a `toJSON()` method (e.g. `RootEntity.toJSON()`).
|
|
12
|
+
* 3. Deep JSON clone (`JSON.parse(JSON.stringify(value))`): Clones plain objects and strips
|
|
13
|
+
* live class references/methods if no `toJSON` exists, guaranteeing isolation parity.
|
|
14
|
+
* 4. Primitive / nullish pass-through: Returns primitives and null/undefined as-is.
|
|
15
|
+
*
|
|
16
|
+
* @example Extracting snapshot from domain entity with toJSON
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const snapshot = toCacheSnapshot(user);
|
|
19
|
+
* // Returns plain UserSnapshot object
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Custom serializer function
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const snapshot = toCacheSnapshot(user, (u) => ({ id: u.id, custom: true }));
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param value - The entity or value to snapshot.
|
|
28
|
+
* @param serializeFn - Optional custom serialization function.
|
|
29
|
+
* @returns Pure, detached serializable snapshot.
|
|
30
|
+
*/
|
|
31
|
+
function toCacheSnapshot(value, serializeFn) {
|
|
32
|
+
if (serializeFn) {
|
|
33
|
+
return serializeFn(value);
|
|
34
|
+
}
|
|
35
|
+
if (value === null || typeof value !== 'object') {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
return typeof value.toJSON === 'function'
|
|
39
|
+
? value.toJSON()
|
|
40
|
+
: JSON.parse(JSON.stringify(value));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=cache-snapshot.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-snapshot.helper.js","sourceRoot":"","sources":["../../../persistence/helpers/cache-snapshot.helper.ts"],"names":[],"mappings":";AAAA,sEAAsE;;AA4BtE,0CAeC;AAzCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,SAAgB,eAAe,CAC7B,KAAQ,EACR,WAA4C;IAE5C,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,OAAQ,KAA8B,CAAC,MAAM,KAAK,UAAU;QACjE,CAAC,CAAE,KAA0C,CAAC,MAAM,EAAE;QACtD,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a cached snapshot or record is strictly newer than an incoming
|
|
3
|
+
* record based on explicit version numbers, generation counters, or updatedAt timestamps.
|
|
4
|
+
*
|
|
5
|
+
* Returns `true` only if `cached` is strictly newer than `incoming`.
|
|
6
|
+
* Returns `false` if `incoming` is newer, equal, or if no meaningful ordering can be determined.
|
|
7
|
+
*
|
|
8
|
+
* Comparison precedence:
|
|
9
|
+
* 1. {@link CacheMutationBarrier}: a barrier outranks any snapshot. A cached
|
|
10
|
+
* barrier is newer than an incoming snapshot, an incoming barrier always
|
|
11
|
+
* replaces a cached snapshot, and between two barriers the cached one is
|
|
12
|
+
* newer unless the incoming one has a later `createdAt`.
|
|
13
|
+
* 2. Numeric `version` (optimistic concurrency version)
|
|
14
|
+
* 3. Numeric `__gen` (generation sequence counter)
|
|
15
|
+
* 4. `updatedAt` (Date instance or ISO 8601 string / timestamp)
|
|
16
|
+
*
|
|
17
|
+
* @example Comparing versioned aggregate snapshots
|
|
18
|
+
* ```typescript
|
|
19
|
+
* isCacheNewer({ id: '1', version: 3 }, { id: '1', version: 2 }); // true
|
|
20
|
+
* isCacheNewer({ id: '1', version: 2 }, { id: '1', version: 3 }); // false
|
|
21
|
+
* isCacheNewer({ id: '1', version: 2 }, { id: '1', version: 2 }); // false
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param cached - The existing data in cache.
|
|
25
|
+
* @param incoming - The incoming data being written or compared.
|
|
26
|
+
* @returns `true` if `cached` is strictly newer than `incoming`, `false` otherwise.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isCacheNewer(cached: unknown, incoming: unknown): boolean;
|
|
29
|
+
//# sourceMappingURL=cache-version.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-version.helper.d.ts","sourceRoot":"","sources":["../../../persistence/helpers/cache-version.helper.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CA4CxE"}
|