@naturalcycles/abba 1.25.0 → 1.25.1

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/dist/abba.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Unsaved } from '@naturalcycles/js-lib';
2
- import { AbbaConfig, Bucket, Experiment, ExperimentAssignmentStatistics, ExperimentWithBuckets, GeneratedUserAssignment } from './types';
3
2
  import { SegmentationData } from '.';
3
+ import { AbbaConfig, Bucket, Experiment, ExperimentAssignmentStatistics, ExperimentWithBuckets, GeneratedUserAssignment } from './types';
4
4
  export declare class Abba {
5
5
  cfg: AbbaConfig;
6
6
  private experimentDao;
package/dist/abba.js CHANGED
@@ -32,7 +32,7 @@ class Abba {
32
32
  */
33
33
  async updateUserId(oldId, newId) {
34
34
  const query = this.userAssignmentDao.query().filterEq('userId', oldId);
35
- await this.userAssignmentDao.updateByQuery(query, { userId: newId });
35
+ await this.userAssignmentDao.patchByQuery(query, { userId: newId });
36
36
  }
37
37
  /**
38
38
  * Returns all experiments.
@@ -128,11 +128,12 @@ class Abba {
128
128
  const experiment = await this.experimentDao.getOneBy('key', experimentKey);
129
129
  (0, js_lib_1._assert)(experiment, `Experiment does not exist: ${experimentKey}`);
130
130
  // Inactive experiments should never return an assignment
131
- if (experiment.status === types_1.AssignmentStatus.Inactive)
131
+ if (experiment.status === types_1.AssignmentStatus.Inactive) {
132
132
  return {
133
133
  experiment,
134
134
  assignment: null,
135
135
  };
136
+ }
136
137
  const buckets = await this.bucketDao.getBy('experimentId', experiment.id);
137
138
  const existingAssignments = await this.userAssignmentDao.getBy('userId', userId);
138
139
  const existing = existingAssignments.find(a => a.experimentId === experiment.id);
@@ -149,26 +150,29 @@ class Abba {
149
150
  };
150
151
  }
151
152
  // No existing assignment, but we don't want to generate a new one
152
- if (existingOnly || experiment.status === types_1.AssignmentStatus.Paused)
153
+ if (existingOnly || experiment.status === types_1.AssignmentStatus.Paused) {
153
154
  return {
154
155
  experiment,
155
156
  assignment: null,
156
157
  };
158
+ }
157
159
  const experiments = await this.getAllExperiments();
158
160
  const exclusionSet = (0, util_1.getUserExclusionSet)(experiments, existingAssignments);
159
- if (!(0, util_1.canGenerateNewAssignments)(experiment, exclusionSet))
161
+ if (!(0, util_1.canGenerateNewAssignments)(experiment, exclusionSet)) {
160
162
  return {
161
163
  experiment,
162
164
  assignment: null,
163
165
  };
166
+ }
164
167
  (0, js_lib_1._assert)(segmentationData, 'Segmentation data required when creating a new assignment');
165
168
  const experimentWithBuckets = { ...experiment, buckets };
166
169
  const assignment = (0, util_1.generateUserAssignmentData)(experimentWithBuckets, userId, segmentationData);
167
- if (!assignment)
170
+ if (!assignment) {
168
171
  return {
169
172
  experiment,
170
173
  assignment: null,
171
174
  };
175
+ }
172
176
  const newAssignment = await this.userAssignmentDao.save(assignment);
173
177
  const bucket = buckets.find(b => b.id === newAssignment.bucketId);
174
178
  return {
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './types';
2
1
  export * from './abba';
2
+ export * from './types';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./types"), exports);
5
4
  tslib_1.__exportStar(require("./abba"), exports);
5
+ tslib_1.__exportStar(require("./types"), exports);
package/dist/util.js CHANGED
@@ -108,7 +108,7 @@ exports.segmentationRuleMap = {
108
108
  return (0, semver_1.satisfies)(keyValue?.toString() || '', ruleValue.toString());
109
109
  },
110
110
  [types_1.SegmentationRuleOperator.Regex](keyValue, ruleValue) {
111
- return new RegExp(`${ruleValue}`).test(keyValue?.toString() || '');
111
+ return new RegExp(ruleValue).test(keyValue?.toString() || '');
112
112
  },
113
113
  [types_1.SegmentationRuleOperator.Boolean](keyValue, ruleValue) {
114
114
  // If it's true, then must be true
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@naturalcycles/abba",
3
- "version": "1.25.0",
3
+ "version": "1.25.1",
4
4
  "scripts": {
5
- "prepare": "husky"
5
+ "prepare": "husky",
6
+ "build": "dev-lib build",
7
+ "test": "dev-lib test",
8
+ "lint": "dev-lib lint",
9
+ "bt": "dev-lib bt",
10
+ "lbt": "dev-lib lbt"
6
11
  },
7
12
  "dependencies": {
8
13
  "@naturalcycles/db-lib": "^9.14.1",
@@ -11,8 +16,8 @@
11
16
  "semver": "^7.3.5"
12
17
  },
13
18
  "devDependencies": {
14
- "@naturalcycles/dev-lib": "^13.44.8",
15
- "@types/node": "^20.2.4",
19
+ "@naturalcycles/dev-lib": "^15.19.0",
20
+ "@types/node": "^22.7.4",
16
21
  "@types/semver": "^7.3.9",
17
22
  "jest": "^29.3.1"
18
23
  },
@@ -34,7 +39,7 @@
34
39
  "url": "https://github.com/NaturalCycles/abba"
35
40
  },
36
41
  "engines": {
37
- "node": ">=18.12.0"
42
+ "node": ">=20.13.0"
38
43
  },
39
44
  "description": "AB test assignment configuration tool for Node.js",
40
45
  "author": "Natural Cycles Team",
package/src/abba.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { _assert, _Memo, _shuffle, pMap, Unsaved } from '@naturalcycles/js-lib'
2
2
  import { LRUMemoCache } from '@naturalcycles/nodejs-lib'
3
+ import { SegmentationData } from '.'
3
4
  import { bucketDao } from './dao/bucket.dao'
4
5
  import { experimentDao } from './dao/experiment.dao'
5
6
  import { userAssignmentDao } from './dao/userAssignment.dao'
@@ -20,7 +21,6 @@ import {
20
21
  getUserExclusionSet,
21
22
  validateTotalBucketRatio,
22
23
  } from './util'
23
- import { SegmentationData } from '.'
24
24
 
25
25
  /**
26
26
  * 10 minutes
@@ -48,7 +48,7 @@ export class Abba {
48
48
  */
49
49
  async updateUserId(oldId: string, newId: string): Promise<void> {
50
50
  const query = this.userAssignmentDao.query().filterEq('userId', oldId)
51
- await this.userAssignmentDao.updateByQuery(query, { userId: newId })
51
+ await this.userAssignmentDao.patchByQuery(query, { userId: newId })
52
52
  }
53
53
 
54
54
  /**
@@ -183,11 +183,12 @@ export class Abba {
183
183
  _assert(experiment, `Experiment does not exist: ${experimentKey}`)
184
184
 
185
185
  // Inactive experiments should never return an assignment
186
- if (experiment.status === AssignmentStatus.Inactive)
186
+ if (experiment.status === AssignmentStatus.Inactive) {
187
187
  return {
188
188
  experiment,
189
189
  assignment: null,
190
190
  }
191
+ }
191
192
 
192
193
  const buckets = await this.bucketDao.getBy('experimentId', experiment.id)
193
194
  const existingAssignments = await this.userAssignmentDao.getBy('userId', userId)
@@ -206,29 +207,32 @@ export class Abba {
206
207
  }
207
208
 
208
209
  // No existing assignment, but we don't want to generate a new one
209
- if (existingOnly || experiment.status === AssignmentStatus.Paused)
210
+ if (existingOnly || experiment.status === AssignmentStatus.Paused) {
210
211
  return {
211
212
  experiment,
212
213
  assignment: null,
213
214
  }
215
+ }
214
216
 
215
217
  const experiments = await this.getAllExperiments()
216
218
  const exclusionSet = getUserExclusionSet(experiments, existingAssignments)
217
- if (!canGenerateNewAssignments(experiment, exclusionSet))
219
+ if (!canGenerateNewAssignments(experiment, exclusionSet)) {
218
220
  return {
219
221
  experiment,
220
222
  assignment: null,
221
223
  }
224
+ }
222
225
 
223
226
  _assert(segmentationData, 'Segmentation data required when creating a new assignment')
224
227
 
225
228
  const experimentWithBuckets = { ...experiment, buckets }
226
229
  const assignment = generateUserAssignmentData(experimentWithBuckets, userId, segmentationData)
227
- if (!assignment)
230
+ if (!assignment) {
228
231
  return {
229
232
  experiment,
230
233
  assignment: null,
231
234
  }
235
+ }
232
236
 
233
237
  const newAssignment = await this.userAssignmentDao.save(assignment)
234
238
 
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './types'
2
1
  export * from './abba'
2
+ export * from './types'
package/src/util.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Unsaved, localDate } from '@naturalcycles/js-lib'
1
+ import { localDate, Unsaved } from '@naturalcycles/js-lib'
2
2
  import { satisfies } from 'semver'
3
3
  import {
4
4
  AssignmentStatus,
@@ -127,7 +127,7 @@ export const segmentationRuleMap: Record<SegmentationRuleOperator, SegmentationR
127
127
  return satisfies(keyValue?.toString() || '', ruleValue.toString())
128
128
  },
129
129
  [SegmentationRuleOperator.Regex](keyValue, ruleValue) {
130
- return new RegExp(`${ruleValue}`).test(keyValue?.toString() || '')
130
+ return new RegExp(ruleValue).test(keyValue?.toString() || '')
131
131
  },
132
132
  [SegmentationRuleOperator.Boolean](keyValue, ruleValue) {
133
133
  // If it's true, then must be true