
Research
/Security News
DuckDB npm Account Compromised in Continuing Supply Chain Attack
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
@bkknights/prosper
Advanced tools
\\//,
ProsperA continuously improving, experimentation framework.
npm i @bkknights/prosper
yarn add @bkknights/prosper
Prosper provides a means of:
The non-Prosper way:
The Prosper way:
@pick(symbol)
with class properties.This is considered 'long-term' code. Our goal is that we want to find out if a Vulcan reply string is better, based on some user interaction.
class ReplyHandler {
reply() {
return 'See ya!';
}
}
class Service {
replyHandler: ReplyHandler = new ReplyHandler();
async setup(httpEvent): Promise<void> {}
run(): string {
return this.replyHandler.reply();
}
}
Using Feature Flags, and a hypothetical function findBestReplyIndex
, which finds the best index for user.
Note: We now have to change from sync to async, which changes usage as well.
class ReplyHandler {
async reply(): string {
// short lived code
const index = await findBestReplyIndex();
// long lived code
const defaultValue = 'See ya!';
// short lived code
if (featureFlagsEnabled()) { // If's can get tricky, when experimenting...
switch (index) {
case 0: return 'Live long, and prosper.';
// Others?
}
}
return defaultValue;
}
}
class Service {
replyHandler: ReplyHandler = new ReplyHandler();
async setup(httpEvent): Promise<void> {}
// Note: Changed from sync to async
async run(): string {
return await this.replyHandler.reply();
}
}
Using Experiments
// Imports
import { BaseExperiment, Variant } from '@bkknights/prosper';
// Create a symbol to reference ReplyHandler
const replyHandlerSymbol = Symbol('ReplyHandler');
//
class Experiment extends BaseExperiment {
// pretend I've connected it up to database
}
// Setup short lived experimentation Code
function whichReply(): Experiment {
class VulcanReply extends ReplyHandler {
reply(): string {
return 'Live Long And Prosper';
}
}
// Setup both defaults, and control set against experiment
return new Experiment('Which Reply Is Best?', [
new Variant('A: Control Set', {
[replyHandlerSymbol]: ReplyHandler
}),
new Variant('B: Vulcan Greeting/Reply', {
...defaults,
[replyHandlerSymbol]: VulcanReply
}),
]);
}
// Instantiate Prosper, with whichReply experiment set
const prosper = new Prosper().with(whichReply());
class Service {
prosper = prosper; // Note: Or inject?
// Note: Now "picking" from multiple ReplyHandler's, associated in setup
@pick(replyHandlerSymbol) replyHandler: ReplyHandler;
// Note: Need to allow prosper to both setup and bind to a value that persists over time in 1 key location within codebase
async setup(httpEvent): Promise<void> {
await this.prosper.setForUser(httpEvent.userId);
}
// Note: usage stayed the same
run(): string {
return this.replyHandler.reply();
}
}
Interacting with Prosper is done by creating a single instance of prosper used on classes where @pick(Symbol)
is used.
import { Prosper, pick } from '@bkknights/prosper';
const prosper = new Prosper();
class MyClass {
prosper: Prosper = prosper;
@pick(Symbol('foo')) foo: Function;
bar() {
this.foo();
}
}
Prosper is interacted with by extending the abstract class BaseExperimentSet
import { Prosper, pick } from '@bkknights/prosper';
import { BaseExperiment } from '@bkknights/prosper/base-experiment';
export class MyExperiment extends BaseExperiment<AlgorithmType> {
public async getExperiment(): Promise<IExperiment | null> {
}
public async upsertExperiment(experiment: IExperiment): Promise<void> {
}
public async deleteExperiment(experiment: IExperiment): Promise<void> {
}
public async getUserExperiment(userId: string, experimentId: string): Promise<IUserVariant | null> {
}
public async upsertUserVariant(userVariant: IUserVariant): Promise<void> {
}
public async deleteUserVariant(userExperiment: IUserVariant): Promise<void> {
}
public async deleteUserVariants(): Promise<void> {
}
public async getAlgorithm(): Promise<Algorithm> {
}
public async upsertAlgorithm(algorithm: Algorithm): Promise<void> {
}
public async deleteAlgorithm(): Promise<void> {
}
public async getVariantIndex(algorithm: Algorithm): Promise<number> {
}
public async rewardAlgorithm(algorithm: Algorithm, userVariantIndex: number, reward: number): Promise<Algorithm> {
}
}
new Prosper().with(setupEvents(new MyExperiment()))
Variants are written and added to an MyExperiment
import { Prosper } from '@bkknights/prosper';
import { BaseExperiment } from '@bkknights/prosper/base-experiment';
import { Variant } from '@bkknights/prosper/variant';
const fooSymbol = Symbol('foo');
const foo1 = () => {
// do default
};
const foo2 = () => {
// do experiment!
};
class Experiment extends BaseExperiment {
constructor(name: string, variants: Variant[]) {
super();
this.name = name;
this.variants = variants;
}
}
const prosper = new Prosper()
.with(
new Experiment('My Experiments', [
new Variant('Control Set: A', {
[fooSymbol]: foo1
}),
new Variant('Deveation: B', {
[fooSymbol]: foo2
}),
])
);
// call and `await prosper.setForUser(key)` just after database connectivity!
// elsewhere in codebase
class MyClass {
prosper = prosper;
@pick(fooSymbol) foo: Function;
myMethod() {
this.foo(); // calls either `foo1` or `foo2`, whichever the algorithms is indicating
}
}
...Vulcan's are cool.
FAQs
A continuously improving, experimentation framework
We found that @bkknights/prosper demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
Security News
The MCP Steering Committee has launched the official MCP Registry in preview, a central hub for discovering and publishing MCP servers.
Product
Socket’s new Pull Request Stories give security teams clear visibility into dependency risks and outcomes across scanned pull requests.