Skip to content

Commit

Permalink
feat: rm result types from browser sdk (#365)
Browse files Browse the repository at this point in the history
* feat: rm result types from browser sdk

Signed-off-by: Mark Phelps <[email protected]>

* chore: dont package engines on pull req

Signed-off-by: Mark Phelps <[email protected]>

* chore: update package-lock.json

Signed-off-by: Mark Phelps <[email protected]>

* chore: rename engine opts to options

Signed-off-by: Mark Phelps <[email protected]>

* chore: rename to client options

Signed-off-by: Mark Phelps <[email protected]>

* chore: cleanup browser readme

Signed-off-by: Mark Phelps <[email protected]>

---------

Signed-off-by: Mark Phelps <[email protected]>
  • Loading branch information
markphelps authored Sep 10, 2024
1 parent d725de8 commit eb939e6
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 85 deletions.
9 changes: 0 additions & 9 deletions .github/workflows/package-ffi-engine.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: Package FFI Engine
on:
pull_request:
branches: ["main"]
push:
tags: ["flipt-engine-ffi-v**"]
workflow_dispatch:
Expand Down Expand Up @@ -99,13 +97,6 @@ jobs:
target/${{ matrix.platform.target }}/release/libfliptengine.* \
|| true
- name: Upload Artifacts (Pull Request)
uses: actions/upload-artifact@v4
if: github.event_name == 'pull_request'
with:
name: flipt-engine-ffi-${{ matrix.platform.name }}
path: flipt-engine-ffi-${{ matrix.platform.name }}.tar.gz

- name: Upload Release Assets (Tag)
uses: softprops/action-gh-release@v2
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/flipt-engine-ffi-v')
Expand Down
7 changes: 3 additions & 4 deletions flipt-client-browser/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Flipt Client Browser

![Status: Hardening](https://img.shields.io/badge/status-hardening-orange)
[![npm](https://img.shields.io/npm/v/@flipt-io/flipt-client-browser?label=%40flipt-io%2Fflipt-client-browser)](https://www.npmjs.com/package/@flipt-io/flipt-client-browser)

The `flipt-client-browser` library contains the JavaScript/TypeScript source code for the Flipt [client-side evaluation](https://www.flipt.io/docs/integration/client) client for the browser.
Expand All @@ -19,7 +18,7 @@ In your JavaScript/Typescript code you can import this client and use it as so:
import { FliptEvaluationClient } from '@flipt-io/flipt-client-browser';

// namespace is the first positional argument and is optional here and will have a value of "default" if not specified.
// engine_opts is the second positional argument and is also optional, the structure is:
// options is the second positional argument and is also optional, the structure is:
// {
// "url": "http://localhost:8080",
// "authentication": {
Expand All @@ -46,7 +45,7 @@ console.log(variant);
The `FliptEvaluationClient` constructor accepts two optional arguments:

- `namespace`: The namespace to fetch flag state from. If not provided, the client will default to the `default` namespace.
- `engine_opts`: An instance of the `EngineOpts` type that supports several options for the client. The structure is:
- `options`: An instance of the `ClientOptions` type that supports several options for the client. The structure is:
- `url`: The URL of the upstream Flipt instance. If not provided, the client will default to `http://localhost:8080`.
- `authentication`: The authentication strategy to use when communicating with the upstream Flipt instance. If not provided, the client will default to no authentication. See the [Authentication](#authentication) section for more information.
- `reference`: The [reference](https://docs.flipt.io/guides/user/using-references) to use when fetching flag state. If not provided, reference will not be used.
Expand Down Expand Up @@ -80,7 +79,7 @@ The fetcher is a function that takes an optional [`IFetcherOpts`](https://github

## State Management

The `FliptEvaluationClient` class pulls flag state from the Flipt instance at the `url` provided in the `engine_opts` object on instantiation.
The `FliptEvaluationClient` class pulls flag state from the Flipt instance at the `url` provided in the `options` object on instantiation.

To update the flag state, you can call the `refresh` method on the `FliptEvaluationClient` class.

Expand Down
70 changes: 27 additions & 43 deletions flipt-client-browser/__tests__/evaluation.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const flipt = require('../dist/index.cjs');

describe('FliptEvaluationClient', () => {
let fliptUrl;
let authToken;
Expand Down Expand Up @@ -32,49 +33,38 @@ describe('FliptEvaluationClient', () => {
fizz: 'buzz'
});

expect(variant.error_message).toBeUndefined();
expect(variant.status).toEqual('success');
expect(variant.result).toBeDefined();
expect(variant.result?.flag_key).toEqual('flag1');
expect(variant.result?.match).toEqual(true);
expect(variant.result?.reason).toEqual('MATCH_EVALUATION_REASON');
expect(variant.result?.segment_keys).toContain('segment1');
expect(variant.result?.variant_key).toContain('variant1');
expect(variant.flag_key).toEqual('flag1');
expect(variant.match).toEqual(true);
expect(variant.reason).toEqual('MATCH_EVALUATION_REASON');
expect(variant.segment_keys).toContain('segment1');
expect(variant.variant_key).toContain('variant1');
});

test('boolean', () => {
const boolean = client.evaluateBoolean('flag_boolean', 'someentity', {
fizz: 'buzz'
});

expect(boolean.error_message).toBeUndefined();
expect(boolean.status).toEqual('success');
expect(boolean.result).toBeDefined();
expect(boolean.result?.flag_key).toEqual('flag_boolean');
expect(boolean.result?.enabled).toEqual(true);
expect(boolean.result?.reason).toEqual('MATCH_EVALUATION_REASON');
expect(boolean.enabled).toEqual(true);
expect(boolean.reason).toEqual('MATCH_EVALUATION_REASON');
});

test('variant failure', () => {
const variant = client.evaluateVariant('nonexistent', 'someentity', {
fizz: 'buzz'
});

expect(variant.result).toBeUndefined();
expect(variant.status).toEqual('failure');
expect(variant.error_message).toEqual(
expect(() => {
client.evaluateVariant('nonexistent', 'someentity', {
fizz: 'buzz'
});
}).toThrow(
'invalid request: failed to get flag information default/nonexistent'
);
});

test('boolean failure', () => {
const boolean = client.evaluateVariant('nonexistent', 'someentity', {
fizz: 'buzz'
});

expect(boolean.result).toBeUndefined();
expect(boolean.status).toEqual('failure');
expect(boolean.error_message).toEqual(
expect(() => {
client.evaluateVariant('nonexistent', 'someentity', {
fizz: 'buzz'
});
}).toThrow(
'invalid request: failed to get flag information default/nonexistent'
);
});
Expand All @@ -86,14 +76,11 @@ describe('FliptEvaluationClient', () => {
fizz: 'buzz'
});

expect(variant.error_message).toBeUndefined();
expect(variant.status).toEqual('success');
expect(variant.result).toBeDefined();
expect(variant.result?.flag_key).toEqual('flag1');
expect(variant.result?.match).toEqual(true);
expect(variant.result?.reason).toEqual('MATCH_EVALUATION_REASON');
expect(variant.result?.segment_keys).toContain('segment1');
expect(variant.result?.variant_key).toContain('variant1');
expect(variant.flag_key).toEqual('flag1');
expect(variant.match).toEqual(true);
expect(variant.reason).toEqual('MATCH_EVALUATION_REASON');
expect(variant.segment_keys).toContain('segment1');
expect(variant.variant_key).toContain('variant1');
});

test('batch', () => {
Expand Down Expand Up @@ -121,12 +108,9 @@ describe('FliptEvaluationClient', () => {
}
]);

expect(batch.error_message).toBeUndefined();
expect(batch.status).toEqual('success');
expect(batch.result).toBeDefined();
expect(batch.responses).toHaveLength(3);
const variant = batch.responses[0];

expect(batch.result?.responses).toHaveLength(3);
const variant = batch.result?.responses[0];
expect(variant?.type).toEqual('VARIANT_EVALUATION_RESPONSE_TYPE');
expect(variant?.variant_evaluation_response?.flag_key).toEqual('flag1');
expect(variant?.variant_evaluation_response?.match).toEqual(true);
Expand All @@ -140,7 +124,7 @@ describe('FliptEvaluationClient', () => {
'variant1'
);

const boolean = batch.result?.responses[1];
const boolean = batch.responses[1];
expect(boolean?.type).toEqual('BOOLEAN_EVALUATION_RESPONSE_TYPE');
expect(boolean?.boolean_evaluation_response?.flag_key).toEqual(
'flag_boolean'
Expand All @@ -150,7 +134,7 @@ describe('FliptEvaluationClient', () => {
'MATCH_EVALUATION_REASON'
);

const error = batch.result?.responses[2];
const error = batch.responses[2];
expect(error?.type).toEqual('ERROR_EVALUATION_RESPONSE_TYPE');
expect(error?.error_evaluation_response?.flag_key).toEqual('notfound');
expect(error?.error_evaluation_response?.namespace_key).toEqual('default');
Expand Down
4 changes: 2 additions & 2 deletions flipt-client-browser/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flipt-client-browser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@flipt-io/flipt-client-browser",
"version": "0.0.20",
"version": "0.1.0",
"description": "Flipt Client Evaluation Browser SDK",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
Expand Down
67 changes: 46 additions & 21 deletions flipt-client-browser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import init, { Engine } from '../dist/flipt_engine_wasm.js';
import wasm from '../dist/flipt_engine_wasm_bg.wasm';

import {
BatchEvaluationResponse,
BatchResult,
BooleanEvaluationResponse,
BooleanResult,
EngineOpts,
ClientOptions,
EvaluationRequest,
IFetcher,
VariantEvaluationResponse,
VariantResult
} from './models.js';

Expand All @@ -23,46 +26,46 @@ export class FliptEvaluationClient {
/**
* Initialize the client
* @param namespace - optional namespace to evaluate flags
* @param engine_opts - optional engine options
* @param options - optional client options
* @returns {Promise<FliptEvaluationClient>}
*/
static async init(
namespace: string = 'default',
engine_opts: EngineOpts = {
options: ClientOptions = {
url: 'http://localhost:8080',
reference: ''
}
): Promise<FliptEvaluationClient> {
await init(await wasm());

let url = engine_opts.url ?? 'http://localhost:8080';
let url = options.url ?? 'http://localhost:8080';
// trim trailing slash
url = url.replace(/\/$/, '');
url = `${url}/internal/v1/evaluation/snapshot/namespace/${namespace}`;

if (engine_opts.reference) {
url = `${url}?reference=${engine_opts.reference}`;
if (options.reference) {
url = `${url}?reference=${options.reference}`;
}

const headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('x-flipt-accept-server-version', '1.47.0');

if (engine_opts.authentication) {
if ('client_token' in engine_opts.authentication) {
if (options.authentication) {
if ('client_token' in options.authentication) {
headers.append(
'Authorization',
`Bearer ${engine_opts.authentication.client_token}`
`Bearer ${options.authentication.client_token}`
);
} else if ('jwt_token' in engine_opts.authentication) {
} else if ('jwt_token' in options.authentication) {
headers.append(
'Authorization',
`JWT ${engine_opts.authentication.jwt_token}`
`JWT ${options.authentication.jwt_token}`
);
}
}

let fetcher = engine_opts.fetcher;
let fetcher = options.fetcher;

if (!fetcher) {
fetcher = async (opts?: { etag?: string }) => {
Expand Down Expand Up @@ -126,49 +129,71 @@ export class FliptEvaluationClient {
* @param flag_key - flag key to evaluate
* @param entity_id - entity id to evaluate
* @param context - optional evaluation context
* @returns {VariantResult}
* @returns {VariantEvaluationResponse}
*/
public evaluateVariant(
flag_key: string,
entity_id: string,
context: {}
): VariantResult {
): VariantEvaluationResponse {
const evaluation_request: EvaluationRequest = {
flag_key,
entity_id,
context
};

return this.engine.evaluate_variant(evaluation_request) as VariantResult;
const result = this.engine.evaluate_variant(
evaluation_request
) as VariantResult;

if (result.status === 'failure') {
throw new Error(result.error_message);
}

return result.result as VariantEvaluationResponse;
}

/**
* Evaluate a boolean flag
* @param flag_key - flag key to evaluate
* @param entity_id - entity id to evaluate
* @param context - optional evaluation context
* @returns {BooleanResult}
* @returns {BooleanEvaluationResponse}
*/
public evaluateBoolean(
flag_key: string,
entity_id: string,
context: {}
): BooleanResult {
): BooleanEvaluationResponse {
const evaluation_request: EvaluationRequest = {
flag_key,
entity_id,
context
};

return this.engine.evaluate_boolean(evaluation_request) as BooleanResult;
const result = this.engine.evaluate_boolean(
evaluation_request
) as BooleanResult;

if (result.status === 'failure') {
throw new Error(result.error_message);
}

return result.result as BooleanEvaluationResponse;
}

/**
* Evaluate a batch of flag requests
* @param requests evaluation requests
* @returns {BatchResult}
* @returns {BatchEvaluationResponse}
*/
public evaluateBatch(requests: EvaluationRequest[]): BatchResult {
return this.engine.evaluate_batch(requests);
public evaluateBatch(requests: EvaluationRequest[]): BatchEvaluationResponse {
const result = this.engine.evaluate_batch(requests) as BatchResult;

if (result.status === 'failure') {
throw new Error(result.error_message);
}

return result.result as BatchEvaluationResponse;
}
}
10 changes: 5 additions & 5 deletions flipt-client-browser/src/models.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export interface IFetcherOpts {
export interface IFetcherOptions {
etag?: string;
}

export interface IFetcher {
(opts?: IFetcherOpts): Promise<Response>;
(opts?: IFetcherOptions): Promise<Response>;
}

export interface AuthenticationStrategy {}
Expand All @@ -16,7 +16,7 @@ export interface JWTAuthentication extends AuthenticationStrategy {
jwt_token: string;
}

export interface EngineOpts {
export interface ClientOptions {
url?: string;
authentication?: AuthenticationStrategy;
reference?: string;
Expand All @@ -34,8 +34,8 @@ export interface VariantEvaluationResponse {
segment_keys: string[];
reason: string;
flag_key: string;
variant_key: string;
variant_attachment: string;
variant_key?: string;
variant_attachment?: string;
request_duration_millis: number;
timestamp: string;
}
Expand Down

0 comments on commit eb939e6

Please sign in to comment.