@hyphen/sdk 1.2.0 → 1.4.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 CHANGED
@@ -17,6 +17,8 @@ The Hyphen Node.js SDK is a JavaScript library that allows developers to easily
17
17
  - [Toggle API](#toggle-api)
18
18
  - [Toggle Hooks](#toggle-hooks)
19
19
  - [Toggle Error Handling](#toggle-error-handling)
20
+ - [Toggle Caching](#toggle-caching)
21
+ - [Toggle Environment Variables](#toggle-environment-variables)
20
22
  - [Toggle Self-Hosted](#toggle-self-hosted)
21
23
  - [Contributing](#contributing)
22
24
  - [Testing Your Changes](#testing-your-changes)
@@ -167,32 +169,32 @@ console.log('Boolean toggle value:', result); // true
167
169
  | *applicationId* | `string` | The application ID for your Hyphen project. You can find this in the Hyphen dashboard. |
168
170
  | *environment?* | `string` | The environment for your Hyphen project such as `production`. Default uses `process.env.NODE_ENV` |
169
171
  | *context?* | `ToggleContext` | The context object that contains the user and custom attributes. This is optional. |
170
- | *cache?* | `{ ttl: number}` | Whether to use the cache or not. |
172
+ | *caching?* | `{ ttl: number, generateCacheKeyFn: (context?: ToggleContext) => string}` | Whether to use the cache or not and a function to set the key. The `ttl` is in seconds |
171
173
 
172
174
  ## Toggle API
173
175
 
174
176
  | Method | Parameters | Description |
175
177
  |----------------|----------------|----------------|
176
178
  | *setContext* | `context: ToggleContext` | Set the context for the toggle. This is optional. |
177
- | *get<Type>* | `key: string, defaultValue: T, options?: ToggleRequestOptions` | Get the value of a toggle. This is a generic method that can be used to get any type from toggle. |
178
- | *getBoolean* | `key: string, defaultValue: boolean, options?: ToggleRequestOptions` | Get the value of a boolean toggle. |
179
- | *getNumber* | `key: string, defaultValue: number, options?: ToggleRequestOptions` | Get the value of a number toggle. |
180
- | *getString* | `key: string, defaultValue: string, options?: ToggleRequestOptions` | Get the value of a string toggle. |
181
- | *getObject<Type>* | `key: string, defaultValue: any, options?: ToggleRequestOptions` | Get the value of a object toggle. |
179
+ | *get<Type>* | `key: string, defaultValue: T, options?: ToggleGetOptions` | Get the value of a toggle. This is a generic method that can be used to get any type from toggle. |
180
+ | *getBoolean* | `key: string, defaultValue: boolean, options?: ToggleGetOptions` | Get the value of a boolean toggle. |
181
+ | *getNumber* | `key: string, defaultValue: number, options?: ToggleGetOptions` | Get the value of a number toggle. |
182
+ | *getString* | `key: string, defaultValue: string, options?: ToggleGetOptions` | Get the value of a string toggle. |
183
+ | *getObject<Type>* | `key: string, defaultValue: any, options?: ToggleGetOptions` | Get the value of a object toggle. |
182
184
 
183
185
  ## Toggle Hooks
184
186
 
185
187
  The following hooks are available for Toggle:
186
188
  | Hook | object | Description |
187
189
  |----------------|----------------|----------------|
188
- | *beforeGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleRequestOptions }` | Called before the boolean toggle is fetched. |
189
- | *afterGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleRequestOptions, result: boolean }` | Called after the boolean toggle is fetched. |
190
- | *beforeGetNumber* | `{ key: string, defaultValue:number, options?: ToggleRequestOptions }` | Called before the number toggle is fetched. |
191
- | *afterGetNumber* | `{ key: string, defaultValue:number, options?: ToggleRequestOptions, result: number }` | Called after the number toggle is fetched. |
192
- | *beforeGetString* | `{ key: string, defaultValue:string, options?: ToggleRequestOptions }` | Called before the string toggle is fetched. |
193
- | *afterGetString* | `{ key: string, defaultValue:string, options?: ToggleRequestOptions, result: string }` | Called after the string toggle is fetched. |
194
- | *beforeGetObject* | `{ key: string, defaultValue:any, options?: ToggleRequestOptions }` | Called before the object toggle is fetched. |
195
- | *afterGetObject* | `{ key: string, defaultValue:any, options?: ToggleRequestOptions, result: any }` | Called after the object toggle is fetched. |
190
+ | *beforeGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleGetOptions }` | Called before the boolean toggle is fetched. |
191
+ | *afterGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleGetOptions, result: boolean }` | Called after the boolean toggle is fetched. |
192
+ | *beforeGetNumber* | `{ key: string, defaultValue:number, options?: ToggleGetOptions }` | Called before the number toggle is fetched. |
193
+ | *afterGetNumber* | `{ key: string, defaultValue:number, options?: ToggleGetOptions, result: number }` | Called after the number toggle is fetched. |
194
+ | *beforeGetString* | `{ key: string, defaultValue:string, options?: ToggleGetOptions }` | Called before the string toggle is fetched. |
195
+ | *afterGetString* | `{ key: string, defaultValue:string, options?: ToggleGetOptions, result: string }` | Called after the string toggle is fetched. |
196
+ | *beforeGetObject* | `{ key: string, defaultValue:any, options?: ToggleGetOptions }` | Called before the object toggle is fetched. |
197
+ | *afterGetObject* | `{ key: string, defaultValue:any, options?: ToggleGetOptions, result: any }` | Called after the object toggle is fetched. |
196
198
 
197
199
  You can use the hooks to modify the request or the response. For example, you can use the `beforeGetBoolean` hook to log the request before it is sent to the server.
198
200
 
@@ -311,6 +313,100 @@ try {
311
313
  }
312
314
  ```
313
315
 
316
+ ## Toggle Caching
317
+ The SDK supports caching of toggle values to improve performance and reduce the number of requests made to the server. You can enable caching by providing a `caching` option in the constructor.
318
+
319
+ ```javascript
320
+ import { Toggle, ToggleContext } from '@hyphen/sdk';
321
+
322
+ const context: ToggleContext = {
323
+ targetingKey: 'user-123',
324
+ ipAddress: '203.0.113.42',
325
+ customAttributes: {
326
+ subscriptionLevel: 'premium',
327
+ region: 'us-east',
328
+ },
329
+ user: {
330
+ id: 'user-123',
331
+ email: 'john.doe@example.com',
332
+ name: 'John Doe',
333
+ customAttributes: {
334
+ role: 'admin',
335
+ },
336
+ },
337
+ };
338
+
339
+ const toggleOptions = {
340
+ publicApiKey: 'your_public_api_key',
341
+ applicationId: 'your_application_id',
342
+ context: context,
343
+ uris: [
344
+ 'https://your-self-hosted-horizon-url',
345
+ ],
346
+ caching: {
347
+ ttl: 60, // Cache for 60 seconds
348
+ };
349
+
350
+ const toggle = new Toggle(toggleOptions);
351
+
352
+ const result = await toggle.getBoolean('hyphen-sdk-boolean', false);
353
+ console.log('Boolean toggle value:', result); // true
354
+ ```
355
+
356
+ If you want to use a custom cache key generation function, you can provide a `generateCacheKeyFn` function in the `caching` option:
357
+
358
+ ```javascript
359
+ import { Toggle, ToggleContext } from '@hyphen/sdk';
360
+
361
+ const context: ToggleContext = {
362
+ targetingKey: 'user-123',
363
+ ipAddress: '203.0.113.42',
364
+ customAttributes: {
365
+ subscriptionLevel: 'premium',
366
+ region: 'us-east',
367
+ },
368
+ user: {
369
+ id: 'user-123',
370
+ email: 'john.doe@example.com',
371
+ name: 'John Doe',
372
+ customAttributes: {
373
+ role: 'admin',
374
+ },
375
+ },
376
+ };
377
+
378
+ const toggleOptions = {
379
+ publicApiKey: 'your_public_api_key',
380
+ applicationId: 'your_application_id',
381
+ context: context,
382
+ uris: [
383
+ 'https://your-self-hosted-horizon-url',
384
+ ],
385
+ caching: {
386
+ ttl: 60, // Cache for 60 seconds
387
+ generateCacheKeyFn: (context) => {
388
+ return `toggle-${context?.targetingKey || 'default'}-hyphen-sdk-boolean`;
389
+ },
390
+ },
391
+ };
392
+
393
+ const toggle = new Toggle(toggleOptions);
394
+
395
+ const result = await toggle.getBoolean('hyphen-sdk-boolean', false);
396
+ console.log('Boolean toggle value:', result); // true
397
+ ```
398
+
399
+ # Toggle Environment Variables
400
+
401
+ You can also use environment variables to set the `publicApiKey` and `applicationId`. This is useful for keeping your API keys secure and not hardcoding them in your code. To do this just set your `.env` file with the following variables:
402
+
403
+ ```bash
404
+ HYPHEN_PUBLIC_API_KEY=your_public_api_key
405
+ HYPHEN_APPLICATION_ID=your_application_id
406
+ ```
407
+
408
+ On initialization of the `Toggle` class, the SDK will automatically check for these environment variables and use them if they are set. If they are not set, you will need to provide them in the constructor.
409
+
314
410
  ## Toggle Self-Hosted
315
411
 
316
412
  Toggle uses [Horizon](https://hyphen.ai/horizon) to fetch the feature flags. If you are using a self-hosted version of Hyphen you can use the `uris` option in the constructor to set the url of your self-hosted version:
package/dist/index.cjs CHANGED
@@ -39,8 +39,10 @@ module.exports = __toCommonJS(index_exports);
39
39
  // src/toggle.ts
40
40
  var import_node_process = __toESM(require("process"), 1);
41
41
  var import_hookified = require("hookified");
42
+ var import_dotenv = __toESM(require("dotenv"), 1);
42
43
  var import_server_sdk = require("@openfeature/server-sdk");
43
44
  var import_openfeature_server_provider = require("@hyphen/openfeature-server-provider");
45
+ import_dotenv.default.config();
44
46
  var ToggleHooks = /* @__PURE__ */ function(ToggleHooks2) {
45
47
  ToggleHooks2["beforeGetBoolean"] = "beforeGetBoolean";
46
48
  ToggleHooks2["afterGetBoolean"] = "afterGetBoolean";
@@ -56,36 +58,40 @@ var Toggle = class extends import_hookified.Hookified {
56
58
  static {
57
59
  __name(this, "Toggle");
58
60
  }
59
- _applicationId;
60
- _publicApiKey = "";
61
+ _applicationId = import_node_process.default.env.HYPHEN_APPLICATION_ID;
62
+ _publicApiKey = import_node_process.default.env.HYPHEN_PUBLIC_API_KEY;
61
63
  _environment;
62
64
  _client;
63
65
  _context;
64
66
  _throwErrors = false;
65
67
  _uris;
68
+ _caching;
66
69
  /*
67
70
  * Create a new Toggle instance. This will create a new client and set the options.
68
71
  * @param {ToggleOptions}
69
72
  */
70
73
  constructor(options) {
71
74
  super();
72
- this._applicationId = options.applicationId;
73
- this.setPublicApiKey(options.publicApiKey);
74
- this._environment = options.environment ?? import_node_process.default.env.NODE_ENV ?? "development";
75
- this._context = options.context;
76
- this._throwErrors = options.throwErrors ?? false;
77
- this._uris = options.uris;
75
+ this._throwErrors = options?.throwErrors ?? false;
76
+ this._applicationId = options?.applicationId;
77
+ if (options?.publicApiKey) {
78
+ this.setPublicApiKey(options.publicApiKey);
79
+ }
80
+ this._environment = options?.environment ?? import_node_process.default.env.NODE_ENV ?? "development";
81
+ this._context = options?.context;
82
+ this._uris = options?.uris;
83
+ this._caching = options?.caching;
78
84
  }
79
85
  /**
80
86
  * Get the application ID
81
- * @returns {string}
87
+ * @returns {string | undefined}
82
88
  */
83
89
  get applicationId() {
84
90
  return this._applicationId;
85
91
  }
86
92
  /**
87
93
  * Set the application ID
88
- * @param {string} value
94
+ * @param {string | undefined} value
89
95
  */
90
96
  set applicationId(value) {
91
97
  this._applicationId = value;
@@ -102,6 +108,11 @@ var Toggle = class extends import_hookified.Hookified {
102
108
  * @param {string} value
103
109
  */
104
110
  set publicApiKey(value) {
111
+ if (!value) {
112
+ this._publicApiKey = void 0;
113
+ this._client = void 0;
114
+ return;
115
+ }
105
116
  this.setPublicApiKey(value);
106
117
  }
107
118
  /**
@@ -161,11 +172,25 @@ var Toggle = class extends import_hookified.Hookified {
161
172
  this._uris = value;
162
173
  }
163
174
  /**
175
+ * Get the caching options.
176
+ * @returns {ToggleCachingOptions | undefined}
177
+ */
178
+ get caching() {
179
+ return this._caching;
180
+ }
181
+ /**
182
+ * Set the caching options.
183
+ * @param {ToggleCachingOptions | undefined} value
184
+ */
185
+ set caching(value) {
186
+ this._caching = value;
187
+ }
188
+ /**
164
189
  * This is a helper function to set the public API key. It will check if the key starts with public_ and set it. If it
165
- * does set it will also set the client to undefined to force a new one to be created. If it does not,
190
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
166
191
  * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
167
- * @param key
168
- * @returns
192
+ * @param key
193
+ * @returns
169
194
  */
170
195
  setPublicApiKey(key) {
171
196
  if (!key.startsWith("public_")) {
@@ -194,12 +219,28 @@ var Toggle = class extends import_hookified.Hookified {
194
219
  */
195
220
  async getClient() {
196
221
  if (!this._client) {
222
+ console.log("Application ID:", this._applicationId);
223
+ if (this._applicationId === void 0 || this._applicationId.length === 0) {
224
+ const errorMessage = "Application ID is not set. You must set it before using the client or have the HYPHEN_APPLICATION_ID environment variable set.";
225
+ this.emit("error", new Error(errorMessage));
226
+ if (this._throwErrors) {
227
+ throw new Error(errorMessage);
228
+ }
229
+ }
197
230
  const options = {
198
231
  application: this._applicationId,
199
232
  environment: this._environment,
200
- horizonUrls: this._uris
233
+ horizonUrls: this._uris,
234
+ cache: this._caching
201
235
  };
202
- await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicApiKey, options));
236
+ if (this._publicApiKey && this._publicApiKey.length > 0) {
237
+ await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicApiKey, options));
238
+ } else {
239
+ this.emit("error", new Error("Public API key is not set. You must set it before using the client or have the HYPHEN_PUBLIC_API_KEY environment variable set."));
240
+ if (this._throwErrors) {
241
+ throw new Error("Public API key is not set");
242
+ }
243
+ }
203
244
  this._client = import_server_sdk.OpenFeature.getClient(this._context);
204
245
  }
205
246
  return this._client;
package/dist/index.d.cts CHANGED
@@ -12,17 +12,21 @@ declare enum ToggleHooks {
12
12
  beforeGetObject = "beforeGetObject",
13
13
  afterGetObject = "afterGetObject"
14
14
  }
15
+ type ToggleCachingOptions = {
16
+ ttl?: number;
17
+ generateCacheKeyFn?: (context?: ToggleContext) => string;
18
+ };
15
19
  type ToggleOptions = {
16
20
  /**
17
- * Your application name
21
+ * Your application name. If this is not set it will look for the HYPHEN_APPLICATION_ID environment variable.
18
22
  * @type {string}
19
23
  */
20
- applicationId: string;
24
+ applicationId?: string;
21
25
  /**
22
- * Your Hyphen Public API key
26
+ * Your Hyphen Public API key. If this is not set it will look for the HYPHEN_PUBLIC_API_KEY environment variable.
23
27
  * @type {string}
24
28
  */
25
- publicApiKey: string;
29
+ publicApiKey?: string;
26
30
  /**
27
31
  * Your environment name such as development, production. Default is what is set at NODE_ENV
28
32
  * @type {string}
@@ -34,13 +38,11 @@ type ToggleOptions = {
34
38
  * @type {ToggleContext}
35
39
  */
36
40
  context?: ToggleContext;
37
- caching?: {
38
- /**
39
- * The time in seconds to cache the feature flag values
40
- * @type {number} - this is in milliseconds
41
- */
42
- ttl?: number;
43
- };
41
+ /**
42
+ * Cache options to use for the request
43
+ * @type {ToggleCachingOptions}
44
+ */
45
+ caching?: ToggleCachingOptions;
44
46
  /**
45
47
  * Throw errors in addition to emitting them
46
48
  * @type {boolean}
@@ -55,7 +57,7 @@ type ToggleOptions = {
55
57
  */
56
58
  uris?: string[];
57
59
  };
58
- type ToggleRequestOptions = {
60
+ type ToggleGetOptions = {
59
61
  /**
60
62
  * The context to use for evaluating feature flags
61
63
  * @type {ToggleContext}
@@ -69,28 +71,29 @@ declare class Toggle extends Hookified {
69
71
  private _client;
70
72
  private _context;
71
73
  private _throwErrors;
72
- private _uris?;
73
- constructor(options: ToggleOptions);
74
+ private _uris;
75
+ private _caching;
76
+ constructor(options?: ToggleOptions);
74
77
  /**
75
78
  * Get the application ID
76
- * @returns {string}
79
+ * @returns {string | undefined}
77
80
  */
78
- get applicationId(): string;
81
+ get applicationId(): string | undefined;
79
82
  /**
80
83
  * Set the application ID
81
- * @param {string} value
84
+ * @param {string | undefined} value
82
85
  */
83
- set applicationId(value: string);
86
+ set applicationId(value: string | undefined);
84
87
  /**
85
88
  * Get the public API key
86
89
  * @returns {string}
87
90
  */
88
- get publicApiKey(): string;
91
+ get publicApiKey(): string | undefined;
89
92
  /**
90
93
  * Set the public API key
91
94
  * @param {string} value
92
95
  */
93
- set publicApiKey(value: string);
96
+ set publicApiKey(value: string | undefined);
94
97
  /**
95
98
  * Get the environment
96
99
  * @returns {string}
@@ -131,6 +134,16 @@ declare class Toggle extends Hookified {
131
134
  * @param {Array<string>} value
132
135
  */
133
136
  set uris(value: string[] | undefined);
137
+ /**
138
+ * Get the caching options.
139
+ * @returns {ToggleCachingOptions | undefined}
140
+ */
141
+ get caching(): ToggleCachingOptions | undefined;
142
+ /**
143
+ * Set the caching options.
144
+ * @param {ToggleCachingOptions | undefined} value
145
+ */
146
+ set caching(value: ToggleCachingOptions | undefined);
134
147
  /**
135
148
  * This is a helper function to set the public API key. It will check if the key starts with public_ and set it. If it
136
149
  * does set it will also set the client to undefined to force a new one to be created. If it does not,
@@ -159,7 +172,7 @@ declare class Toggle extends Hookified {
159
172
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
160
173
  * @returns {Promise<T>}
161
174
  */
162
- get<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
175
+ get<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
163
176
  /**
164
177
  * Get a boolean value from the feature flag. This will check the type of the default value and call the
165
178
  * appropriate function. It will also set the context if it is not set.
@@ -168,7 +181,7 @@ declare class Toggle extends Hookified {
168
181
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
169
182
  * @returns {Promise<boolean>} - The value of the feature flag
170
183
  */
171
- getBoolean(key: string, defaultValue: boolean, options?: ToggleRequestOptions): Promise<boolean>;
184
+ getBoolean(key: string, defaultValue: boolean, options?: ToggleGetOptions): Promise<boolean>;
172
185
  /**
173
186
  * Get a string value from the feature flag.
174
187
  * @param {string} key - The key of the feature flag
@@ -176,8 +189,8 @@ declare class Toggle extends Hookified {
176
189
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
177
190
  * @returns {Promise<string>} - The value of the feature flag
178
191
  */
179
- getString(key: string, defaultValue: string, options?: ToggleRequestOptions): Promise<string>;
180
- getNumber(key: string, defaultValue: number, options?: ToggleRequestOptions): Promise<number>;
192
+ getString(key: string, defaultValue: string, options?: ToggleGetOptions): Promise<string>;
193
+ getNumber(key: string, defaultValue: number, options?: ToggleGetOptions): Promise<number>;
181
194
  /**
182
195
  * Get an object value from the feature flag. This will check the type of the default value and call the
183
196
  * appropriate function. It will also set the context if it is not set.
@@ -186,7 +199,7 @@ declare class Toggle extends Hookified {
186
199
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
187
200
  * @returns {Promise<T>} - The value of the feature flag
188
201
  */
189
- getObject<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
202
+ getObject<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
190
203
  }
191
204
 
192
- export { Toggle, type ToggleContext, ToggleHooks, type ToggleOptions, type ToggleRequestOptions };
205
+ export { Toggle, type ToggleCachingOptions, type ToggleContext, type ToggleGetOptions, ToggleHooks, type ToggleOptions };
package/dist/index.d.ts CHANGED
@@ -12,17 +12,21 @@ declare enum ToggleHooks {
12
12
  beforeGetObject = "beforeGetObject",
13
13
  afterGetObject = "afterGetObject"
14
14
  }
15
+ type ToggleCachingOptions = {
16
+ ttl?: number;
17
+ generateCacheKeyFn?: (context?: ToggleContext) => string;
18
+ };
15
19
  type ToggleOptions = {
16
20
  /**
17
- * Your application name
21
+ * Your application name. If this is not set it will look for the HYPHEN_APPLICATION_ID environment variable.
18
22
  * @type {string}
19
23
  */
20
- applicationId: string;
24
+ applicationId?: string;
21
25
  /**
22
- * Your Hyphen Public API key
26
+ * Your Hyphen Public API key. If this is not set it will look for the HYPHEN_PUBLIC_API_KEY environment variable.
23
27
  * @type {string}
24
28
  */
25
- publicApiKey: string;
29
+ publicApiKey?: string;
26
30
  /**
27
31
  * Your environment name such as development, production. Default is what is set at NODE_ENV
28
32
  * @type {string}
@@ -34,13 +38,11 @@ type ToggleOptions = {
34
38
  * @type {ToggleContext}
35
39
  */
36
40
  context?: ToggleContext;
37
- caching?: {
38
- /**
39
- * The time in seconds to cache the feature flag values
40
- * @type {number} - this is in milliseconds
41
- */
42
- ttl?: number;
43
- };
41
+ /**
42
+ * Cache options to use for the request
43
+ * @type {ToggleCachingOptions}
44
+ */
45
+ caching?: ToggleCachingOptions;
44
46
  /**
45
47
  * Throw errors in addition to emitting them
46
48
  * @type {boolean}
@@ -55,7 +57,7 @@ type ToggleOptions = {
55
57
  */
56
58
  uris?: string[];
57
59
  };
58
- type ToggleRequestOptions = {
60
+ type ToggleGetOptions = {
59
61
  /**
60
62
  * The context to use for evaluating feature flags
61
63
  * @type {ToggleContext}
@@ -69,28 +71,29 @@ declare class Toggle extends Hookified {
69
71
  private _client;
70
72
  private _context;
71
73
  private _throwErrors;
72
- private _uris?;
73
- constructor(options: ToggleOptions);
74
+ private _uris;
75
+ private _caching;
76
+ constructor(options?: ToggleOptions);
74
77
  /**
75
78
  * Get the application ID
76
- * @returns {string}
79
+ * @returns {string | undefined}
77
80
  */
78
- get applicationId(): string;
81
+ get applicationId(): string | undefined;
79
82
  /**
80
83
  * Set the application ID
81
- * @param {string} value
84
+ * @param {string | undefined} value
82
85
  */
83
- set applicationId(value: string);
86
+ set applicationId(value: string | undefined);
84
87
  /**
85
88
  * Get the public API key
86
89
  * @returns {string}
87
90
  */
88
- get publicApiKey(): string;
91
+ get publicApiKey(): string | undefined;
89
92
  /**
90
93
  * Set the public API key
91
94
  * @param {string} value
92
95
  */
93
- set publicApiKey(value: string);
96
+ set publicApiKey(value: string | undefined);
94
97
  /**
95
98
  * Get the environment
96
99
  * @returns {string}
@@ -131,6 +134,16 @@ declare class Toggle extends Hookified {
131
134
  * @param {Array<string>} value
132
135
  */
133
136
  set uris(value: string[] | undefined);
137
+ /**
138
+ * Get the caching options.
139
+ * @returns {ToggleCachingOptions | undefined}
140
+ */
141
+ get caching(): ToggleCachingOptions | undefined;
142
+ /**
143
+ * Set the caching options.
144
+ * @param {ToggleCachingOptions | undefined} value
145
+ */
146
+ set caching(value: ToggleCachingOptions | undefined);
134
147
  /**
135
148
  * This is a helper function to set the public API key. It will check if the key starts with public_ and set it. If it
136
149
  * does set it will also set the client to undefined to force a new one to be created. If it does not,
@@ -159,7 +172,7 @@ declare class Toggle extends Hookified {
159
172
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
160
173
  * @returns {Promise<T>}
161
174
  */
162
- get<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
175
+ get<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
163
176
  /**
164
177
  * Get a boolean value from the feature flag. This will check the type of the default value and call the
165
178
  * appropriate function. It will also set the context if it is not set.
@@ -168,7 +181,7 @@ declare class Toggle extends Hookified {
168
181
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
169
182
  * @returns {Promise<boolean>} - The value of the feature flag
170
183
  */
171
- getBoolean(key: string, defaultValue: boolean, options?: ToggleRequestOptions): Promise<boolean>;
184
+ getBoolean(key: string, defaultValue: boolean, options?: ToggleGetOptions): Promise<boolean>;
172
185
  /**
173
186
  * Get a string value from the feature flag.
174
187
  * @param {string} key - The key of the feature flag
@@ -176,8 +189,8 @@ declare class Toggle extends Hookified {
176
189
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
177
190
  * @returns {Promise<string>} - The value of the feature flag
178
191
  */
179
- getString(key: string, defaultValue: string, options?: ToggleRequestOptions): Promise<string>;
180
- getNumber(key: string, defaultValue: number, options?: ToggleRequestOptions): Promise<number>;
192
+ getString(key: string, defaultValue: string, options?: ToggleGetOptions): Promise<string>;
193
+ getNumber(key: string, defaultValue: number, options?: ToggleGetOptions): Promise<number>;
181
194
  /**
182
195
  * Get an object value from the feature flag. This will check the type of the default value and call the
183
196
  * appropriate function. It will also set the context if it is not set.
@@ -186,7 +199,7 @@ declare class Toggle extends Hookified {
186
199
  * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
187
200
  * @returns {Promise<T>} - The value of the feature flag
188
201
  */
189
- getObject<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
202
+ getObject<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
190
203
  }
191
204
 
192
- export { Toggle, type ToggleContext, ToggleHooks, type ToggleOptions, type ToggleRequestOptions };
205
+ export { Toggle, type ToggleCachingOptions, type ToggleContext, type ToggleGetOptions, ToggleHooks, type ToggleOptions };
package/dist/index.js CHANGED
@@ -4,8 +4,10 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
4
4
  // src/toggle.ts
5
5
  import process from "process";
6
6
  import { Hookified } from "hookified";
7
+ import dotenv from "dotenv";
7
8
  import { OpenFeature } from "@openfeature/server-sdk";
8
9
  import { HyphenProvider } from "@hyphen/openfeature-server-provider";
10
+ dotenv.config();
9
11
  var ToggleHooks = /* @__PURE__ */ function(ToggleHooks2) {
10
12
  ToggleHooks2["beforeGetBoolean"] = "beforeGetBoolean";
11
13
  ToggleHooks2["afterGetBoolean"] = "afterGetBoolean";
@@ -21,36 +23,40 @@ var Toggle = class extends Hookified {
21
23
  static {
22
24
  __name(this, "Toggle");
23
25
  }
24
- _applicationId;
25
- _publicApiKey = "";
26
+ _applicationId = process.env.HYPHEN_APPLICATION_ID;
27
+ _publicApiKey = process.env.HYPHEN_PUBLIC_API_KEY;
26
28
  _environment;
27
29
  _client;
28
30
  _context;
29
31
  _throwErrors = false;
30
32
  _uris;
33
+ _caching;
31
34
  /*
32
35
  * Create a new Toggle instance. This will create a new client and set the options.
33
36
  * @param {ToggleOptions}
34
37
  */
35
38
  constructor(options) {
36
39
  super();
37
- this._applicationId = options.applicationId;
38
- this.setPublicApiKey(options.publicApiKey);
39
- this._environment = options.environment ?? process.env.NODE_ENV ?? "development";
40
- this._context = options.context;
41
- this._throwErrors = options.throwErrors ?? false;
42
- this._uris = options.uris;
40
+ this._throwErrors = options?.throwErrors ?? false;
41
+ this._applicationId = options?.applicationId;
42
+ if (options?.publicApiKey) {
43
+ this.setPublicApiKey(options.publicApiKey);
44
+ }
45
+ this._environment = options?.environment ?? process.env.NODE_ENV ?? "development";
46
+ this._context = options?.context;
47
+ this._uris = options?.uris;
48
+ this._caching = options?.caching;
43
49
  }
44
50
  /**
45
51
  * Get the application ID
46
- * @returns {string}
52
+ * @returns {string | undefined}
47
53
  */
48
54
  get applicationId() {
49
55
  return this._applicationId;
50
56
  }
51
57
  /**
52
58
  * Set the application ID
53
- * @param {string} value
59
+ * @param {string | undefined} value
54
60
  */
55
61
  set applicationId(value) {
56
62
  this._applicationId = value;
@@ -67,6 +73,11 @@ var Toggle = class extends Hookified {
67
73
  * @param {string} value
68
74
  */
69
75
  set publicApiKey(value) {
76
+ if (!value) {
77
+ this._publicApiKey = void 0;
78
+ this._client = void 0;
79
+ return;
80
+ }
70
81
  this.setPublicApiKey(value);
71
82
  }
72
83
  /**
@@ -126,11 +137,25 @@ var Toggle = class extends Hookified {
126
137
  this._uris = value;
127
138
  }
128
139
  /**
140
+ * Get the caching options.
141
+ * @returns {ToggleCachingOptions | undefined}
142
+ */
143
+ get caching() {
144
+ return this._caching;
145
+ }
146
+ /**
147
+ * Set the caching options.
148
+ * @param {ToggleCachingOptions | undefined} value
149
+ */
150
+ set caching(value) {
151
+ this._caching = value;
152
+ }
153
+ /**
129
154
  * This is a helper function to set the public API key. It will check if the key starts with public_ and set it. If it
130
- * does set it will also set the client to undefined to force a new one to be created. If it does not,
155
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
131
156
  * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
132
- * @param key
133
- * @returns
157
+ * @param key
158
+ * @returns
134
159
  */
135
160
  setPublicApiKey(key) {
136
161
  if (!key.startsWith("public_")) {
@@ -159,12 +184,28 @@ var Toggle = class extends Hookified {
159
184
  */
160
185
  async getClient() {
161
186
  if (!this._client) {
187
+ console.log("Application ID:", this._applicationId);
188
+ if (this._applicationId === void 0 || this._applicationId.length === 0) {
189
+ const errorMessage = "Application ID is not set. You must set it before using the client or have the HYPHEN_APPLICATION_ID environment variable set.";
190
+ this.emit("error", new Error(errorMessage));
191
+ if (this._throwErrors) {
192
+ throw new Error(errorMessage);
193
+ }
194
+ }
162
195
  const options = {
163
196
  application: this._applicationId,
164
197
  environment: this._environment,
165
- horizonUrls: this._uris
198
+ horizonUrls: this._uris,
199
+ cache: this._caching
166
200
  };
167
- await OpenFeature.setProviderAndWait(new HyphenProvider(this._publicApiKey, options));
201
+ if (this._publicApiKey && this._publicApiKey.length > 0) {
202
+ await OpenFeature.setProviderAndWait(new HyphenProvider(this._publicApiKey, options));
203
+ } else {
204
+ this.emit("error", new Error("Public API key is not set. You must set it before using the client or have the HYPHEN_PUBLIC_API_KEY environment variable set."));
205
+ if (this._throwErrors) {
206
+ throw new Error("Public API key is not set");
207
+ }
208
+ }
168
209
  this._client = OpenFeature.getClient(this._context);
169
210
  }
170
211
  return this._client;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyphen/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Hyphen SDK for Node.js",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -11,12 +11,12 @@
11
11
  "require": "./dist/index.cjs"
12
12
  }
13
13
  },
14
- "types": "dist/node/index.d.ts",
14
+ "types": "dist/index.d.ts",
15
15
  "scripts": {
16
16
  "test": "xo --fix && vitest run --coverage",
17
17
  "test:ci": "xo && vitest run --coverage",
18
18
  "build": "rimraf ./dist && tsup src/index.ts --format esm,cjs --dts --clean",
19
- "clean": "rimraf ./dist",
19
+ "clean": "rimraf ./dist pnpm-lock.yaml node_modules coverage",
20
20
  "prepublishOnly": "rimraf ./dist && tsup src/index.ts --format esm,cjs --dts --clean"
21
21
  },
22
22
  "keywords": [
@@ -29,15 +29,15 @@
29
29
  "author": "Team Hyphen <hello@hyphen.ai>",
30
30
  "license": "MIT",
31
31
  "devDependencies": {
32
- "@swc/core": "^1.11.24",
33
- "@types/node": "^22.15.17",
34
- "@vitest/coverage-v8": "^3.1.3",
32
+ "@swc/core": "^1.11.29",
33
+ "@types/node": "^22.15.21",
34
+ "@vitest/coverage-v8": "^3.1.4",
35
35
  "rimraf": "^6.0.1",
36
36
  "tsd": "^0.32.0",
37
- "tsup": "^8.4.0",
37
+ "tsup": "^8.5.0",
38
38
  "typescript": "^5.8.3",
39
- "vitest": "^3.1.3",
40
- "xo": "^0.60.0"
39
+ "vitest": "^3.1.4",
40
+ "xo": "^1.0.0"
41
41
  },
42
42
  "files": [
43
43
  "dist",