Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,21 @@ if (reforge.isEnabled('cool-feature') {
setTimeout(ping, reforge.get('ping-delay'));
```

Here's an explanation of each property

| property | example | purpose |
| --------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- |
| `isEnabled` | `reforge.isEnabled("new-logo")` | returns a boolean (default `false`) if a feature is enabled based on the current context |
| `get` | `reforge.get('retry-count')` | returns the value of a flag or config evaluated in the current context |
| `getDuration` | `reforge.getDuration('http.timeout')` | returns a duration object `{seconds: number, ms: number}` |
| `loaded` | `if (reforge.loaded) { ... }` | a boolean indicating whether reforge content has loaded |
| `shouldLog` | `if (reforge.shouldLog(...)) {` | returns a boolean indicating whether the proposed log level is valid for the current context |
| `poll` | `reforge.poll({frequencyInMs})` | starts polling every `frequencyInMs` ms. |
| `stopPolling` | `reforge.stopPolling()` | stops the polling process |
| `context` | `reforge.context` | get the current context (after `init()`). |
| `updateContext` | `reforge.updateContext(newContext)` | update the context and refetch. Pass `false` as a second argument to skip refetching |
## Client API

| property | example | purpose |
| --------------- | -------------------------------------- | -------------------------------------------------------------------------------------------- |
| `isEnabled` | `reforge.isEnabled("new-logo")` | returns a boolean (default `false`) if a feature is enabled based on the current context |
| `get` | `reforge.get('retry-count')` | returns the value of a flag or config evaluated in the current context |
| `getDuration` | `reforge.getDuration('http.timeout')` | returns a duration object `{seconds: number, ms: number}` |
| `loaded` | `if (reforge.loaded) { ... }` | a boolean indicating whether reforge content has loaded |
| `shouldLog` | `if (reforge.shouldLog(...)) {` | returns a boolean indicating whether the proposed log level is valid for the current context |
| `poll` | `reforge.poll({frequencyInMs})` | starts polling every `frequencyInMs` ms. |
| `stopPolling` | `reforge.stopPolling()` | stops the polling process |
| `context` | `reforge.context` | get the current context (after `init()`). |
| `updateContext` | `reforge.updateContext(newContext)` | update the context and refetch. Pass `false` as a second argument to skip refetching |
| `extract` | `reforge.extract()` | returns the current config as a plain object of key, config value pairs |
| `hydrate` | `reforge.hydrate(configurationObject)` | sets the current config based on a plain object of key, config value pairs |

## `shouldLog()`

Expand Down
8 changes: 4 additions & 4 deletions src/afterEvaluationCallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe("afterEvaluationCallback", () => {
const reforge = new Reforge();
reforge.afterEvaluationCallback = callback;

reforge.setConfig({ turbo: 2.5 });
reforge.hydrate({ turbo: 2.5 });

expect(callback).not.toHaveBeenCalled();

Expand All @@ -46,7 +46,7 @@ describe("afterEvaluationCallback", () => {

reforge.afterEvaluationCallback = callback;

reforge.setConfig({ turbo: 2.5 });
reforge.hydrate({ turbo: 2.5 });

expect(callback).not.toHaveBeenCalled();

Expand All @@ -72,7 +72,7 @@ describe("afterEvaluationCallback", () => {
await waitForAsyncCall();
expect(callback).toHaveBeenCalledTimes(0);

reforge.setConfig({ foo: true });
reforge.hydrate({ foo: true });

expect(reforge.isEnabled("foo")).toBe(true);

Expand All @@ -94,7 +94,7 @@ describe("afterEvaluationCallback", () => {
await waitForAsyncCall();
expect(callback).toHaveBeenCalledTimes(0);

reforge.setConfig({ foo: true });
reforge.hydrate({ foo: true });

expect(reforge.isEnabled("foo")).toBe(true);

Expand Down
38 changes: 30 additions & 8 deletions src/reforge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,11 @@ describe("poll", () => {
});
});

describe("setConfig", () => {
describe("hydrate", () => {
it("works when types are not provided", () => {
expect(reforge.configs).toEqual({});

reforge.setConfig({
reforge.hydrate({
turbo: 2.5,
foo: true,
jsonExample: { foo: "bar", baz: 123 },
Expand Down Expand Up @@ -287,7 +287,7 @@ describe("bootstrapping", () => {
});

test("get", () => {
reforge.setConfig({
reforge.hydrate({
evaluations: {
turbo: { value: { double: 2.5 } },
durationExample: { value: { duration: { millis: 1884000, definition: "PT1884S" } } },
Expand All @@ -310,7 +310,7 @@ test("get", () => {
});

test("getDuration", () => {
reforge.setConfig({
reforge.hydrate({
evaluations: {
turbo: { value: { double: 2.5 } },
durationExample: {
Expand All @@ -333,11 +333,33 @@ test("isEnabled", () => {
// it is false when no config is loaded
expect(reforge.isEnabled("foo")).toBe(false);

reforge.setConfig({ foo: true });
reforge.hydrate({ foo: true });

expect(reforge.isEnabled("foo")).toBe(true);
});

describe("extract", () => {
it("correctly extracts configuration values", () => {
reforge.hydrate({
turbo: 2.5,
foo: true,
jsonExample: { foo: "bar", baz: 123 },
});

const extracted = reforge.extract();
expect(extracted).toEqual({
turbo: 2.5,
foo: true,
jsonExample: { foo: "bar", baz: 123 },
});
});

it("returns an empty object when no configs are set", () => {
const extracted = reforge.extract();
expect(extracted).toEqual({});
});
});

describe("shouldLog", () => {
test("compares against the default level where there is no value", () => {
expect(
Expand All @@ -358,7 +380,7 @@ describe("shouldLog", () => {
});

test("compares against the value when present", () => {
reforge.setConfig({
reforge.hydrate({
"log-level.example": "INFO",
});

Expand All @@ -382,7 +404,7 @@ describe("shouldLog", () => {
test("traverses the hierarchy to get the closest level for the loggerName", () => {
const loggerName = "some.test.name.with.more.levels";

reforge.setConfig({
reforge.hydrate({
"log-level.some.test.name": "TRACE",
"log-level.some.test": "DEBUG",
"log-level.irrelevant": "ERROR",
Expand Down Expand Up @@ -422,7 +444,7 @@ describe("shouldLog", () => {
});

it("can use the root log level setting if nothing is found in the hierarchy", () => {
reforge.setConfig({
reforge.hydrate({
"log-level": "INFO",
});

Expand Down
32 changes: 28 additions & 4 deletions src/reforge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,24 @@ export class Reforge {
return this.load();
}

get configs(): { [key: string]: Config } {
extract(): Record<string, Config["value"]> {
return Object.entries(this._configs).reduce(
(agg, [key, value]) => ({
...agg,
[key]: value.value,
}),
{} as Record<string, Config["value"]>
);
}

hydrate(rawValues: RawConfigWithoutTypes | EvaluationPayload): void {
this.setConfigPrivate(rawValues);
}

get configs(): Record<string, Config> {
// eslint-disable-next-line no-console
console.warn("\x1b[33m%s\x1b[0m", 'Deprecated: Use "prefab.extract" instead');

return this._configs;
}

Expand Down Expand Up @@ -175,7 +192,7 @@ export class Reforge {
const bootstrapContext = new Context(reforgeBootstrap.context);

if (this.context.equals(bootstrapContext)) {
this.setConfig({ evaluations: reforgeBootstrap.evaluations });
this.setConfigPrivate({ evaluations: reforgeBootstrap.evaluations });
return Promise.resolve();
}
}
Expand All @@ -186,7 +203,7 @@ export class Reforge {
return this.loader
.load()
.then((rawValues: any) => {
this.setConfig(rawValues as EvaluationPayload);
this.setConfigPrivate(rawValues as EvaluationPayload);
})
.finally(() => {
if (this.pollStatus.status === "running") {
Expand Down Expand Up @@ -255,6 +272,13 @@ export class Reforge {
}

setConfig(rawValues: RawConfigWithoutTypes | EvaluationPayload) {
// eslint-disable-next-line no-console
console.warn("\x1b[33m%s\x1b[0m", 'Deprecated: Use "prefab.hydrate" instead');

this.setConfigPrivate(rawValues);
}

private setConfigPrivate(rawValues: RawConfigWithoutTypes | EvaluationPayload) {
this._configs = Config.digest(rawValues);
this.loaded = true;
}
Expand All @@ -275,7 +299,7 @@ export class Reforge {
return undefined;
}

const config = this.configs[key];
const config = this._configs[key];

const value = config?.value;

Expand Down