@xemahq/object-projection-nest 0.3.0 → 0.4.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/README.md CHANGED
@@ -11,7 +11,37 @@ surface that every XemaObject-owning service exposes so
11
11
  | --- | --- |
12
12
  | `GET /describe-objects` wire DTOs | `DescribeObjectsResponseDto`, `XemaObjectResponseDto`, `XemaSpaceRefDto`, `XemaSubjectRefDto` |
13
13
  | CloudEvent descriptor factory | `defineObjectProjectionEvents(serviceName)` |
14
- | boot + periodic + debounced publisher | `ObjectProjectionPublisherService` |
14
+ | change-driven publisher with reconcile-on-boot | `ObjectProjectionPublisherService` |
15
+ | the slice content digest it compares | `projectionEnvelopeDigest(envelope)` |
16
+
17
+ ## Freshness model: reconcile on boot, publish on change
18
+
19
+ The publisher pushes the COMPLETE slice **unconditionally at boot** and
20
+ thereafter **only when the slice has actually changed**.
21
+
22
+ - **boot** — always publishes. A fresh process knows nothing about what the
23
+ registry currently holds for its source, so this is what repairs a slice
24
+ whose publish was dropped or failed before the last restart.
25
+ - **every `PROJECTION_REFRESH_INTERVAL_MS`** — builds the envelope, digests it
26
+ locally, and publishes *only* if the digest differs from the last
27
+ successfully published one. In a quiet hour this puts **nothing** on the bus.
28
+ - **`scheduleRepublish()`** — an optional per-write hook that collapses
29
+ detection latency from one interval to `PROJECTION_DEBOUNCE_MS`. It passes
30
+ the same digest gate, so a write that projects to identical content still
31
+ publishes nothing. Wiring one can only ever make a producer more responsive,
32
+ never noisier.
33
+ - **`publishProjection(Manual)`** — forced, like boot. "Force a resync" that
34
+ silently did nothing would be worse than the republish it saves.
35
+
36
+ The interval is a POLL, not a heartbeat, and it is deliberately still here:
37
+ most producers in the fleet wire no per-write hook, so for them it *is* the
38
+ change signal. Deleting it would leave them publishing at boot and never again
39
+ — the registry's cache would go stale on every write with nothing anywhere
40
+ reporting a failure.
41
+
42
+ The baseline is per PROCESS and in memory. Two replicas each publish once per
43
+ real change instead of once a minute each; the consumer applies an idempotent
44
+ REPLACE, so the duplicate costs nothing.
15
45
 
16
46
  ## Producer shape
17
47
 
@@ -65,5 +95,11 @@ subpath export, every consuming pod crashes at boot with
65
95
  - A row that cannot be projected (missing scope qualifier, missing version)
66
96
  MUST throw a typed error carrying the row id. Never skip it silently.
67
97
  - The publisher logs and does not rethrow on transport failure — a
68
- cache-refresh push must not crash its host. The periodic tick retries and the
69
- consumer can always recover the same slice over the pull path.
98
+ cache-refresh push must not crash its host. The next tick retries **because
99
+ the baseline advances only after `publish` resolves**, and the consumer can
100
+ always recover the same slice over the pull path.
101
+ - An ABSENT key and an EMPTY collection are different slices. The digest uses
102
+ the kernel's `canonicalJsonStringify`, which drops an `undefined` property
103
+ and keeps `[]`, so a producer that starts emitting an empty collection where
104
+ it previously omitted the key republishes once. That is correct, and it costs
105
+ nothing across a deploy because the boot publish re-seeds the baseline anyway.
@@ -1,5 +1,5 @@
1
- import { ObjectLifecycle, XemaObjectKind } from '@xemahq/kernel-contracts/object';
2
- import { SpaceKind } from '@xemahq/kernel-contracts/space';
1
+ import { ObjectLifecycle, XemaObjectKind } from '@xemahq/contracts/object';
2
+ import { SpaceKind } from '@xemahq/contracts/space';
3
3
  export declare class XemaSubjectRefDto {
4
4
  kind: string;
5
5
  ref: string;
@@ -1 +1 @@
1
- {"version":3,"file":"describe-objects.dto.d.ts","sourceRoot":"","sources":["../../src/projection/describe-objects.dto.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,cAAc,EACf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAmB3D,qBAAa,iBAAiB;IAM5B,IAAI,EAAG,MAAM,CAAC;IAMd,GAAG,EAAG,MAAM,CAAC;CACd;AAQD,qBAAa,eAAe;IAO1B,IAAI,EAAG,SAAS,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,qBAAa,qBAAqB;IAKhC,GAAG,EAAG,MAAM,CAAC;IAOb,IAAI,EAAG,cAAc,CAAC;IAGtB,KAAK,EAAG,eAAe,CAAC;IAGxB,KAAK,EAAG,iBAAiB,CAAC;IAO1B,OAAO,EAAG,MAAM,CAAC;IAOjB,SAAS,EAAG,eAAe,CAAC;IAQ5B,OAAO,EAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAUD,qBAAa,0BAA0B;IAMrC,MAAM,EAAG,MAAM,CAAC;IAMhB,OAAO,EAAG,qBAAqB,EAAE,CAAC;CACnC"}
1
+ {"version":3,"file":"describe-objects.dto.d.ts","sourceRoot":"","sources":["../../src/projection/describe-objects.dto.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,cAAc,EACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAmBpD,qBAAa,iBAAiB;IAM5B,IAAI,EAAG,MAAM,CAAC;IAMd,GAAG,EAAG,MAAM,CAAC;CACd;AAQD,qBAAa,eAAe;IAO1B,IAAI,EAAG,SAAS,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,qBAAa,qBAAqB;IAKhC,GAAG,EAAG,MAAM,CAAC;IAOb,IAAI,EAAG,cAAc,CAAC;IAGtB,KAAK,EAAG,eAAe,CAAC;IAGxB,KAAK,EAAG,iBAAiB,CAAC;IAO1B,OAAO,EAAG,MAAM,CAAC;IAOjB,SAAS,EAAG,eAAe,CAAC;IAQ5B,OAAO,EAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAUD,qBAAa,0BAA0B;IAMrC,MAAM,EAAG,MAAM,CAAC;IAMhB,OAAO,EAAG,qBAAqB,EAAE,CAAC;CACnC"}
@@ -11,8 +11,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DescribeObjectsResponseDto = exports.XemaObjectResponseDto = exports.XemaSpaceRefDto = exports.XemaSubjectRefDto = void 0;
13
13
  const swagger_1 = require("@nestjs/swagger");
14
- const object_1 = require("@xemahq/kernel-contracts/object");
15
- const space_1 = require("@xemahq/kernel-contracts/space");
14
+ const object_1 = require("@xemahq/contracts/object");
15
+ const space_1 = require("@xemahq/contracts/space");
16
16
  class XemaSubjectRefDto {
17
17
  kind;
18
18
  ref;
@@ -1 +1 @@
1
- {"version":3,"file":"describe-objects.dto.js","sourceRoot":"","sources":["../../src/projection/describe-objects.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA8C;AAC9C,4DAGyC;AACzC,0DAA2D;AAmB3D,MAAa,iBAAiB;IAM5B,IAAI,CAAU;IAMd,GAAG,CAAU;CACd;AAbD,8CAaC;AAPC;IALC,IAAA,qBAAW,EAAC;QACX,WAAW,EACT,mGAAmG;QACrG,OAAO,EAAE,SAAS;KACnB,CAAC;;+CACY;AAMd;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,+DAA+D;QAC5E,OAAO,EAAE,oBAAoB;KAC9B,CAAC;;8CACW;AASf,MAAa,eAAe;IAO1B,IAAI,CAAa;IAGjB,KAAK,CAAU;IAGf,SAAS,CAAU;IAGnB,KAAK,CAAU;IAGf,SAAS,CAAU;IAGnB,OAAO,CAAU;IAGjB,MAAM,CAAU;CACjB;AA1BD,0CA0BC;AAnBC;IANC,IAAA,qBAAW,EAAC;QACX,IAAI,EAAE,iBAAS;QACf,QAAQ,EAAE,WAAW;QACrB,WAAW,EACT,yEAAyE;KAC5E,CAAC;;6CACe;AAGjB;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;8CAClB;AAGf;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;kDACd;AAGnB;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;8CAClB;AAGf;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;kDACd;AAGnB;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;gDAChB;AAGjB;IADC,IAAA,qBAAW,EAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;+CACjB;AAgBlB,MAAa,qBAAqB;IAKhC,GAAG,CAAU;IAOb,IAAI,CAAkB;IAGtB,KAAK,CAAmB;IAGxB,KAAK,CAAqB;IAO1B,OAAO,CAAU;IAOjB,SAAS,CAAmB;IAQ5B,OAAO,CAA2B;CACnC;AAzCD,sDAyCC;AApCC;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,0BAA0B;QACvC,OAAO,EAAE,6DAA6D;KACvE,CAAC;;kDACW;AAOb;IALC,IAAA,qBAAW,EAAC;QACX,IAAI,EAAE,uBAAc;QACpB,QAAQ,EAAE,gBAAgB;QAC1B,WAAW,EAAE,0CAA0C;KACxD,CAAC;;mDACoB;AAGtB;IADC,IAAA,qBAAW,EAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;8BAC/B,eAAe;oDAAC;AAGxB;IADC,IAAA,qBAAW,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;8BACjC,iBAAiB;oDAAC;AAO1B;IALC,IAAA,qBAAW,EAAC;QACX,WAAW,EACT,kKAAkK;QACpK,OAAO,EAAE,OAAO;KACjB,CAAC;;sDACe;AAOjB;IALC,IAAA,qBAAW,EAAC;QACX,IAAI,EAAE,wBAAe;QACrB,QAAQ,EAAE,iBAAiB;QAC3B,WAAW,EAAE,+BAA+B;KAC7C,CAAC;;wDAC0B;AAQ5B;IANC,IAAA,qBAAW,EAAC;QACX,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,IAAI;QAC1B,WAAW,EACT,mGAAmG;KACtG,CAAC;;sDACgC;AAWpC,MAAa,0BAA0B;IAMrC,MAAM,CAAU;IAMhB,OAAO,CAA2B;CACnC;AAbD,gEAaC;AAPC;IALC,IAAA,qBAAW,EAAC;QACX,WAAW,EACT,kGAAkG;QACpG,OAAO,EAAE,oBAAoB;KAC9B,CAAC;;0DACc;AAMhB;IAJC,IAAA,qBAAW,EAAC;QACX,IAAI,EAAE,CAAC,qBAAqB,CAAC;QAC7B,WAAW,EAAE,sDAAsD;KACpE,CAAC;;2DACgC"}
1
+ {"version":3,"file":"describe-objects.dto.js","sourceRoot":"","sources":["../../src/projection/describe-objects.dto.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './describe-objects.dto';
2
2
  export * from './projection-events';
3
+ export * from './projection-digest';
3
4
  export * from './object-projection-publisher.service';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"AAiBA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uCAAuC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"AAiBA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uCAAuC,CAAC"}
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./describe-objects.dto"), exports);
18
18
  __exportStar(require("./projection-events"), exports);
19
+ __exportStar(require("./projection-digest"), exports);
19
20
  __exportStar(require("./object-projection-publisher.service"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAiBA,yDAAuC;AACvC,sDAAoC;AACpC,wEAAsD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAiBA,yDAAuC;AACvC,sDAAoC;AACpC,sDAAoC;AACpC,wEAAsD"}
@@ -1,5 +1,4 @@
1
1
  import { Logger, type OnApplicationBootstrap, type OnApplicationShutdown } from '@nestjs/common';
2
- import type { DescribeObjectsResponseDto } from './describe-objects.dto';
3
2
  import type { ObjectProjectionPublishedDescriptor } from './projection-events';
4
3
  import type { DescriptorEventPublisherService } from '@xemahq/events/nest';
5
4
  export declare const PROJECTION_DEBOUNCE_MS = 1000;
@@ -10,10 +9,14 @@ export declare enum ObjectProjectionPublishReason {
10
9
  Manual = "manual",
11
10
  Change = "change"
12
11
  }
12
+ export interface ObjectProjectionEnvelope {
13
+ readonly source: string;
14
+ readonly objects: readonly unknown[];
15
+ }
13
16
  export interface ObjectProjectionPublisherOptions {
14
17
  readonly source: string;
15
18
  readonly descriptor: ObjectProjectionPublishedDescriptor;
16
- buildEnvelope(): Promise<DescribeObjectsResponseDto>;
19
+ buildEnvelope(): Promise<ObjectProjectionEnvelope>;
17
20
  }
18
21
  export declare abstract class ObjectProjectionPublisherService implements OnApplicationBootstrap, OnApplicationShutdown {
19
22
  private readonly publisher;
@@ -22,6 +25,7 @@ export declare abstract class ObjectProjectionPublisherService implements OnAppl
22
25
  private timer;
23
26
  private debounceTimer;
24
27
  private publishing;
28
+ private lastPublishedDigest;
25
29
  protected constructor(publisher: DescriptorEventPublisherService, options: ObjectProjectionPublisherOptions);
26
30
  onApplicationBootstrap(): Promise<void>;
27
31
  onApplicationShutdown(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"object-projection-publisher.service.d.ts","sourceRoot":"","sources":["../../src/projection/object-projection-publisher.service.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AAIxB,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EACV,+BAA+B,EAEhC,MAAM,qBAAqB,CAAC;AAO7B,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAO5C,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAMrD,oBAAY,6BAA6B;IACvC,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW;CAClB;AAKD,MAAM,WAAW,gCAAgC;IAO/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAMxB,QAAQ,CAAC,UAAU,EAAE,mCAAmC,CAAC;IAOzD,aAAa,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;CACtD;AA8BD,8BAAsB,gCACpB,YAAW,sBAAsB,EAAE,qBAAqB;IAStD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,UAAU,CAAS;IAE3B,SAAS,aACU,SAAS,EAAE,+BAA+B,EAC1C,OAAO,EAAE,gCAAgC;IAOtD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAe7C,qBAAqB,IAAI,IAAI;IAmB7B,SAAS,CAAC,iBAAiB,IAAI,IAAI;IAsB7B,iBAAiB,CACrB,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,IAAI,CAAC;IAmEhB,OAAO,CAAC,eAAe;CAQxB"}
1
+ {"version":3,"file":"object-projection-publisher.service.d.ts","sourceRoot":"","sources":["../../src/projection/object-projection-publisher.service.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,MAAM,EACN,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EACV,+BAA+B,EAEhC,MAAM,qBAAqB,CAAC;AAO7B,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAoB5C,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAMrD,oBAAY,6BAA6B;IACvC,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW;CAClB;AA0CD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;CACtC;AAKD,MAAM,WAAW,gCAAgC;IAO/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAMxB,QAAQ,CAAC,UAAU,EAAE,mCAAmC,CAAC;IAmBzD,aAAa,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACpD;AAuED,8BAAsB,gCACpB,YAAW,sBAAsB,EAAE,qBAAqB;IAmBtD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAlB1B,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,UAAU,CAAS;IAU3B,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,SAAS,aACU,SAAS,EAAE,+BAA+B,EAC1C,OAAO,EAAE,gCAAgC;IAOtD,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB7C,qBAAqB,IAAI,IAAI;IAyB7B,SAAS,CAAC,iBAAiB,IAAI,IAAI;IA4B7B,iBAAiB,CACrB,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,IAAI,CAAC;IA+FhB,OAAO,CAAC,eAAe;CAQxB"}
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObjectProjectionPublisherService = exports.ObjectProjectionPublishReason = exports.PROJECTION_REFRESH_INTERVAL_MS = exports.PROJECTION_DEBOUNCE_MS = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const common_1 = require("@nestjs/common");
6
+ const tenant_1 = require("@xemahq/contracts/tenant");
6
7
  const events_1 = require("@xemahq/events");
7
- const tenant_1 = require("@xemahq/kernel-contracts/tenant");
8
+ const projection_digest_1 = require("./projection-digest");
8
9
  exports.PROJECTION_DEBOUNCE_MS = 1_000;
9
10
  exports.PROJECTION_REFRESH_INTERVAL_MS = 60_000;
10
11
  var ObjectProjectionPublishReason;
@@ -14,6 +15,16 @@ var ObjectProjectionPublishReason;
14
15
  ObjectProjectionPublishReason["Manual"] = "manual";
15
16
  ObjectProjectionPublishReason["Change"] = "change";
16
17
  })(ObjectProjectionPublishReason || (exports.ObjectProjectionPublishReason = ObjectProjectionPublishReason = {}));
18
+ function publishesUnconditionally(reason) {
19
+ switch (reason) {
20
+ case ObjectProjectionPublishReason.Boot:
21
+ case ObjectProjectionPublishReason.Manual:
22
+ return true;
23
+ case ObjectProjectionPublishReason.Periodic:
24
+ case ObjectProjectionPublishReason.Change:
25
+ return false;
26
+ }
27
+ }
17
28
  class ObjectProjectionPublisherService {
18
29
  publisher;
19
30
  options;
@@ -21,6 +32,7 @@ class ObjectProjectionPublisherService {
21
32
  timer;
22
33
  debounceTimer;
23
34
  publishing = false;
35
+ lastPublishedDigest;
24
36
  constructor(publisher, options) {
25
37
  this.publisher = publisher;
26
38
  this.options = options;
@@ -65,7 +77,16 @@ class ObjectProjectionPublisherService {
65
77
  throw new Error(`Projection envelope source "${envelope.source}" does not match ` +
66
78
  `the configured publisher source "${this.options.source}".`);
67
79
  }
80
+ const digest = (0, projection_digest_1.projectionEnvelopeDigest)(envelope);
81
+ if (!publishesUnconditionally(reason) &&
82
+ digest === this.lastPublishedDigest) {
83
+ this.logger.log(`Unchanged ${this.options.descriptor.type} ` +
84
+ `reason=${reason} source=${envelope.source} ` +
85
+ `objectCount=${envelope.objects.length} — nothing published`);
86
+ return;
87
+ }
68
88
  await this.publisher.publish(this.options.descriptor, envelope, this.platformContext(), {});
89
+ this.lastPublishedDigest = digest;
69
90
  this.logger.log(`Published ${this.options.descriptor.type} ` +
70
91
  `reason=${reason} source=${envelope.source} ` +
71
92
  `objectCount=${envelope.objects.length}`);
@@ -1 +1 @@
1
- {"version":3,"file":"object-projection-publisher.service.js","sourceRoot":"","sources":["../../src/projection/object-projection-publisher.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"object-projection-publisher.service.js","sourceRoot":"","sources":["../../src/projection/object-projection-publisher.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ObjectProjectionEnvelope } from './object-projection-publisher.service';
2
+ export declare function projectionEnvelopeDigest(envelope: ObjectProjectionEnvelope): string;
3
+ //# sourceMappingURL=projection-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection-digest.d.ts","sourceRoot":"","sources":["../../src/projection/projection-digest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AA+DtF,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,wBAAwB,GACjC,MAAM,CAKR"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectionEnvelopeDigest = projectionEnvelopeDigest;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const content_address_1 = require("@xemahq/contracts/content-address");
6
+ function projectionEnvelopeDigest(envelope) {
7
+ const wire = JSON.parse(JSON.stringify(envelope));
8
+ return (0, node_crypto_1.createHash)('sha256')
9
+ .update((0, content_address_1.canonicalJsonStringify)(wire), 'utf8')
10
+ .digest('hex');
11
+ }
12
+ //# sourceMappingURL=projection-digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection-digest.js","sourceRoot":"","sources":["../../src/projection/projection-digest.ts"],"names":[],"mappings":";;AAmEA,4DAOC;AA1ED,6CAAyC;AAEzC,uEAA2E;AAiE3E,SAAgB,wBAAwB,CACtC,QAAkC;IAElC,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,IAAA,wCAAsB,EAAC,IAAI,CAAC,EAAE,MAAM,CAAC;SAC5C,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/object-projection-nest",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Shared NestJS building blocks for the XSI plane-1 object projection surface (`GET /describe-objects` + the `xema.object-registry.projection.published.v1` CloudEvent) that every XemaObject-owning service implements.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -14,23 +14,22 @@
14
14
  "peerDependencies": {
15
15
  "@nestjs/common": ">=11.0.0",
16
16
  "@nestjs/swagger": ">=11.0.0",
17
- "@xemahq/events": "^0.6.0",
18
- "@xemahq/kernel-contracts": "^12.3.0",
17
+ "@xemahq/events": "^0.11.0",
18
+ "@xemahq/contracts": "^0.1.0",
19
19
  "zod": "^4.3.6"
20
20
  },
21
21
  "devDependencies": {
22
- "@eslint/js": "^9.39.4",
23
22
  "@nestjs/common": "11.1.18",
24
23
  "@nestjs/swagger": "11.2.6",
24
+ "@types/jest": "^30.0.0",
25
25
  "@types/node": "25.2.3",
26
- "@xemahq/events": "^0.6.0",
27
- "@xemahq/kernel-contracts": "^12.3.0",
26
+ "@xemahq/eslint-config": "^0.5.0",
27
+ "@xemahq/events": "^0.11.0",
28
+ "@xemahq/contracts": "^0.1.0",
28
29
  "eslint": "^9.39.4",
29
- "eslint-config-prettier": "^10.1.8",
30
- "eslint-plugin-import": "^2.32.0",
31
- "eslint-plugin-unused-imports": "^4.4.1",
30
+ "jest": "^30.3.0",
31
+ "ts-jest": "^29.4.9",
32
32
  "typescript": "5.9.3",
33
- "typescript-eslint": "^8.56.1",
34
33
  "zod": "^4.3.6"
35
34
  },
36
35
  "exports": {
@@ -56,8 +55,9 @@
56
55
  },
57
56
  "scripts": {
58
57
  "clean": "rm -rf dist",
59
- "build": "tsc -p tsconfig.json",
58
+ "build": "tsc -p tsconfig.build.json",
60
59
  "lint": "eslint .",
60
+ "test": "jest --config jest.config.ts",
61
61
  "typecheck": "tsc -p tsconfig.json --noEmit"
62
62
  }
63
63
  }