wardx 0.8.0 → 0.9.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 +9 -1
- package/package.json +2 -2
- package/src/WardxNode.js +25 -2
- package/src/index.d.ts +1 -0
package/README.md
CHANGED
|
@@ -522,7 +522,15 @@ If there is no identified subject and you omit `{ subjectId }`, that call is not
|
|
|
522
522
|
2. If there is no subject (`identify` unset and no `{ subjectId }`), return the Remote Config value.
|
|
523
523
|
3. If an experiment applies to the subject, return the variant value.
|
|
524
524
|
|
|
525
|
-
The
|
|
525
|
+
The server first filters keys and experiments by role, then resolves any conditional base values against the instance's metadata and attributes. An applicable experiment still overrides that resolved base. Attributes do not change experiment eligibility, allocation, assignment, or exposure tracking.
|
|
526
|
+
|
|
527
|
+
SDK 0.9.0 requires `@wardx/server` 0.9.0 or newer. Upgrade the server first: older servers reject the new client fields even when attributes are empty.
|
|
528
|
+
|
|
529
|
+
Pass an optional flat `attributes` object to `createWardx`, for example `attributes: { os: 'android', build: 119, channel: 'stable' }`. Names are application-defined; values must be strings, finite numbers, or booleans. Wardx's `platform` identifies the SDK runtime (`node`, `csharp`, or `unity`), so use a custom attribute for the operating system. Attributes are shared by the SDK instance, not set per `config.get` subject; do not use an instance's attributes to switch between concurrent users.
|
|
530
|
+
|
|
531
|
+
`wardx.setAttributes({ os: 'android', build: 120 })` replaces the entire attribute map with a copy. Use `{}` to clear it. The next successful sync resolves the new context; `await wardx.flush()` requests a sync now. Reads remain local and use the last snapshot until then. Attributes travel as client metadata; send only non-secret values.
|
|
532
|
+
|
|
533
|
+
The SDK updates the snapshot when the project version or the resolved configuration changes. Every successful server response includes an opaque `configContext` token, which the SDK returns on subsequent syncs. The same contract applies with or without rules, allowing context changes to refresh values at the same `configVersion`. Until a successful sync, `config.get` returns the fallback or the last snapshot.
|
|
526
534
|
|
|
527
535
|
## Use case 10: Run an A/B experiment and record a goal
|
|
528
536
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wardx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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.9.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/WardxNode.js
CHANGED
|
@@ -18,6 +18,19 @@ const pkg = JSON.parse(
|
|
|
18
18
|
readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8')
|
|
19
19
|
);
|
|
20
20
|
|
|
21
|
+
function copyAttributes(attributes) {
|
|
22
|
+
if (!attributes || typeof attributes !== 'object' || Array.isArray(attributes)) {
|
|
23
|
+
throw new Error('attributes must be an object');
|
|
24
|
+
}
|
|
25
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
26
|
+
if (key.length === 0) throw new Error('attributes keys must be non-empty strings');
|
|
27
|
+
if (typeof value !== 'string' && typeof value !== 'boolean' && !(typeof value === 'number' && Number.isFinite(value))) {
|
|
28
|
+
throw new Error(`attributes.${key} must be a string, finite number, or boolean`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Object.fromEntries(Object.entries(attributes));
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
export class WardxNode {
|
|
22
35
|
constructor(settings) {
|
|
23
36
|
this.settings = settings;
|
|
@@ -31,6 +44,8 @@ export class WardxNode {
|
|
|
31
44
|
goal: (name, context) => this._core.experimentGoal(name, context)
|
|
32
45
|
};
|
|
33
46
|
if (this._disabled) return;
|
|
47
|
+
this._attributes = copyAttributes(settings.attributes === undefined ? {} : settings.attributes);
|
|
48
|
+
this._configContext = undefined;
|
|
34
49
|
this._transport = createHttpTransport(settings);
|
|
35
50
|
this._stopped = false;
|
|
36
51
|
this._shutdownPromise = null;
|
|
@@ -54,6 +69,11 @@ export class WardxNode {
|
|
|
54
69
|
this._core.identify(subjectId);
|
|
55
70
|
}
|
|
56
71
|
|
|
72
|
+
setAttributes(attributes) {
|
|
73
|
+
if (this._disabled) return;
|
|
74
|
+
this._attributes = copyAttributes(attributes);
|
|
75
|
+
}
|
|
76
|
+
|
|
57
77
|
counter(name, dims) {
|
|
58
78
|
return this._core.counter(name, dims);
|
|
59
79
|
}
|
|
@@ -126,7 +146,7 @@ export class WardxNode {
|
|
|
126
146
|
this._core.snapshotIfDirty();
|
|
127
147
|
}
|
|
128
148
|
const frames = this._core.takePendingFrames();
|
|
129
|
-
if (!flags.bootstrap && frames.length === 0) return;
|
|
149
|
+
if (!flags.bootstrap && !flags.flush && frames.length === 0) return;
|
|
130
150
|
const envelope = {
|
|
131
151
|
protocol: PROTOCOL_VERSION,
|
|
132
152
|
project: this.settings.project,
|
|
@@ -140,9 +160,11 @@ export class WardxNode {
|
|
|
140
160
|
role: this.settings.role,
|
|
141
161
|
appVersion: this.settings.appVersion,
|
|
142
162
|
environment: this.settings.environment,
|
|
143
|
-
platform: PLATFORM
|
|
163
|
+
platform: PLATFORM,
|
|
164
|
+
attributes: this._attributes
|
|
144
165
|
},
|
|
145
166
|
configVersion: this._core.configStore.version,
|
|
167
|
+
configContext: this._configContext,
|
|
146
168
|
frames
|
|
147
169
|
};
|
|
148
170
|
const json = JSON.stringify(envelope);
|
|
@@ -210,6 +232,7 @@ export class WardxNode {
|
|
|
210
232
|
}
|
|
211
233
|
if (json.config) {
|
|
212
234
|
this._core.applyConfig(json.configVersion, json.config);
|
|
235
|
+
this._configContext = json.configContext;
|
|
213
236
|
}
|
|
214
237
|
}
|
|
215
238
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -80,6 +80,7 @@ export class WardxNode {
|
|
|
80
80
|
constructor(settings: ResolvedSettings | DisabledWardxOptions);
|
|
81
81
|
retentionActivity(userId: string): void;
|
|
82
82
|
identify(subjectId: string | null | undefined): void;
|
|
83
|
+
setAttributes(attributes: Record<string, string | number | boolean>): void;
|
|
83
84
|
counter(name: string, dims?: Dimensions | null): CounterHandle;
|
|
84
85
|
gauge(name: string, dims?: Dimensions | null): GaugeHandle;
|
|
85
86
|
histogram(name: string, a?: HistogramOptions | null, b?: HistogramOptions | null): HistogramHandle;
|