@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 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
@@ -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 };
@@ -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
+ }