Skip to content

Commit

Permalink
feat: base apply functionality on backend decision
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklasl committed Feb 3, 2025
1 parent 2abcd9d commit 978c8fa
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
13 changes: 13 additions & 0 deletions packages/sdk/src/Confidence.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ const mockResolveResponse = {
value: { str: 'hello' },
flagSchema: { schema: { str: { stringSchema: {} } } },
reason: 'RESOLVE_REASON_MATCH',
shouldApply: true,
},
{
flag: 'flags/flag2',
variant: 'treatment',
value: { str: 'hello again' },
flagSchema: { schema: { str: { stringSchema: {} } } },
reason: 'RESOLVE_REASON_MATCH',
shouldApply: false,
},
],
resolveToken: 'xyz',
Expand Down Expand Up @@ -86,6 +95,10 @@ describe('Confidence integration tests', () => {
}),
);
});
it('should resolve a value but not send apply if shouldApply is false', async () => {
expect(await confidence.getFlag('flag2.str', 'goodbye')).toBe('hello again');
expect(applyHandlerMock).not.toHaveBeenCalled();
});
it('should abort previous requests when context changes', async () => {
confidence.setContext({ pants: 'yellow' });
const value = confidence.getFlag('flag1.str', 'goodbye');
Expand Down
19 changes: 13 additions & 6 deletions packages/sdk/src/FlagResolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type ResolvedFlag = {
| 'FLAG_ARCHIVED'
| 'TARGETING_KEY_ERROR'
| 'ERROR';
shouldApply: boolean;
};

export type Applier = (flagName: string) => void;
Expand All @@ -50,7 +51,7 @@ export class ReadyFlagResolution implements FlagResolution {
resolveResponse: ResolveFlagsResponse,
private readonly applier?: Applier,
) {
for (const { flag, variant, value, reason, flagSchema } of resolveResponse.resolvedFlags) {
for (const { flag, variant, value, reason, flagSchema, shouldApply } of resolveResponse.resolvedFlags) {
const name = flag.slice(FLAG_PREFIX.length);

const schema = flagSchema ? Schema.parse({ structSchema: flagSchema }) : Schema.ANY;
Expand All @@ -59,6 +60,7 @@ export class ReadyFlagResolution implements FlagResolution {
value: value! as Value.Struct,
variant,
reason: toEvaluationReason(reason),
shouldApply,
});
}
this.resolveToken = base64FromBytes(resolveResponse.resolveToken);
Expand All @@ -78,10 +80,12 @@ export class ReadyFlagResolution implements FlagResolution {
}
const reason = flag.reason;
if (reason === 'ERROR') throw new Error('Unknown resolve error');

if (flag.shouldApply && this.applier) {
this.applier?.(name);
}

if (reason !== 'MATCH') {
if (reason === 'NO_SEGMENT_MATCH' && this.applier) {
this.applier?.(name);
}
return {
reason,
value: defaultValue,
Expand All @@ -95,7 +99,6 @@ export class ReadyFlagResolution implements FlagResolution {
schema.assertAssignsTo(defaultValue);
});

this.applier?.(name);
return {
reason,
value,
Expand All @@ -116,7 +119,11 @@ ReadyFlagResolution.prototype.state = 'READY';

export class FailedFlagResolution implements FlagResolution {
declare state: 'ERROR';
constructor(readonly context: Value.Struct, readonly code: FlagEvaluation.ErrorCode, readonly message: string) {}
constructor(
readonly context: Value.Struct,
readonly code: FlagEvaluation.ErrorCode,
readonly message: string,
) {}

evaluate<T extends Value>(_path: string, defaultValue: T): FlagEvaluation.Resolved<T> {
return {
Expand Down
23 changes: 22 additions & 1 deletion packages/sdk/src/FlagResolverClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('Client environment Evaluation', () => {
});
});

it('should apply when a flag has no segment match', async () => {
it('should apply based on shouldApply', async () => {
const flagResolution = await instanceUnderTest.resolve({}, []);
flagResolution.evaluate('no-seg-flag.enabled', false);
const [applyRequest] = await nextMockArgs(applyHandlerMock);
Expand All @@ -122,6 +122,9 @@ describe('Client environment Evaluation', () => {
},
],
});
expect(applyHandlerMock).toHaveBeenCalledTimes(1);
flagResolution.evaluate('no-flag-apply-flag.str', 'default');
expect(applyHandlerMock).toHaveBeenCalledTimes(1);
});
});
});
Expand Down Expand Up @@ -562,12 +565,30 @@ function createFlagResolutionResponse(): unknown {
},
},
reason: 'RESOLVE_REASON_MATCH',
shouldApply: true,
},
{
flag: 'flags/no-seg-flag',
variant: '',
value: {},
reason: 'RESOLVE_REASON_NO_SEGMENT_MATCH',
shouldApply: true,
},
{
flag: 'flags/no-flag-apply-flag',
variant: '',
value: {
str: 'string',
},
reason: 'RESOLVE_REASON_MATCH',
flagSchema: {
schema: {
str: {
stringSchema: {},
},
},
},
shouldApply: true,
},
],
resolveToken: 'SGVsbG9Xb3JsZA==',
Expand Down

0 comments on commit 978c8fa

Please sign in to comment.