@orange-ember/easy-flags-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Easy Flags SDK
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for the **Easy Flags** feature flag management platform. Manage features toggles, rollouts, and targeting rules with ease in your Node.js or Browser applications.
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Universal Support**: Works seamlessly in Node.js, Browsers, and Edge environments.
|
|
8
|
+
- 🛡️ **Strongly Typed**: Full TypeScript support with generics for flag values.
|
|
9
|
+
- 📉 **Smart Context**: Automatically optimizes requests (GET/POST) based on context size.
|
|
10
|
+
- 🔇 **Silent Fail**: Never breaks your app – returns user-defined defaults if the service is unavailable.
|
|
11
|
+
- 📦 **Modern Bundle**: Shipped in ESM and CommonJS formats.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @orange-ember/easy-flags-sdk
|
|
17
|
+
# or
|
|
18
|
+
yarn add @orange-ember/easy-flags-sdk
|
|
19
|
+
# pnpm
|
|
20
|
+
pnpm add @orange-ember/easy-flags-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Initialize the Client
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { EasyFlagsClient } from "@orange-ember/easy-flags-sdk";
|
|
29
|
+
|
|
30
|
+
const client = new EasyFlagsClient({
|
|
31
|
+
apiKey: "your-api-key",
|
|
32
|
+
spaceId: "your-space-id",
|
|
33
|
+
environmentId: "your-environment-id",
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Evaluate a Flag
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Basic boolean toggle
|
|
41
|
+
const isFeatureEnabled = await client.evaluate("new-ui-v2", {
|
|
42
|
+
defaultValue: false,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (isFeatureEnabled) {
|
|
46
|
+
renderNewUI();
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Using Smart Context & Generics
|
|
51
|
+
|
|
52
|
+
Pass a `userId` and a custom `context` for advanced targeting and deterministic rollouts.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const buttonColor = await client.evaluate<string>("signup-btn-color", {
|
|
56
|
+
defaultValue: "#000000",
|
|
57
|
+
userId: "user_123",
|
|
58
|
+
context: {
|
|
59
|
+
plan: "premium",
|
|
60
|
+
country: "US",
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Advanced Configuration
|
|
66
|
+
|
|
67
|
+
| Option | Type | Default | Description |
|
|
68
|
+
| --------------- | --------- | ------------ | ------------------------------------------------ |
|
|
69
|
+
| `apiKey` | `string` | **Required** | Your Easy Flags API Key. |
|
|
70
|
+
| `spaceId` | `string` | **Required** | The ID of your Space. |
|
|
71
|
+
| `environmentId` | `string` | **Required** | The ID of the environment (e.g., prod, staging). |
|
|
72
|
+
| `baseUrl` | `string` | `https://` | Custom API base URL. |
|
|
73
|
+
| `debug` | `boolean` | `false` | Enable console logging for debugging. |
|
|
74
|
+
|
|
75
|
+
## Error Handling
|
|
76
|
+
|
|
77
|
+
The SDK implements a "Silent Fail" strategy. If a network request fails or the service returns an error, the `evaluate` method catch the error and return the `defaultValue` provided in the options.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const flag = await client.evaluate("my-flag", {
|
|
81
|
+
defaultValue: "safe-value",
|
|
82
|
+
});
|
|
83
|
+
// result is always 'safe-value' if something goes wrong
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
Apache-2.0 © Orange Ember Studios
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface EasyFlagsConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
spaceId: string;
|
|
4
|
+
environmentId: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface EvaluationOptions<T = any> {
|
|
9
|
+
userId?: string;
|
|
10
|
+
context?: Record<string, any>;
|
|
11
|
+
defaultValue: T;
|
|
12
|
+
}
|
|
13
|
+
interface EvaluationResult<T = any> {
|
|
14
|
+
value: T;
|
|
15
|
+
matched: boolean;
|
|
16
|
+
reason?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare class EasyFlagsClient {
|
|
20
|
+
private readonly config;
|
|
21
|
+
constructor(config: EasyFlagsConfig);
|
|
22
|
+
private log;
|
|
23
|
+
evaluate<T = any>(featureKey: string, options: EvaluationOptions<T>): Promise<T>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { EasyFlagsClient, type EasyFlagsConfig, type EvaluationOptions, type EvaluationResult };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface EasyFlagsConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
spaceId: string;
|
|
4
|
+
environmentId: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface EvaluationOptions<T = any> {
|
|
9
|
+
userId?: string;
|
|
10
|
+
context?: Record<string, any>;
|
|
11
|
+
defaultValue: T;
|
|
12
|
+
}
|
|
13
|
+
interface EvaluationResult<T = any> {
|
|
14
|
+
value: T;
|
|
15
|
+
matched: boolean;
|
|
16
|
+
reason?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare class EasyFlagsClient {
|
|
20
|
+
private readonly config;
|
|
21
|
+
constructor(config: EasyFlagsConfig);
|
|
22
|
+
private log;
|
|
23
|
+
evaluate<T = any>(featureKey: string, options: EvaluationOptions<T>): Promise<T>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { EasyFlagsClient, type EasyFlagsConfig, type EvaluationOptions, type EvaluationResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var p=(s,e)=>{for(var t in e)i(s,t,{get:e[t],enumerable:!0})},y=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of g(e))!d.call(s,a)&&a!==t&&i(s,a,{get:()=>e[a],enumerable:!(n=f(e,a))||n.enumerable});return s};var h=s=>y(i({},"__esModule",{value:!0}),s);var m={};p(m,{EasyFlagsClient:()=>l});module.exports=h(m);var l=class{constructor(e){this.config={baseUrl:"https://easy-flags.orangeember.com/api",debug:!1,...e}}log(...e){this.config.debug&&console.log("[EasyFlags]",...e)}async evaluate(e,t){try{let n=`${this.config.baseUrl}/api/features/${e}/evaluate`,a=new URLSearchParams;t.userId&&a.append("userId",t.userId),t.context&&a.append("context",JSON.stringify(t.context));let c=`${n}?${a.toString()}`,u=c.length>2048,r={headers:{"x-api-key":this.config.apiKey,"x-space-id":this.config.spaceId,"x-environment-id":this.config.environmentId,"Content-Type":"application/json"}};u?(r.method="POST",r.body=JSON.stringify({userId:t.userId,context:t.context})):r.method="GET";let o=await fetch(u?n:c,r);return o.ok?(await o.json()).value:(this.log(`Evaluation failed: ${o.status} ${o.statusText}`),t.defaultValue)}catch(n){return this.log("Evaluation error:",n),t.defaultValue}}};0&&(module.exports={EasyFlagsClient});
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export * from './client'\nexport type * from './types'\n","import type { EasyFlagsConfig, EvaluationOptions, EvaluationResult } from './types'\n\nexport class EasyFlagsClient {\n private readonly config: EasyFlagsConfig\n\n constructor(config: EasyFlagsConfig) {\n this.config = {\n baseUrl: 'https://easy-flags.orangeember.com/api',\n debug: false,\n ...config\n }\n }\n\n private log(...args: any[]) {\n if (this.config.debug) {\n console.log('[EasyFlags]', ...args)\n }\n }\n\n async evaluate<T = any>(featureKey: string, options: EvaluationOptions<T>): Promise<T> {\n try {\n const baseUrl = `${this.config.baseUrl}/api/features/${featureKey}/evaluate`\n const queryParams = new URLSearchParams()\n if (options.userId) queryParams.append('userId', options.userId)\n if (options.context) queryParams.append('context', JSON.stringify(options.context))\n\n const fullUrl = `${baseUrl}?${queryParams.toString()}`\n const isLarge = fullUrl.length > 2048\n\n const fetchOptions: RequestInit = {\n headers: {\n 'x-api-key': this.config.apiKey,\n 'x-space-id': this.config.spaceId,\n 'x-environment-id': this.config.environmentId,\n 'Content-Type': 'application/json'\n }\n }\n\n if (isLarge) {\n fetchOptions.method = 'POST'\n fetchOptions.body = JSON.stringify({\n userId: options.userId,\n context: options.context\n })\n } else {\n fetchOptions.method = 'GET'\n }\n\n const url = isLarge ? baseUrl : fullUrl\n const response = await fetch(url, fetchOptions)\n\n if (!response.ok) {\n this.log(`Evaluation failed: ${response.status} ${response.statusText}`)\n return options.defaultValue\n }\n\n const data: EvaluationResult<T> = await response.json()\n return data.value\n } catch (error) {\n this.log('Evaluation error:', error)\n return options.defaultValue\n }\n }\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,qBAAAE,IAAA,eAAAC,EAAAH,GCEO,IAAMI,EAAN,KAAsB,CAG3B,YAAYC,EAAyB,CACnC,KAAK,OAAS,CACZ,QAAS,yCACT,MAAO,GACP,GAAGA,CACL,CACF,CAEQ,OAAOC,EAAa,CACtB,KAAK,OAAO,OACd,QAAQ,IAAI,cAAe,GAAGA,CAAI,CAEtC,CAEA,MAAM,SAAkBC,EAAoBC,EAA2C,CACrF,GAAI,CACF,IAAMC,EAAU,GAAG,KAAK,OAAO,OAAO,iBAAiBF,CAAU,YAC3DG,EAAc,IAAI,gBACpBF,EAAQ,QAAQE,EAAY,OAAO,SAAUF,EAAQ,MAAM,EAC3DA,EAAQ,SAASE,EAAY,OAAO,UAAW,KAAK,UAAUF,EAAQ,OAAO,CAAC,EAElF,IAAMG,EAAU,GAAGF,CAAO,IAAIC,EAAY,SAAS,CAAC,GAC9CE,EAAUD,EAAQ,OAAS,KAE3BE,EAA4B,CAChC,QAAS,CACP,YAAa,KAAK,OAAO,OACzB,aAAc,KAAK,OAAO,QAC1B,mBAAoB,KAAK,OAAO,cAChC,eAAgB,kBAClB,CACF,EAEID,GACFC,EAAa,OAAS,OACtBA,EAAa,KAAO,KAAK,UAAU,CACjC,OAAQL,EAAQ,OAChB,QAASA,EAAQ,OACnB,CAAC,GAEDK,EAAa,OAAS,MAIxB,IAAMC,EAAW,MAAM,MADXF,EAAUH,EAAUE,EACEE,CAAY,EAE9C,OAAKC,EAAS,IAKoB,MAAMA,EAAS,KAAK,GAC1C,OALV,KAAK,IAAI,sBAAsBA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAChEN,EAAQ,aAKnB,OAASO,EAAO,CACd,YAAK,IAAI,oBAAqBA,CAAK,EAC5BP,EAAQ,YACjB,CACF,CACF","names":["index_exports","__export","EasyFlagsClient","__toCommonJS","EasyFlagsClient","config","args","featureKey","options","baseUrl","queryParams","fullUrl","isLarge","fetchOptions","response","error"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var l=class{constructor(t){this.config={baseUrl:"https://easy-flags.orangeember.com/api",debug:!1,...t}}log(...t){this.config.debug&&console.log("[EasyFlags]",...t)}async evaluate(t,e){try{let a=`${this.config.baseUrl}/api/features/${t}/evaluate`,r=new URLSearchParams;e.userId&&r.append("userId",e.userId),e.context&&r.append("context",JSON.stringify(e.context));let o=`${a}?${r.toString()}`,i=o.length>2048,s={headers:{"x-api-key":this.config.apiKey,"x-space-id":this.config.spaceId,"x-environment-id":this.config.environmentId,"Content-Type":"application/json"}};i?(s.method="POST",s.body=JSON.stringify({userId:e.userId,context:e.context})):s.method="GET";let n=await fetch(i?a:o,s);return n.ok?(await n.json()).value:(this.log(`Evaluation failed: ${n.status} ${n.statusText}`),e.defaultValue)}catch(a){return this.log("Evaluation error:",a),e.defaultValue}}};export{l as EasyFlagsClient};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type { EasyFlagsConfig, EvaluationOptions, EvaluationResult } from './types'\n\nexport class EasyFlagsClient {\n private readonly config: EasyFlagsConfig\n\n constructor(config: EasyFlagsConfig) {\n this.config = {\n baseUrl: 'https://easy-flags.orangeember.com/api',\n debug: false,\n ...config\n }\n }\n\n private log(...args: any[]) {\n if (this.config.debug) {\n console.log('[EasyFlags]', ...args)\n }\n }\n\n async evaluate<T = any>(featureKey: string, options: EvaluationOptions<T>): Promise<T> {\n try {\n const baseUrl = `${this.config.baseUrl}/api/features/${featureKey}/evaluate`\n const queryParams = new URLSearchParams()\n if (options.userId) queryParams.append('userId', options.userId)\n if (options.context) queryParams.append('context', JSON.stringify(options.context))\n\n const fullUrl = `${baseUrl}?${queryParams.toString()}`\n const isLarge = fullUrl.length > 2048\n\n const fetchOptions: RequestInit = {\n headers: {\n 'x-api-key': this.config.apiKey,\n 'x-space-id': this.config.spaceId,\n 'x-environment-id': this.config.environmentId,\n 'Content-Type': 'application/json'\n }\n }\n\n if (isLarge) {\n fetchOptions.method = 'POST'\n fetchOptions.body = JSON.stringify({\n userId: options.userId,\n context: options.context\n })\n } else {\n fetchOptions.method = 'GET'\n }\n\n const url = isLarge ? baseUrl : fullUrl\n const response = await fetch(url, fetchOptions)\n\n if (!response.ok) {\n this.log(`Evaluation failed: ${response.status} ${response.statusText}`)\n return options.defaultValue\n }\n\n const data: EvaluationResult<T> = await response.json()\n return data.value\n } catch (error) {\n this.log('Evaluation error:', error)\n return options.defaultValue\n }\n }\n}\n"],"mappings":"AAEO,IAAMA,EAAN,KAAsB,CAG3B,YAAYC,EAAyB,CACnC,KAAK,OAAS,CACZ,QAAS,yCACT,MAAO,GACP,GAAGA,CACL,CACF,CAEQ,OAAOC,EAAa,CACtB,KAAK,OAAO,OACd,QAAQ,IAAI,cAAe,GAAGA,CAAI,CAEtC,CAEA,MAAM,SAAkBC,EAAoBC,EAA2C,CACrF,GAAI,CACF,IAAMC,EAAU,GAAG,KAAK,OAAO,OAAO,iBAAiBF,CAAU,YAC3DG,EAAc,IAAI,gBACpBF,EAAQ,QAAQE,EAAY,OAAO,SAAUF,EAAQ,MAAM,EAC3DA,EAAQ,SAASE,EAAY,OAAO,UAAW,KAAK,UAAUF,EAAQ,OAAO,CAAC,EAElF,IAAMG,EAAU,GAAGF,CAAO,IAAIC,EAAY,SAAS,CAAC,GAC9CE,EAAUD,EAAQ,OAAS,KAE3BE,EAA4B,CAChC,QAAS,CACP,YAAa,KAAK,OAAO,OACzB,aAAc,KAAK,OAAO,QAC1B,mBAAoB,KAAK,OAAO,cAChC,eAAgB,kBAClB,CACF,EAEID,GACFC,EAAa,OAAS,OACtBA,EAAa,KAAO,KAAK,UAAU,CACjC,OAAQL,EAAQ,OAChB,QAASA,EAAQ,OACnB,CAAC,GAEDK,EAAa,OAAS,MAIxB,IAAMC,EAAW,MAAM,MADXF,EAAUH,EAAUE,EACEE,CAAY,EAE9C,OAAKC,EAAS,IAKoB,MAAMA,EAAS,KAAK,GAC1C,OALV,KAAK,IAAI,sBAAsBA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAChEN,EAAQ,aAKnB,OAASO,EAAO,CACd,YAAK,IAAI,oBAAqBA,CAAK,EAC5BP,EAAQ,YACjB,CACF,CACF","names":["EasyFlagsClient","config","args","featureKey","options","baseUrl","queryParams","fullUrl","isLarge","fetchOptions","response","error"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@orange-ember/easy-flags-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official TypeScript SDK for Easy Flags management platform.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup",
|
|
13
|
+
"dev": "tsup --watch",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"lint:fix": "eslint . --fix",
|
|
18
|
+
"format": "prettier --write .",
|
|
19
|
+
"check-types": "tsc --noEmit",
|
|
20
|
+
"prepare": "husky"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"feature-flags",
|
|
24
|
+
"feature-toggles",
|
|
25
|
+
"sdk",
|
|
26
|
+
"typescript",
|
|
27
|
+
"javascript",
|
|
28
|
+
"node",
|
|
29
|
+
"browser",
|
|
30
|
+
"edge",
|
|
31
|
+
"orange-ember",
|
|
32
|
+
"easy-flags"
|
|
33
|
+
],
|
|
34
|
+
"author": "Seobryn <ing.jose.joya@gmail.com>",
|
|
35
|
+
"license": "Apache-2.0",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^25.5.2",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
39
|
+
"@typescript-eslint/parser": "^8.58.0",
|
|
40
|
+
"eslint": "^9.39.4",
|
|
41
|
+
"eslint-config-love": "^151.0.0",
|
|
42
|
+
"eslint-config-prettier": "^10.1.8",
|
|
43
|
+
"eslint-plugin-import": "^2.32.0",
|
|
44
|
+
"eslint-plugin-n": "^17.24.0",
|
|
45
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
46
|
+
"husky": "^9.1.7",
|
|
47
|
+
"lint-staged": "^16.4.0",
|
|
48
|
+
"prettier": "^3.8.1",
|
|
49
|
+
"ts-node": "^10.9.2",
|
|
50
|
+
"tsup": "^8.5.1",
|
|
51
|
+
"typescript": "^5.4.5",
|
|
52
|
+
"vitest": "^4.1.2"
|
|
53
|
+
},
|
|
54
|
+
"lint-staged": {
|
|
55
|
+
"*.{js,mjs,ts}": [
|
|
56
|
+
"eslint --fix",
|
|
57
|
+
"prettier --write",
|
|
58
|
+
"vitest related --run --passWithNoTests=false"
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|