@featureflare/sdk-js 0.0.6 → 0.0.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @featureflare/sdk-js
2
2
 
3
- JavaScript/TypeScript SDK for ShipIt feature flags.
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 { ShipItClient } from '@featureflare/sdk-js';
20
+ import { FeatureFlareClient } from '@featureflare/sdk-js';
21
21
 
22
22
  // SDK automatically uses production API URL
23
- // Set SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY env var, or pass sdkKey explicitly
24
- const shipit = new ShipItClient({
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 shipit.bool('new-nav', { id: 'user-123' }, false);
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
- - `SHIPIT_CLIENT_KEY` - Client SDK key (for browser/mobile)
37
- - `SHIPIT_SERVER_KEY` - Server SDK key (for backend)
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 SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY from env
41
- const shipit = new ShipItClient();
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
- - **Browser**: Uses `window.location.origin` (assumes API is on same origin)
49
- - **Node.js**: Uses the production ShipIt API endpoint
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
- The API URL cannot be overridden.
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 { ShipItClient, type ShipItUserPayload } from '@featureflare/sdk-js';
65
+ import { FeatureFlareClient, type FeatureFlareUserPayload } from '@featureflare/sdk-js';
57
66
 
58
- const user: ShipItUserPayload = {
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 shipit.bool('feature-flag', user, false);
78
+ const enabled = await featureflare.bool('feature-flag', user, false);
70
79
  ```
71
80
 
72
81
  ## API Reference
73
82
 
74
- ### `ShipItClient`
83
+ ### `FeatureFlareClient`
75
84
 
76
85
  #### Constructor
77
86
 
78
87
  ```typescript
79
- new ShipItClient(options?: ShipItClientOptions)
88
+ new FeatureFlareClient(options?: FeatureFlareClientOptions)
80
89
  ```
81
90
 
82
91
  **Options:**
83
92
 
84
- - `sdkKey?: string` - SDK key (client or server). If not provided, reads from `SHIPIT_CLIENT_KEY` or `SHIPIT_SERVER_KEY` env vars.
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: ShipItUserPayload, defaultValue?: boolean): Promise<boolean>`
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 shipit.bool('new-nav', { id: 'user-123' }, false);
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 shipit.bool('flag', user, false);
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,11 @@ 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 ShipIt Console → Environments.
153
+ Get your SDK keys from your FeatureFlare Console → Environments.
154
+
155
+ ## Security: Client-side flags are not authorization
156
+
157
+ Client keys can be extracted from your frontend bundle. **Never gate truly sensitive operations solely with client-evaluated flags**—enforce authorization on your backend. Use client keys for non-sensitive UI toggles (e.g. feature visibility, A/B tests). For access control, billing gates, or data protection, always validate on the server.
127
158
 
128
159
  ## License
129
160
 
package/dist/index.cjs CHANGED
@@ -1,35 +1,54 @@
1
1
  'use strict';
2
2
 
3
3
  // src/index.ts
4
- function getApiBaseUrl() {
5
- if (typeof window !== "undefined" && typeof window.location !== "undefined") {
6
- return window.location.origin;
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 "https://shipit-api-246728836834.us-central1.run.app";
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 ShipItClient = class {
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
- this.envKey = options.envKey ?? "production";
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("ShipItClient requires either sdkKey (recommended) or projectKey (legacy). Set SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY env var, or pass sdkKey in options.");
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("ShipItClient requires user.id (or legacy user.key).");
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.ShipItClient = ShipItClient;
118
+ exports.FeatureFlareClient = FeatureFlareClient;
72
119
  //# sourceMappingURL=index.cjs.map
73
120
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export type ShipItUserPayload = {\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 ShipItUser = {\n key: string;\n email?: string;\n name?: string;\n country?: string;\n custom?: Record<string, string | number | boolean | null>;\n};\n\nfunction getApiBaseUrl(): string {\n // Browser: use current origin (assumes API is on same origin)\n if (typeof window !== 'undefined' && typeof (window as any).location !== 'undefined') {\n return (window as any).location.origin;\n }\n // Node.js: always use production API\n return 'https://shipit-api-246728836834.us-central1.run.app';\n}\n\nexport type ShipItClientOptions = {\n sdkKey?: string;\n projectKey?: string;\n envKey?: string;\n};\n\nfunction getSdkKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;\n }\n return null;\n}\n\nexport class ShipItClient {\n private readonly apiBaseUrl: string;\n private readonly sdkKey: string | null;\n private readonly projectKey: string | null;\n private readonly envKey: string;\n\n constructor(options: ShipItClientOptions = {}) {\n this.apiBaseUrl = getApiBaseUrl().replace(/\\/$/, '');\n this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();\n this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;\n this.envKey = options.envKey ?? 'production';\n\n if (!this.sdkKey && !this.projectKey) {\n throw new Error('ShipItClient requires either sdkKey (recommended) or projectKey (legacy). Set SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY env var, or pass sdkKey in options.');\n }\n }\n\n private normalizeUser(input: ShipItUserPayload): ShipItUser {\n const key = (input.id ?? input.key ?? '').trim();\n if (!key) throw new Error('ShipItClient 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: ShipItUserPayload, 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 })\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"]}
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 ShipItUserPayload = {
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 ShipItClientOptions = {
14
+ type FeatureFlareClientOptions = {
15
+ apiBaseUrl?: string;
15
16
  sdkKey?: string;
16
17
  projectKey?: string;
17
18
  envKey?: string;
18
19
  };
19
- declare class ShipItClient {
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
- constructor(options?: ShipItClientOptions);
25
+ private readonly expectedEnvKey;
26
+ constructor(options?: FeatureFlareClientOptions);
25
27
  private normalizeUser;
26
- bool(flagKey: string, user: ShipItUserPayload, defaultValue?: boolean): Promise<boolean>;
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 { ShipItClient, type ShipItClientOptions, type ShipItUserPayload };
35
+ export { FeatureFlareClient, type FeatureFlareClientOptions, type FeatureFlareUserPayload };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type ShipItUserPayload = {
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 ShipItClientOptions = {
14
+ type FeatureFlareClientOptions = {
15
+ apiBaseUrl?: string;
15
16
  sdkKey?: string;
16
17
  projectKey?: string;
17
18
  envKey?: string;
18
19
  };
19
- declare class ShipItClient {
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
- constructor(options?: ShipItClientOptions);
25
+ private readonly expectedEnvKey;
26
+ constructor(options?: FeatureFlareClientOptions);
25
27
  private normalizeUser;
26
- bool(flagKey: string, user: ShipItUserPayload, defaultValue?: boolean): Promise<boolean>;
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 { ShipItClient, type ShipItClientOptions, type ShipItUserPayload };
35
+ export { FeatureFlareClient, type FeatureFlareClientOptions, type FeatureFlareUserPayload };
package/dist/index.js CHANGED
@@ -1,33 +1,52 @@
1
1
  // src/index.ts
2
- function getApiBaseUrl() {
3
- if (typeof window !== "undefined" && typeof window.location !== "undefined") {
4
- return window.location.origin;
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 "https://shipit-api-246728836834.us-central1.run.app";
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 ShipItClient = class {
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
- this.envKey = options.envKey ?? "production";
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("ShipItClient requires either sdkKey (recommended) or projectKey (legacy). Set SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY env var, or pass sdkKey in options.");
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("ShipItClient requires user.id (or legacy user.key).");
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 { ShipItClient };
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":"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","file":"index.js","sourcesContent":["export type ShipItUserPayload = {\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 ShipItUser = {\n key: string;\n email?: string;\n name?: string;\n country?: string;\n custom?: Record<string, string | number | boolean | null>;\n};\n\nfunction getApiBaseUrl(): string {\n // Browser: use current origin (assumes API is on same origin)\n if (typeof window !== 'undefined' && typeof (window as any).location !== 'undefined') {\n return (window as any).location.origin;\n }\n // Node.js: always use production API\n return 'https://shipit-api-246728836834.us-central1.run.app';\n}\n\nexport type ShipItClientOptions = {\n sdkKey?: string;\n projectKey?: string;\n envKey?: string;\n};\n\nfunction getSdkKeyFromEnv(): string | null {\n if (typeof process !== 'undefined' && process.env) {\n return process.env.SHIPIT_CLIENT_KEY?.trim() || process.env.SHIPIT_SERVER_KEY?.trim() || null;\n }\n return null;\n}\n\nexport class ShipItClient {\n private readonly apiBaseUrl: string;\n private readonly sdkKey: string | null;\n private readonly projectKey: string | null;\n private readonly envKey: string;\n\n constructor(options: ShipItClientOptions = {}) {\n this.apiBaseUrl = getApiBaseUrl().replace(/\\/$/, '');\n this.sdkKey = options.sdkKey?.trim() || getSdkKeyFromEnv();\n this.projectKey = options.projectKey?.trim() ? options.projectKey.trim() : null;\n this.envKey = options.envKey ?? 'production';\n\n if (!this.sdkKey && !this.projectKey) {\n throw new Error('ShipItClient requires either sdkKey (recommended) or projectKey (legacy). Set SHIPIT_CLIENT_KEY or SHIPIT_SERVER_KEY env var, or pass sdkKey in options.');\n }\n }\n\n private normalizeUser(input: ShipItUserPayload): ShipItUser {\n const key = (input.id ?? input.key ?? '').trim();\n if (!key) throw new Error('ShipItClient 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: ShipItUserPayload, 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 })\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"]}
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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featureflare/sdk-js",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"