@wardx/core 0.4.0 → 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.
package/README.md CHANGED
@@ -302,3 +302,12 @@ Internal series use the prefix `wardx.internal.`.
302
302
  - Ingest server: `@wardx/server`
303
303
 
304
304
  The wire contract is protocol version 1. A runtime sends `POST /v1/sync` with JSON and gzip. The request header is `X-Wardx-Key`.
305
+
306
+ ## Retention activity
307
+
308
+ `WardxCore.retentionActivity(userId)` requires an explicit nonblank user ID and
309
+ emits salted `retention.activity` evidence into the existing event buffer. The
310
+ server persists UTC cohorts and exact received-user D1/D7/D30 returns; the core
311
+ does not infer activity or keep a durable client identity/outbox. Use the same
312
+ user ID and privacy salt across sessions and clients. See the
313
+ [Node retention contract](../node/README.md#user-retention-d1--d7--d30).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wardx/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Runtime-agnostic Wardx engine for metrics, events, logs, Remote Config, and experiments.",
5
5
  "keywords": [
6
6
  "wardx",
@@ -41,4 +41,4 @@
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  }
44
- }
44
+ }
package/src/WardxCore.js CHANGED
@@ -3,6 +3,7 @@ import { EventBuffer } from './buffers/EventBuffer.js';
3
3
  import { LogBuffer } from './buffers/LogBuffer.js';
4
4
  import { ConfigStore } from './config/ConfigStore.js';
5
5
  import { ExperimentResolver } from './config/ExperimentResolver.js';
6
+ import { subjectHash } from './config/hash.js';
6
7
  import { FrameBuilder } from './frame/FrameBuilder.js';
7
8
  import { InternalMetrics } from './internal/InternalMetrics.js';
8
9
  import { NOOP_COUNTER } from './metrics/Counter.js';
@@ -106,6 +107,20 @@ export class WardxCore {
106
107
  return wrapped;
107
108
  }
108
109
 
110
+ retentionActivity(userId) {
111
+ if (typeof userId !== 'string' || userId.trim().length === 0) {
112
+ throw new Error('retentionActivity requires a non-empty userId');
113
+ }
114
+ const salt = this.settings.privacySalt;
115
+ if (typeof salt !== 'string' || salt.trim().length === 0) {
116
+ throw new Error('retentionActivity requires a non-empty privacySalt');
117
+ }
118
+ this.event('retention.activity', {
119
+ subject: subjectHash(salt, userId),
120
+ salt: subjectHash(salt, 'wardx.retention.identity')
121
+ });
122
+ }
123
+
109
124
  identify(subjectId) {
110
125
  if (subjectId === undefined || subjectId === null) {
111
126
  this._subjectId = null;
package/src/index.d.ts CHANGED
@@ -440,6 +440,7 @@ export class WardxCore {
440
440
  distinct(name: string, dims?: Dimensions | null): DistinctHandle;
441
441
  timer(name: string, dims?: Dimensions | null): StopTimer;
442
442
  event(name: string, attrs?: Attrs | null): void;
443
+ retentionActivity(userId: string): void;
443
444
  identify(subjectId: string | null | undefined): void;
444
445
  configGet<T>(key: string, fallback: T, context?: SubjectContext): T;
445
446
  experimentGoal(name: string, context?: ExperimentGoalContext): void;