@featureflare/sdk-js 0.0.6 → 0.0.7
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 +49 -22
- package/dist/index.cjs +59 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -6
- package/dist/index.d.ts +12 -6
- package/dist/index.js +59 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @featureflare/sdk-js
|
|
2
2
|
|
|
3
|
-
JavaScript/TypeScript SDK for
|
|
3
|
+
JavaScript/TypeScript SDK for FeatureFlare feature flags.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -17,15 +17,15 @@ yarn add @featureflare/sdk-js
|
|
|
17
17
|
### Basic Example
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
import {
|
|
20
|
+
import { FeatureFlareClient } from '@featureflare/sdk-js';
|
|
21
21
|
|
|
22
22
|
// SDK automatically uses production API URL
|
|
23
|
-
// Set
|
|
24
|
-
const
|
|
23
|
+
// Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey explicitly
|
|
24
|
+
const featureflare = new FeatureFlareClient({
|
|
25
25
|
sdkKey: 'your-sdk-key-here'
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const enabled = await
|
|
28
|
+
const enabled = await featureflare.bool('new-nav', { id: 'user-123' }, false);
|
|
29
29
|
console.log(enabled);
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -33,29 +33,38 @@ console.log(enabled);
|
|
|
33
33
|
|
|
34
34
|
The SDK automatically reads from environment variables if `sdkKey` is not provided:
|
|
35
35
|
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
36
|
+
- `FEATUREFLARE_CLIENT_KEY` - Client SDK key (for browser/mobile)
|
|
37
|
+
- `FEATUREFLARE_SERVER_KEY` - Server SDK key (for backend)
|
|
38
|
+
- `FEATUREFLARE_ENV_KEY` - Expected environment key binding (`development`, `staging`, `production`, etc.)
|
|
38
39
|
|
|
39
40
|
```typescript
|
|
40
|
-
// In Node.js, this will use
|
|
41
|
-
const
|
|
41
|
+
// In Node.js, this will use FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY from env
|
|
42
|
+
const featureflare = new FeatureFlareClient();
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
### API Base URL
|
|
45
46
|
|
|
46
47
|
The SDK automatically determines the API base URL:
|
|
47
48
|
|
|
48
|
-
-
|
|
49
|
-
- **
|
|
49
|
+
- **`options.apiBaseUrl`**: Highest priority if provided.
|
|
50
|
+
- **Environment variables**: `FEATUREFLARE_API_BASE_URL`, then `SHIPIT_API_BASE_URL`.
|
|
51
|
+
- **Default fallback (all runtimes)**: `https://shipit-api-392444455847.us-central1.run.app`.
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
Example override:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
const featureflare = new FeatureFlareClient({
|
|
57
|
+
apiBaseUrl: 'https://flags.your-company.com',
|
|
58
|
+
sdkKey: 'featureflare_cli_...'
|
|
59
|
+
});
|
|
60
|
+
```
|
|
52
61
|
|
|
53
62
|
### User Payload
|
|
54
63
|
|
|
55
64
|
```typescript
|
|
56
|
-
import {
|
|
65
|
+
import { FeatureFlareClient, type FeatureFlareUserPayload } from '@featureflare/sdk-js';
|
|
57
66
|
|
|
58
|
-
const user:
|
|
67
|
+
const user: FeatureFlareUserPayload = {
|
|
59
68
|
id: 'user-123', // Required: unique user identifier
|
|
60
69
|
email: 'user@example.com',
|
|
61
70
|
name: 'John Doe',
|
|
@@ -66,28 +75,31 @@ const user: ShipItUserPayload = {
|
|
|
66
75
|
}
|
|
67
76
|
};
|
|
68
77
|
|
|
69
|
-
const enabled = await
|
|
78
|
+
const enabled = await featureflare.bool('feature-flag', user, false);
|
|
70
79
|
```
|
|
71
80
|
|
|
72
81
|
## API Reference
|
|
73
82
|
|
|
74
|
-
### `
|
|
83
|
+
### `FeatureFlareClient`
|
|
75
84
|
|
|
76
85
|
#### Constructor
|
|
77
86
|
|
|
78
87
|
```typescript
|
|
79
|
-
new
|
|
88
|
+
new FeatureFlareClient(options?: FeatureFlareClientOptions)
|
|
80
89
|
```
|
|
81
90
|
|
|
82
91
|
**Options:**
|
|
83
92
|
|
|
84
|
-
- `
|
|
93
|
+
- `apiBaseUrl?: string` - Explicit FeatureFlare API base URL.
|
|
94
|
+
- `sdkKey?: string` - SDK key (client or server). If not provided, reads from `FEATUREFLARE_CLIENT_KEY` or `FEATUREFLARE_SERVER_KEY` env vars.
|
|
85
95
|
- `projectKey?: string` - Legacy: project key (requires `envKey`). Not recommended.
|
|
86
96
|
- `envKey?: string` - Environment key (default: `'production'`). Only used with `projectKey`.
|
|
87
97
|
|
|
98
|
+
When using `sdkKey`, `envKey` is sent as an expected environment binding. The API rejects requests if the key's actual environment does not match `envKey`.
|
|
99
|
+
|
|
88
100
|
#### Methods
|
|
89
101
|
|
|
90
|
-
##### `bool(flagKey: string, user:
|
|
102
|
+
##### `bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<boolean>`
|
|
91
103
|
|
|
92
104
|
Evaluates a boolean feature flag for a user.
|
|
93
105
|
|
|
@@ -100,7 +112,22 @@ Returns `Promise<boolean>` - The flag value for the user.
|
|
|
100
112
|
**Example:**
|
|
101
113
|
|
|
102
114
|
```typescript
|
|
103
|
-
const enabled = await
|
|
115
|
+
const enabled = await featureflare.bool('new-nav', { id: 'user-123' }, false);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
##### `flags(user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<Record<string, boolean>>`
|
|
119
|
+
|
|
120
|
+
Fetches all boolean flags for the provided user.
|
|
121
|
+
|
|
122
|
+
- `user`: User payload with `id` or `key` (required)
|
|
123
|
+
- `defaultValue`: Default value to apply for missing/offline evaluations (default: `false`)
|
|
124
|
+
|
|
125
|
+
Returns `Promise<Record<string, boolean>>` - A map of `flagKey -> value`.
|
|
126
|
+
|
|
127
|
+
**Example:**
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const allFlags = await featureflare.flags({ id: 'user-123' }, false);
|
|
104
131
|
```
|
|
105
132
|
|
|
106
133
|
## Error Handling
|
|
@@ -109,7 +136,7 @@ If the API request fails (network error, non-2xx status), the SDK returns the `d
|
|
|
109
136
|
|
|
110
137
|
```typescript
|
|
111
138
|
try {
|
|
112
|
-
const enabled = await
|
|
139
|
+
const enabled = await featureflare.bool('flag', user, false);
|
|
113
140
|
} catch (error) {
|
|
114
141
|
// Handle network errors
|
|
115
142
|
console.error('Failed to evaluate flag:', error);
|
|
@@ -123,7 +150,7 @@ Each environment has two SDK keys:
|
|
|
123
150
|
- **Server key**: Secret. Use only in trusted server environments.
|
|
124
151
|
- **Client key**: Not a secret. Intended for browser/mobile SDKs.
|
|
125
152
|
|
|
126
|
-
Get your SDK keys from your
|
|
153
|
+
Get your SDK keys from your FeatureFlare Console → Environments.
|
|
127
154
|
|
|
128
155
|
## License
|
|
129
156
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,35 +1,54 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
var DEFAULT_FEATUREFLARE_API_BASE_URL = "https://shipit-api-392444455847.us-central1.run.app";
|
|
5
|
+
function getApiBaseUrlFromEnv() {
|
|
6
|
+
if (typeof process !== "undefined" && process.env) {
|
|
7
|
+
return process.env.FEATUREFLARE_API_BASE_URL?.trim() || process.env.SHIPIT_API_BASE_URL?.trim() || null;
|
|
7
8
|
}
|
|
8
|
-
return
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
function getApiBaseUrl(explicit) {
|
|
12
|
+
const fromOptions = explicit?.trim();
|
|
13
|
+
if (fromOptions) return fromOptions;
|
|
14
|
+
const fromEnv = getApiBaseUrlFromEnv();
|
|
15
|
+
if (fromEnv) return fromEnv;
|
|
16
|
+
return DEFAULT_FEATUREFLARE_API_BASE_URL;
|
|
17
|
+
}
|
|
18
|
+
function getEnvKeyFromEnv() {
|
|
19
|
+
if (typeof process !== "undefined" && process.env) {
|
|
20
|
+
return process.env.FEATUREFLARE_ENV_KEY?.trim() || process.env.SHIPIT_ENV_KEY?.trim() || null;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
9
23
|
}
|
|
10
24
|
function getSdkKeyFromEnv() {
|
|
11
25
|
if (typeof process !== "undefined" && process.env) {
|
|
12
|
-
return process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;
|
|
26
|
+
return process.env.FEATUREFLARE_CLIENT_KEY?.trim() || process.env.FEATUREFLARE_SERVER_KEY?.trim() || process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;
|
|
13
27
|
}
|
|
14
28
|
return null;
|
|
15
29
|
}
|
|
16
|
-
var
|
|
30
|
+
var FeatureFlareClient = class {
|
|
17
31
|
apiBaseUrl;
|
|
18
32
|
sdkKey;
|
|
19
33
|
projectKey;
|
|
20
34
|
envKey;
|
|
35
|
+
expectedEnvKey;
|
|
21
36
|
constructor(options = {}) {
|
|
22
|
-
this.apiBaseUrl = getApiBaseUrl().replace(/\/$/, "");
|
|
37
|
+
this.apiBaseUrl = getApiBaseUrl(options.apiBaseUrl).replace(/\/$/, "");
|
|
23
38
|
this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();
|
|
24
39
|
this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;
|
|
25
|
-
|
|
40
|
+
const resolvedEnvKey = options.envKey?.trim() || getEnvKeyFromEnv() || "production";
|
|
41
|
+
this.envKey = resolvedEnvKey;
|
|
42
|
+
this.expectedEnvKey = resolvedEnvKey;
|
|
26
43
|
if (!this.sdkKey && !this.projectKey) {
|
|
27
|
-
throw new Error(
|
|
44
|
+
throw new Error(
|
|
45
|
+
"FeatureFlareClient requires either sdkKey (recommended) or projectKey (legacy). Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey in options."
|
|
46
|
+
);
|
|
28
47
|
}
|
|
29
48
|
}
|
|
30
49
|
normalizeUser(input) {
|
|
31
50
|
const key = (input.id ?? input.key ?? "").trim();
|
|
32
|
-
if (!key) throw new Error("
|
|
51
|
+
if (!key) throw new Error("FeatureFlareClient requires user.id (or legacy user.key).");
|
|
33
52
|
return {
|
|
34
53
|
key,
|
|
35
54
|
email: input.email,
|
|
@@ -49,7 +68,8 @@ var ShipItClient = class {
|
|
|
49
68
|
body: JSON.stringify({
|
|
50
69
|
flagKey,
|
|
51
70
|
user: normalizedUser,
|
|
52
|
-
defaultValue
|
|
71
|
+
defaultValue,
|
|
72
|
+
expectedEnvKey: this.expectedEnvKey ?? void 0
|
|
53
73
|
})
|
|
54
74
|
}) : await fetch(`${this.apiBaseUrl}/api/v1/eval`, {
|
|
55
75
|
method: "POST",
|
|
@@ -66,8 +86,35 @@ var ShipItClient = class {
|
|
|
66
86
|
const json = await res.json();
|
|
67
87
|
return json.value;
|
|
68
88
|
}
|
|
89
|
+
async flags(user, defaultValue = false) {
|
|
90
|
+
if (!this.sdkKey) {
|
|
91
|
+
throw new Error("FeatureFlareClient.flags requires sdkKey. Legacy projectKey mode does not support listing all flags.");
|
|
92
|
+
}
|
|
93
|
+
const normalizedUser = this.normalizeUser(user);
|
|
94
|
+
const res = await fetch(`${this.apiBaseUrl}/api/v1/sdk/flags`, {
|
|
95
|
+
method: "POST",
|
|
96
|
+
headers: {
|
|
97
|
+
"content-type": "application/json",
|
|
98
|
+
"x-featureflare-sdk-key": this.sdkKey
|
|
99
|
+
},
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
user: normalizedUser,
|
|
102
|
+
defaultValue,
|
|
103
|
+
expectedEnvKey: this.expectedEnvKey ?? void 0
|
|
104
|
+
})
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok) return [];
|
|
107
|
+
const json = await res.json();
|
|
108
|
+
if (Array.isArray(json.flags)) {
|
|
109
|
+
return json.flags.filter(
|
|
110
|
+
(entry) => !!entry && typeof entry.key === "string" && typeof entry.value === "boolean"
|
|
111
|
+
).map((entry) => ({ key: entry.key, value: entry.value }));
|
|
112
|
+
}
|
|
113
|
+
const values = json.values ?? {};
|
|
114
|
+
return Object.entries(values).map(([key, value]) => ({ key, value: Boolean(value) }));
|
|
115
|
+
}
|
|
69
116
|
};
|
|
70
117
|
|
|
71
|
-
exports.
|
|
118
|
+
exports.FeatureFlareClient = FeatureFlareClient;
|
|
72
119
|
//# sourceMappingURL=index.cjs.map
|
|
73
120
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAsBA,SAAS,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export type FeatureFlareUserPayload = {\n /** Unique user identifier (preferred). */\n id?: string;\n /** Legacy alias for id. */\n key?: string;\n email?: string;\n name?: string;\n country?: string;\n /** Queryable attributes. */\n meta?: Record<string, string | number | boolean | null>;\n /** Legacy alias for meta. */\n custom?: Record<string, string | number | boolean | null>;\n};\n\ntype FeatureFlareUser = {\n key: string;\n email?: string;\n name?: string;\n country?: string;\n custom?: Record<string, string | number | boolean | null>;\n};\n\nconst DEFAULT_FEATUREFLARE_API_BASE_URL =\n 'https://shipit-api-392444455847.us-central1.run.app';\n\nfunction getApiBaseUrlFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_API_BASE_URL?.trim() ||\n process.env.SHIPIT_API_BASE_URL?.trim() ||\n null\n );\n }\n return null;\n}\n\nfunction getApiBaseUrl(explicit?: string): string {\n const fromOptions = explicit?.trim();\n if (fromOptions) return fromOptions;\n\n const fromEnv = getApiBaseUrlFromEnv();\n if (fromEnv) return fromEnv;\n\n return DEFAULT_FEATUREFLARE_API_BASE_URL;\n}\n\nexport type FeatureFlareClientOptions = {\n apiBaseUrl?: string;\n sdkKey?: string;\n projectKey?: string;\n envKey?: string;\n};\n\nfunction getEnvKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_ENV_KEY?.trim() ||\n process.env.SHIPIT_ENV_KEY?.trim() ||\n null\n );\n }\n return null;\n}\n\nfunction getSdkKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_CLIENT_KEY?.trim() ||\n process.env.FEATUREFLARE_SERVER_KEY?.trim() ||\n process.env.SHIPIT_CLIENT_KEY?.trim() ||\n process.env.SHIPIT_SERVER_KEY?.trim() ||\n null\n );\n }\n return null;\n}\n\nexport class FeatureFlareClient {\n private readonly apiBaseUrl: string;\n private readonly sdkKey: string | null;\n private readonly projectKey: string | null;\n private readonly envKey: string;\n private readonly expectedEnvKey: string | null;\n\n constructor(options: FeatureFlareClientOptions = {}) {\n this.apiBaseUrl = getApiBaseUrl(options.apiBaseUrl).replace(/\\/$/, '');\n this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();\n this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;\n const resolvedEnvKey = options.envKey?.trim() || getEnvKeyFromEnv() || 'production';\n this.envKey = resolvedEnvKey;\n this.expectedEnvKey = resolvedEnvKey;\n\n if (!this.sdkKey && !this.projectKey) {\n throw new Error(\n 'FeatureFlareClient requires either sdkKey (recommended) or projectKey (legacy). Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey in options.'\n );\n }\n }\n\n private normalizeUser(input: FeatureFlareUserPayload): FeatureFlareUser {\n const key = (input.id ?? input.key ?? '').trim();\n if (!key) throw new Error('FeatureFlareClient requires user.id (or legacy user.key).');\n return {\n key,\n email: input.email,\n name: input.name,\n country: input.country,\n custom: input.meta ?? input.custom\n };\n }\n\n async bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue = false): Promise<boolean> {\n const normalizedUser = this.normalizeUser(user);\n const res = this.sdkKey\n ? await fetch(`${this.apiBaseUrl}/api/v1/sdk/eval`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-featureflare-sdk-key': this.sdkKey\n },\n body: JSON.stringify({\n flagKey,\n user: normalizedUser,\n defaultValue,\n expectedEnvKey: this.expectedEnvKey ?? undefined\n })\n })\n : await fetch(`${this.apiBaseUrl}/api/v1/eval`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n projectKey: this.projectKey,\n envKey: this.envKey,\n flagKey,\n user: normalizedUser,\n defaultValue\n })\n });\n\n if (!res.ok) return defaultValue;\n const json = (await res.json()) as { value: boolean };\n return json.value;\n }\n\n async flags(user: FeatureFlareUserPayload, defaultValue = false): Promise<Array<{ key: string; value: boolean }>> {\n if (!this.sdkKey) {\n throw new Error('FeatureFlareClient.flags requires sdkKey. Legacy projectKey mode does not support listing all flags.');\n }\n\n const normalizedUser = this.normalizeUser(user);\n const res = await fetch(`${this.apiBaseUrl}/api/v1/sdk/flags`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-featureflare-sdk-key': this.sdkKey\n },\n body: JSON.stringify({\n user: normalizedUser,\n defaultValue,\n expectedEnvKey: this.expectedEnvKey ?? undefined\n })\n });\n\n if (!res.ok) return [];\n const json = (await res.json()) as {\n flags?: Array<{ key: string; value: boolean }>;\n values?: Record<string, boolean>;\n };\n\n if (Array.isArray(json.flags)) {\n return json.flags\n .filter((entry): entry is { key: string; value: boolean } =>\n !!entry && typeof entry.key === 'string' && typeof entry.value === 'boolean'\n )\n .map((entry) => ({ key: entry.key, value: entry.value }));\n }\n\n const values = json.values ?? {};\n return Object.entries(values).map(([key, value]) => ({ key, value: Boolean(value) }));\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type
|
|
1
|
+
type FeatureFlareUserPayload = {
|
|
2
2
|
/** Unique user identifier (preferred). */
|
|
3
3
|
id?: string;
|
|
4
4
|
/** Legacy alias for id. */
|
|
@@ -11,19 +11,25 @@ type ShipItUserPayload = {
|
|
|
11
11
|
/** Legacy alias for meta. */
|
|
12
12
|
custom?: Record<string, string | number | boolean | null>;
|
|
13
13
|
};
|
|
14
|
-
type
|
|
14
|
+
type FeatureFlareClientOptions = {
|
|
15
|
+
apiBaseUrl?: string;
|
|
15
16
|
sdkKey?: string;
|
|
16
17
|
projectKey?: string;
|
|
17
18
|
envKey?: string;
|
|
18
19
|
};
|
|
19
|
-
declare class
|
|
20
|
+
declare class FeatureFlareClient {
|
|
20
21
|
private readonly apiBaseUrl;
|
|
21
22
|
private readonly sdkKey;
|
|
22
23
|
private readonly projectKey;
|
|
23
24
|
private readonly envKey;
|
|
24
|
-
|
|
25
|
+
private readonly expectedEnvKey;
|
|
26
|
+
constructor(options?: FeatureFlareClientOptions);
|
|
25
27
|
private normalizeUser;
|
|
26
|
-
bool(flagKey: string, user:
|
|
28
|
+
bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<boolean>;
|
|
29
|
+
flags(user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<Array<{
|
|
30
|
+
key: string;
|
|
31
|
+
value: boolean;
|
|
32
|
+
}>>;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
export {
|
|
35
|
+
export { FeatureFlareClient, type FeatureFlareClientOptions, type FeatureFlareUserPayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type
|
|
1
|
+
type FeatureFlareUserPayload = {
|
|
2
2
|
/** Unique user identifier (preferred). */
|
|
3
3
|
id?: string;
|
|
4
4
|
/** Legacy alias for id. */
|
|
@@ -11,19 +11,25 @@ type ShipItUserPayload = {
|
|
|
11
11
|
/** Legacy alias for meta. */
|
|
12
12
|
custom?: Record<string, string | number | boolean | null>;
|
|
13
13
|
};
|
|
14
|
-
type
|
|
14
|
+
type FeatureFlareClientOptions = {
|
|
15
|
+
apiBaseUrl?: string;
|
|
15
16
|
sdkKey?: string;
|
|
16
17
|
projectKey?: string;
|
|
17
18
|
envKey?: string;
|
|
18
19
|
};
|
|
19
|
-
declare class
|
|
20
|
+
declare class FeatureFlareClient {
|
|
20
21
|
private readonly apiBaseUrl;
|
|
21
22
|
private readonly sdkKey;
|
|
22
23
|
private readonly projectKey;
|
|
23
24
|
private readonly envKey;
|
|
24
|
-
|
|
25
|
+
private readonly expectedEnvKey;
|
|
26
|
+
constructor(options?: FeatureFlareClientOptions);
|
|
25
27
|
private normalizeUser;
|
|
26
|
-
bool(flagKey: string, user:
|
|
28
|
+
bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<boolean>;
|
|
29
|
+
flags(user: FeatureFlareUserPayload, defaultValue?: boolean): Promise<Array<{
|
|
30
|
+
key: string;
|
|
31
|
+
value: boolean;
|
|
32
|
+
}>>;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
export {
|
|
35
|
+
export { FeatureFlareClient, type FeatureFlareClientOptions, type FeatureFlareUserPayload };
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,52 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var DEFAULT_FEATUREFLARE_API_BASE_URL = "https://shipit-api-392444455847.us-central1.run.app";
|
|
3
|
+
function getApiBaseUrlFromEnv() {
|
|
4
|
+
if (typeof process !== "undefined" && process.env) {
|
|
5
|
+
return process.env.FEATUREFLARE_API_BASE_URL?.trim() || process.env.SHIPIT_API_BASE_URL?.trim() || null;
|
|
5
6
|
}
|
|
6
|
-
return
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
function getApiBaseUrl(explicit) {
|
|
10
|
+
const fromOptions = explicit?.trim();
|
|
11
|
+
if (fromOptions) return fromOptions;
|
|
12
|
+
const fromEnv = getApiBaseUrlFromEnv();
|
|
13
|
+
if (fromEnv) return fromEnv;
|
|
14
|
+
return DEFAULT_FEATUREFLARE_API_BASE_URL;
|
|
15
|
+
}
|
|
16
|
+
function getEnvKeyFromEnv() {
|
|
17
|
+
if (typeof process !== "undefined" && process.env) {
|
|
18
|
+
return process.env.FEATUREFLARE_ENV_KEY?.trim() || process.env.SHIPIT_ENV_KEY?.trim() || null;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
7
21
|
}
|
|
8
22
|
function getSdkKeyFromEnv() {
|
|
9
23
|
if (typeof process !== "undefined" && process.env) {
|
|
10
|
-
return process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;
|
|
24
|
+
return process.env.FEATUREFLARE_CLIENT_KEY?.trim() || process.env.FEATUREFLARE_SERVER_KEY?.trim() || process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;
|
|
11
25
|
}
|
|
12
26
|
return null;
|
|
13
27
|
}
|
|
14
|
-
var
|
|
28
|
+
var FeatureFlareClient = class {
|
|
15
29
|
apiBaseUrl;
|
|
16
30
|
sdkKey;
|
|
17
31
|
projectKey;
|
|
18
32
|
envKey;
|
|
33
|
+
expectedEnvKey;
|
|
19
34
|
constructor(options = {}) {
|
|
20
|
-
this.apiBaseUrl = getApiBaseUrl().replace(/\/$/, "");
|
|
35
|
+
this.apiBaseUrl = getApiBaseUrl(options.apiBaseUrl).replace(/\/$/, "");
|
|
21
36
|
this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();
|
|
22
37
|
this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;
|
|
23
|
-
|
|
38
|
+
const resolvedEnvKey = options.envKey?.trim() || getEnvKeyFromEnv() || "production";
|
|
39
|
+
this.envKey = resolvedEnvKey;
|
|
40
|
+
this.expectedEnvKey = resolvedEnvKey;
|
|
24
41
|
if (!this.sdkKey && !this.projectKey) {
|
|
25
|
-
throw new Error(
|
|
42
|
+
throw new Error(
|
|
43
|
+
"FeatureFlareClient requires either sdkKey (recommended) or projectKey (legacy). Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey in options."
|
|
44
|
+
);
|
|
26
45
|
}
|
|
27
46
|
}
|
|
28
47
|
normalizeUser(input) {
|
|
29
48
|
const key = (input.id ?? input.key ?? "").trim();
|
|
30
|
-
if (!key) throw new Error("
|
|
49
|
+
if (!key) throw new Error("FeatureFlareClient requires user.id (or legacy user.key).");
|
|
31
50
|
return {
|
|
32
51
|
key,
|
|
33
52
|
email: input.email,
|
|
@@ -47,7 +66,8 @@ var ShipItClient = class {
|
|
|
47
66
|
body: JSON.stringify({
|
|
48
67
|
flagKey,
|
|
49
68
|
user: normalizedUser,
|
|
50
|
-
defaultValue
|
|
69
|
+
defaultValue,
|
|
70
|
+
expectedEnvKey: this.expectedEnvKey ?? void 0
|
|
51
71
|
})
|
|
52
72
|
}) : await fetch(`${this.apiBaseUrl}/api/v1/eval`, {
|
|
53
73
|
method: "POST",
|
|
@@ -64,8 +84,35 @@ var ShipItClient = class {
|
|
|
64
84
|
const json = await res.json();
|
|
65
85
|
return json.value;
|
|
66
86
|
}
|
|
87
|
+
async flags(user, defaultValue = false) {
|
|
88
|
+
if (!this.sdkKey) {
|
|
89
|
+
throw new Error("FeatureFlareClient.flags requires sdkKey. Legacy projectKey mode does not support listing all flags.");
|
|
90
|
+
}
|
|
91
|
+
const normalizedUser = this.normalizeUser(user);
|
|
92
|
+
const res = await fetch(`${this.apiBaseUrl}/api/v1/sdk/flags`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: {
|
|
95
|
+
"content-type": "application/json",
|
|
96
|
+
"x-featureflare-sdk-key": this.sdkKey
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
user: normalizedUser,
|
|
100
|
+
defaultValue,
|
|
101
|
+
expectedEnvKey: this.expectedEnvKey ?? void 0
|
|
102
|
+
})
|
|
103
|
+
});
|
|
104
|
+
if (!res.ok) return [];
|
|
105
|
+
const json = await res.json();
|
|
106
|
+
if (Array.isArray(json.flags)) {
|
|
107
|
+
return json.flags.filter(
|
|
108
|
+
(entry) => !!entry && typeof entry.key === "string" && typeof entry.value === "boolean"
|
|
109
|
+
).map((entry) => ({ key: entry.key, value: entry.value }));
|
|
110
|
+
}
|
|
111
|
+
const values = json.values ?? {};
|
|
112
|
+
return Object.entries(values).map(([key, value]) => ({ key, value: Boolean(value) }));
|
|
113
|
+
}
|
|
67
114
|
};
|
|
68
115
|
|
|
69
|
-
export {
|
|
116
|
+
export { FeatureFlareClient };
|
|
70
117
|
//# sourceMappingURL=index.js.map
|
|
71
118
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAsBA,SAAS,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type FeatureFlareUserPayload = {\n /** Unique user identifier (preferred). */\n id?: string;\n /** Legacy alias for id. */\n key?: string;\n email?: string;\n name?: string;\n country?: string;\n /** Queryable attributes. */\n meta?: Record<string, string | number | boolean | null>;\n /** Legacy alias for meta. */\n custom?: Record<string, string | number | boolean | null>;\n};\n\ntype FeatureFlareUser = {\n key: string;\n email?: string;\n name?: string;\n country?: string;\n custom?: Record<string, string | number | boolean | null>;\n};\n\nconst DEFAULT_FEATUREFLARE_API_BASE_URL =\n 'https://shipit-api-392444455847.us-central1.run.app';\n\nfunction getApiBaseUrlFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_API_BASE_URL?.trim() ||\n process.env.SHIPIT_API_BASE_URL?.trim() ||\n null\n );\n }\n return null;\n}\n\nfunction getApiBaseUrl(explicit?: string): string {\n const fromOptions = explicit?.trim();\n if (fromOptions) return fromOptions;\n\n const fromEnv = getApiBaseUrlFromEnv();\n if (fromEnv) return fromEnv;\n\n return DEFAULT_FEATUREFLARE_API_BASE_URL;\n}\n\nexport type FeatureFlareClientOptions = {\n apiBaseUrl?: string;\n sdkKey?: string;\n projectKey?: string;\n envKey?: string;\n};\n\nfunction getEnvKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_ENV_KEY?.trim() ||\n process.env.SHIPIT_ENV_KEY?.trim() ||\n null\n );\n }\n return null;\n}\n\nfunction getSdkKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return (\n process.env.FEATUREFLARE_CLIENT_KEY?.trim() ||\n process.env.FEATUREFLARE_SERVER_KEY?.trim() ||\n process.env.SHIPIT_CLIENT_KEY?.trim() ||\n process.env.SHIPIT_SERVER_KEY?.trim() ||\n null\n );\n }\n return null;\n}\n\nexport class FeatureFlareClient {\n private readonly apiBaseUrl: string;\n private readonly sdkKey: string | null;\n private readonly projectKey: string | null;\n private readonly envKey: string;\n private readonly expectedEnvKey: string | null;\n\n constructor(options: FeatureFlareClientOptions = {}) {\n this.apiBaseUrl = getApiBaseUrl(options.apiBaseUrl).replace(/\\/$/, '');\n this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();\n this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;\n const resolvedEnvKey = options.envKey?.trim() || getEnvKeyFromEnv() || 'production';\n this.envKey = resolvedEnvKey;\n this.expectedEnvKey = resolvedEnvKey;\n\n if (!this.sdkKey && !this.projectKey) {\n throw new Error(\n 'FeatureFlareClient requires either sdkKey (recommended) or projectKey (legacy). Set FEATUREFLARE_CLIENT_KEY or FEATUREFLARE_SERVER_KEY env var, or pass sdkKey in options.'\n );\n }\n }\n\n private normalizeUser(input: FeatureFlareUserPayload): FeatureFlareUser {\n const key = (input.id ?? input.key ?? '').trim();\n if (!key) throw new Error('FeatureFlareClient requires user.id (or legacy user.key).');\n return {\n key,\n email: input.email,\n name: input.name,\n country: input.country,\n custom: input.meta ?? input.custom\n };\n }\n\n async bool(flagKey: string, user: FeatureFlareUserPayload, defaultValue = false): Promise<boolean> {\n const normalizedUser = this.normalizeUser(user);\n const res = this.sdkKey\n ? await fetch(`${this.apiBaseUrl}/api/v1/sdk/eval`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-featureflare-sdk-key': this.sdkKey\n },\n body: JSON.stringify({\n flagKey,\n user: normalizedUser,\n defaultValue,\n expectedEnvKey: this.expectedEnvKey ?? undefined\n })\n })\n : await fetch(`${this.apiBaseUrl}/api/v1/eval`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n projectKey: this.projectKey,\n envKey: this.envKey,\n flagKey,\n user: normalizedUser,\n defaultValue\n })\n });\n\n if (!res.ok) return defaultValue;\n const json = (await res.json()) as { value: boolean };\n return json.value;\n }\n\n async flags(user: FeatureFlareUserPayload, defaultValue = false): Promise<Array<{ key: string; value: boolean }>> {\n if (!this.sdkKey) {\n throw new Error('FeatureFlareClient.flags requires sdkKey. Legacy projectKey mode does not support listing all flags.');\n }\n\n const normalizedUser = this.normalizeUser(user);\n const res = await fetch(`${this.apiBaseUrl}/api/v1/sdk/flags`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-featureflare-sdk-key': this.sdkKey\n },\n body: JSON.stringify({\n user: normalizedUser,\n defaultValue,\n expectedEnvKey: this.expectedEnvKey ?? undefined\n })\n });\n\n if (!res.ok) return [];\n const json = (await res.json()) as {\n flags?: Array<{ key: string; value: boolean }>;\n values?: Record<string, boolean>;\n };\n\n if (Array.isArray(json.flags)) {\n return json.flags\n .filter((entry): entry is { key: string; value: boolean } =>\n !!entry && typeof entry.key === 'string' && typeof entry.value === 'boolean'\n )\n .map((entry) => ({ key: entry.key, value: entry.value }));\n }\n\n const values = json.values ?? {};\n return Object.entries(values).map(([key, value]) => ({ key, value: Boolean(value) }));\n }\n}\n"]}
|