@molassesapp/molasses-server
Advanced tools
Comparing version 0.1.4 to 0.2.4
@@ -14,12 +14,15 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MolassesClient = void 0; | ||
var axios_1 = require("axios"); | ||
var common_1 = require("@molassesapp/common"); | ||
var MolassesClient = /** @class */ (function () { | ||
/** | ||
* Creates a new MolassesClient. | ||
* @param Options options - the settings for the MolassesClient | ||
*/ | ||
function MolassesClient(options) { | ||
var _this = this; | ||
this.options = { | ||
APIKey: "", | ||
URL: "https://www.molasses.app", | ||
Debug: false, | ||
debug: false, | ||
sendEvents: true, | ||
}; | ||
@@ -30,35 +33,2 @@ this.featuresCache = {}; | ||
this.refreshInterval = 15000; // 15 seconds | ||
this.init = function () { | ||
return _this.fetchFeatures(); | ||
}; | ||
this.fetchFeatures = function () { | ||
var headers = { Authorization: "Bearer " + _this.options.APIKey }; | ||
if (_this.etag) { | ||
headers["If-None-Match"] = _this.etag; | ||
} | ||
return _this.axios | ||
.get("/v1/sdk/features", { | ||
headers: headers, | ||
}) | ||
.then(function (response) { | ||
_this.timedFetch(); | ||
if (response.status == 304) { | ||
return void 0; | ||
} | ||
if (response.data && response.data.data) { | ||
var jsonData = response.data.data; | ||
_this.featuresCache = jsonData.reduce(function (acc, value) { | ||
acc[value.key] = value; | ||
return acc; | ||
}, {}); | ||
_this.etag = response.headers["etag"]; | ||
_this.initiated = true; | ||
} | ||
return void 0; | ||
}) | ||
.catch(function (err) { | ||
_this.timedFetch(); | ||
throw err; | ||
}); | ||
}; | ||
this.options = __assign(__assign({}, this.options), options); | ||
@@ -72,13 +42,23 @@ if (this.options.APIKey == "") { | ||
} | ||
/** | ||
* `init` - Initializes the feature toggles by fetching them from the Molasses Server | ||
* */ | ||
MolassesClient.prototype.init = function () { | ||
return this.fetchFeatures(); | ||
}; | ||
MolassesClient.prototype.timedFetch = function () { | ||
var _this = this; | ||
if (this.refreshInterval != null && this.refreshInterval > 0) { | ||
this.timer = setTimeout(function () { return _this.fetchFeatures(); }, this.refreshInterval); | ||
} | ||
this.timer = setTimeout(function () { return _this.fetchFeatures(); }, this.refreshInterval); | ||
}; | ||
/** Stops any polling by the molasses client */ | ||
MolassesClient.prototype.stop = function () { | ||
if (this.timer) { | ||
clearTimeout(this.timer); | ||
} | ||
clearTimeout(this.timer); | ||
}; | ||
/** | ||
* Checks to see if a feature is active for a user. | ||
* A `User` is optional. If no user is passed, it will check if the feature is fully available for a user. | ||
* However, if no user is passed and the identify call is in place it will use that user to evaluate | ||
* @param string key - the name of the feature toggle | ||
* @param User? user - The user that the feature toggle will be evaluated against. | ||
*/ | ||
MolassesClient.prototype.isActive = function (key, user) { | ||
@@ -88,7 +68,72 @@ if (!this.initiated) { | ||
} | ||
return common_1.isActive(this.featuresCache[key], user); | ||
var feature = this.featuresCache[key]; | ||
var result = common_1.isActive(feature, user); | ||
if (user && this.options.sendEvents) { | ||
this.uploadEvent({ | ||
event: "experiment_started", | ||
tags: user.params, | ||
userId: user.id, | ||
featureId: feature.id, | ||
featureName: key, | ||
testType: result ? "experiment" : "control", | ||
}); | ||
} | ||
return result; | ||
}; | ||
MolassesClient.prototype.experimentSuccess = function (key, additionalDetails, user) { | ||
if (!this.initiated || !this.options.sendEvents || !user || !user.id) { | ||
return false; | ||
} | ||
var feature = this.featuresCache[key]; | ||
var result = common_1.isActive(feature, user); | ||
this.uploadEvent({ | ||
event: "experiment_success", | ||
tags: __assign(__assign({}, user.params), additionalDetails), | ||
userId: user.id, | ||
featureId: feature.id, | ||
featureName: key, | ||
testType: result ? "experiment" : "control", | ||
}); | ||
}; | ||
MolassesClient.prototype.uploadEvent = function (eventOptions) { | ||
var headers = { Authorization: "Bearer " + this.options.APIKey }; | ||
var data = __assign(__assign({}, eventOptions), { tags: JSON.stringify(eventOptions.tags) }); | ||
axios_1.default.post("https://us-central1-molasses-36bff.cloudfunctions.net/analytics", data, { | ||
headers: headers, | ||
}); | ||
}; | ||
MolassesClient.prototype.fetchFeatures = function () { | ||
var _this = this; | ||
var headers = { Authorization: "Bearer " + this.options.APIKey }; | ||
if (this.etag) { | ||
headers["If-None-Match"] = this.etag; | ||
} | ||
return this.axios | ||
.get("/v1/sdk/features", { | ||
headers: headers, | ||
}) | ||
.then(function (response) { | ||
_this.timedFetch(); | ||
if (response.status == 304) { | ||
return true; | ||
} | ||
if (response.data && response.data.data) { | ||
var jsonData = response.data.data; | ||
_this.featuresCache = jsonData.reduce(function (acc, value) { | ||
acc[value.key] = value; | ||
return acc; | ||
}, {}); | ||
_this.etag = response.headers["etag"]; | ||
_this.initiated = true; | ||
} | ||
return true; | ||
}) | ||
.catch(function (err) { | ||
_this.timedFetch(); | ||
throw err; | ||
}); | ||
}; | ||
return MolassesClient; | ||
}()); | ||
exports.MolassesClient = MolassesClient; | ||
exports.default = MolassesClient; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@molassesapp/molasses-server", | ||
"version": "0.1.4", | ||
"version": "0.2.4", | ||
"description": "A Node (with TypeScript support) SDK for Molasses. It allows you to evaluate user's status for a feature. It also helps simplify logging events for A/B testing.", | ||
@@ -10,2 +10,3 @@ "main": "dist/index.js", | ||
"compile": "tsc -p tsconfig.build.json", | ||
"prepublishOnly": "tsc", | ||
"test": "jest" | ||
@@ -20,3 +21,3 @@ }, | ||
"dependencies": { | ||
"@molassesapp/common": "^0.1.4" | ||
"@molassesapp/common": "^0.2.4" | ||
}, | ||
@@ -26,3 +27,3 @@ "publishConfig": { | ||
}, | ||
"gitHead": "002b1d12bd0fbbf65b9f9193e848b280f0e4a9da" | ||
"gitHead": "a0bf259985a4ada73d7405ab30adf22a8fa37c1a" | ||
} |
102
src/index.ts
import axios, { AxiosInstance, AxiosResponse } from "axios" | ||
import { Feature, User, isActive } from "@molassesapp/common" | ||
/** Options for the `MolassesClient` - APIKey is required */ | ||
export type Options = { | ||
/** Sets the API Key to be used in calls to Molasses*/ | ||
APIKey: string | ||
URL: string | ||
Debug: boolean | ||
/** The based url to be used to call Molasses */ | ||
URL?: string | ||
/** When set to true it starts debug mode */ | ||
debug?: boolean | ||
/** Whether to send user event data back for reporting */ | ||
sendEvents?: boolean | ||
} | ||
export class MolassesClient { | ||
type EventOptions = { | ||
featureId: string | ||
userId: string | ||
featureName: string | ||
event: "experiment_started" | "experiment_success" | ||
tags?: { [key: string]: string } | ||
testType?: string | ||
} | ||
export default class MolassesClient { | ||
private options: Options = { | ||
APIKey: "", | ||
URL: "https://www.molasses.app", | ||
Debug: false, | ||
debug: false, | ||
sendEvents: true, | ||
} | ||
@@ -26,3 +42,6 @@ | ||
private timer: NodeJS.Timer | undefined | ||
/** | ||
* Creates a new MolassesClient. | ||
* @param Options options - the settings for the MolassesClient | ||
*/ | ||
constructor(options: Options) { | ||
@@ -38,3 +57,6 @@ this.options = { ...this.options, ...options } | ||
init = () => { | ||
/** | ||
* `init` - Initializes the feature toggles by fetching them from the Molasses Server | ||
* */ | ||
init() { | ||
return this.fetchFeatures() | ||
@@ -44,13 +66,17 @@ } | ||
private timedFetch() { | ||
if (this.refreshInterval != null && this.refreshInterval > 0) { | ||
this.timer = setTimeout(() => this.fetchFeatures(), this.refreshInterval) | ||
} | ||
this.timer = setTimeout(() => this.fetchFeatures(), this.refreshInterval) | ||
} | ||
/** Stops any polling by the molasses client */ | ||
stop() { | ||
if (this.timer) { | ||
clearTimeout(this.timer) | ||
} | ||
clearTimeout(this.timer) | ||
} | ||
/** | ||
* Checks to see if a feature is active for a user. | ||
* A `User` is optional. If no user is passed, it will check if the feature is fully available for a user. | ||
* However, if no user is passed and the identify call is in place it will use that user to evaluate | ||
* @param string key - the name of the feature toggle | ||
* @param User? user - The user that the feature toggle will be evaluated against. | ||
*/ | ||
isActive(key: string, user?: User) { | ||
@@ -60,7 +86,51 @@ if (!this.initiated) { | ||
} | ||
return isActive(this.featuresCache[key], user) | ||
const feature = this.featuresCache[key] | ||
const result = isActive(feature, user) | ||
if (user && this.options.sendEvents) { | ||
this.uploadEvent({ | ||
event: "experiment_started", | ||
tags: user.params, | ||
userId: user.id, | ||
featureId: feature.id, | ||
featureName: key, | ||
testType: result ? "experiment" : "control", | ||
}) | ||
} | ||
return result | ||
} | ||
private fetchFeatures = () => { | ||
experimentSuccess(key: string, additionalDetails: { [key: string]: string }, user: User) { | ||
if (!this.initiated || !this.options.sendEvents || !user || !user.id) { | ||
return false | ||
} | ||
const feature = this.featuresCache[key] | ||
const result = isActive(feature, user) | ||
this.uploadEvent({ | ||
event: "experiment_success", | ||
tags: { | ||
...user.params, | ||
...additionalDetails, | ||
}, | ||
userId: user.id, | ||
featureId: feature.id, | ||
featureName: key, | ||
testType: result ? "experiment" : "control", | ||
}) | ||
} | ||
private uploadEvent(eventOptions: EventOptions) { | ||
const headers = { Authorization: "Bearer " + this.options.APIKey } | ||
const data = { | ||
...eventOptions, | ||
tags: JSON.stringify(eventOptions.tags), | ||
} | ||
axios.post("https://us-central1-molasses-36bff.cloudfunctions.net/analytics", data, { | ||
headers, | ||
}) | ||
} | ||
private fetchFeatures() { | ||
const headers = { Authorization: "Bearer " + this.options.APIKey } | ||
if (this.etag) { | ||
@@ -76,3 +146,3 @@ headers["If-None-Match"] = this.etag | ||
if (response.status == 304) { | ||
return void 0 | ||
return true | ||
} | ||
@@ -92,3 +162,3 @@ | ||
} | ||
return void 0 | ||
return true | ||
}) | ||
@@ -95,0 +165,0 @@ .catch((err: Error) => { |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
53163
15
1104
1
46
1
+ Added@molassesapp/common@0.2.7(transitive)
+ Addedcrc-32@1.2.2(transitive)
- Removed@molassesapp/common@0.1.4(transitive)
Updated@molassesapp/common@^0.2.4