wardx 0.2.2 → 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 +43 -2
- package/package.json +3 -3
- package/src/WardxNode.js +8 -0
- package/src/index.d.ts +4 -0
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ wardx.event('match.started', { mode: 'ranked', country: 'AR' });
|
|
|
83
83
|
wardx.counter('match.completed', { mode: 'ranked' }).inc();
|
|
84
84
|
wardx.gauge('players.online').set(12);
|
|
85
85
|
wardx.histogram('request.duration', { buckets: [10, 25, 50, 100, 250] }).observe(42);
|
|
86
|
+
wardx.distinct('shot.traffic.hids', { result: 'violating' }).add(hid);
|
|
86
87
|
|
|
87
88
|
const end = wardx.timer('matchmaking.duration');
|
|
88
89
|
end({ result: 'success' });
|
|
@@ -277,7 +278,7 @@ If the event buffer is full, the SDK discards the new event and increments `ward
|
|
|
277
278
|
|
|
278
279
|
**Objective:** Emit one named event and one counter per step. Compare those counts. Do not reconstruct a per-user path.
|
|
279
280
|
|
|
280
|
-
Wardx does not store a user journey. Delivery is at-most-once. Production discards envelopes after ingest (`sink: "null"`). The aggregator counts events by name and role. Event attrs do not split that count. `sessionId` identifies the envelope. It is not a join key.
|
|
281
|
+
Wardx does not store a user journey. Delivery is at-most-once. Production discards envelopes after ingest (`sink: "null"`). The aggregator counts events by name and role. Event attrs do not split that count. `sessionId` identifies the envelope. It is not a join key. `distinct` can estimate unique identifiers per named aggregate, but it does not provide ordered sequences or time between steps.
|
|
281
282
|
|
|
282
283
|
Give each step its own name. Do not reuse `screen.view` with a `surface` attr as the funnel. Use `surface` only as a counter dimension when you also need a breakdown of one step.
|
|
283
284
|
|
|
@@ -309,7 +310,47 @@ function onOnboardingDone(wardx, userId) {
|
|
|
309
310
|
|
|
310
311
|
On a backend that serves many users, increment the counters in process. Do not `event()` once per user action.
|
|
311
312
|
|
|
312
|
-
Do not put `userId` on a counter dimension.
|
|
313
|
+
Do not put `userId` on a counter dimension. For an approximate unique count at
|
|
314
|
+
one step, use `distinct(stepName, dims).add(userId)`. It hashes with the required
|
|
315
|
+
local `privacySalt` and sends only a 512-register HLL sketch (`p=9`, about 4.6%
|
|
316
|
+
standard error). This still does not create a Mixpanel-style per-user funnel.
|
|
317
|
+
|
|
318
|
+
## User retention: D1 / D7 / D30
|
|
319
|
+
|
|
320
|
+
Call `wardx.retentionActivity(userId)` on the activity that defines a return,
|
|
321
|
+
for example opening the app or starting a game. Use the same definition in all
|
|
322
|
+
clients of the project. `userId` is required on every call, must be nonblank,
|
|
323
|
+
and must remain stable across sessions and devices. `identify()` is not used
|
|
324
|
+
as an implicit fallback.
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
wardx.retentionActivity(userId);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The SDK sends a salted subject hash, never the raw ID. Keep `privacySalt` stable
|
|
331
|
+
and identical across project clients; the server pins its fingerprint on the
|
|
332
|
+
first accepted activity and rejects a different salt. Cohorts and returns are
|
|
333
|
+
project-wide across roles and environments; use separate projects for separate
|
|
334
|
+
populations such as production and testing.
|
|
335
|
+
|
|
336
|
+
The server persists the earliest received activity date as the cohort and
|
|
337
|
+
counts each user once on each UTC calendar day. D7 means activity **on** the
|
|
338
|
+
seventh calendar day after the cohort date, not activity on or after D7.
|
|
339
|
+
Duplicate activities do not increase the count. Delayed earlier activity can
|
|
340
|
+
correct the cohort and its returns; subsequent activity never advances it.
|
|
341
|
+
|
|
342
|
+
Query MCP `get_retention` with `project`, inclusive `from`, and exclusive `to`
|
|
343
|
+
as `YYYY-MM-DD` cohort dates. Return dates need not fall inside that range.
|
|
344
|
+
Each cohort contains `users` and D1/D7/D30 `returns` with `users`, `rate` (0–1),
|
|
345
|
+
and `status`. Until the entire target UTC day has elapsed, the return is
|
|
346
|
+
`pending` with null count and rate. Empty cohorts are omitted.
|
|
347
|
+
|
|
348
|
+
Counts are exact for received activity, not proof of complete delivery. This
|
|
349
|
+
uses the existing bounded, in-memory event buffer and at-most-once sync: lost
|
|
350
|
+
batches can lose initial activity or returns. There is no historical backfill
|
|
351
|
+
from ordinary events or `distinct`. Existing timestamp and late-data limits
|
|
352
|
+
apply. A mature result can still change when accepted delayed activity arrives.
|
|
353
|
+
Retention requires a server with this feature; older servers cannot compute it.
|
|
313
354
|
|
|
314
355
|
## Use case 8: Detect abnormal point accumulation
|
|
315
356
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wardx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Node.js SDK for Wardx telemetry, Remote Config, and experiments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wardx",
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
"src"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@wardx/core": "0.
|
|
40
|
+
"@wardx/core": "0.5.0"
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
}
|
package/src/WardxNode.js
CHANGED
|
@@ -43,6 +43,10 @@ export class WardxNode {
|
|
|
43
43
|
this._enqueueSync({ bootstrap: true });
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
retentionActivity(userId) {
|
|
47
|
+
this._core.retentionActivity(userId);
|
|
48
|
+
}
|
|
49
|
+
|
|
46
50
|
identify(subjectId) {
|
|
47
51
|
this._core.identify(subjectId);
|
|
48
52
|
}
|
|
@@ -59,6 +63,10 @@ export class WardxNode {
|
|
|
59
63
|
return this._core.histogram(name, a, b);
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
distinct(name, dims) {
|
|
67
|
+
return this._core.distinct(name, dims);
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
timer(name, dims) {
|
|
63
71
|
return this._core.timer(name, dims);
|
|
64
72
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
CreateWardxOptions,
|
|
8
8
|
DimensionValue,
|
|
9
9
|
Dimensions,
|
|
10
|
+
DistinctHandle,
|
|
10
11
|
EventTraceRecord,
|
|
11
12
|
Experiment,
|
|
12
13
|
ExperimentGoalContext,
|
|
@@ -36,6 +37,7 @@ export type {
|
|
|
36
37
|
CreateWardxOptions,
|
|
37
38
|
DimensionValue,
|
|
38
39
|
Dimensions,
|
|
40
|
+
DistinctHandle,
|
|
39
41
|
EventTraceRecord,
|
|
40
42
|
Experiment,
|
|
41
43
|
ExperimentGoalContext,
|
|
@@ -74,10 +76,12 @@ export class WardxNode {
|
|
|
74
76
|
config: ConfigApi;
|
|
75
77
|
experiment: ExperimentApi;
|
|
76
78
|
constructor(settings: ResolvedSettings);
|
|
79
|
+
retentionActivity(userId: string): void;
|
|
77
80
|
identify(subjectId: string | null | undefined): void;
|
|
78
81
|
counter(name: string, dims?: Dimensions | null): CounterHandle;
|
|
79
82
|
gauge(name: string, dims?: Dimensions | null): GaugeHandle;
|
|
80
83
|
histogram(name: string, a?: HistogramOptions | null, b?: HistogramOptions | null): HistogramHandle;
|
|
84
|
+
distinct(name: string, dims?: Dimensions | null): DistinctHandle;
|
|
81
85
|
timer(name: string, dims?: Dimensions | null): StopTimer;
|
|
82
86
|
event(name: string, attrs?: Attrs | null): void;
|
|
83
87
|
flush(): Promise<void>;
|