@hyphen/sdk 1.1.0 → 1.3.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
@@ -10,7 +10,6 @@
10
10
  The Hyphen Node.js SDK is a JavaScript library that allows developers to easily integrate Hyphen's feature flagging and experimentation capabilities into their Node.js applications. With this SDK, you can manage feature flags more effectively, enabling you to control the rollout of new features and conduct A/B testing with ease.
11
11
 
12
12
  # Table of Contents
13
- - [Hyphen Node.js SDK](#hyphen-nodejs-sdk)
14
13
  - [Installation](#installation)
15
14
  - [Basic Usage](#basic-usage)
16
15
  - [Toggle](#toggle)
@@ -18,6 +17,7 @@ The Hyphen Node.js SDK is a JavaScript library that allows developers to easily
18
17
  - [Toggle API](#toggle-api)
19
18
  - [Toggle Hooks](#toggle-hooks)
20
19
  - [Toggle Error Handling](#toggle-error-handling)
20
+ - [Toggle Caching](#toggle-caching)
21
21
  - [Toggle Self-Hosted](#toggle-self-hosted)
22
22
  - [Contributing](#contributing)
23
23
  - [Testing Your Changes](#testing-your-changes)
@@ -168,32 +168,32 @@ console.log('Boolean toggle value:', result); // true
168
168
  | *applicationId* | `string` | The application ID for your Hyphen project. You can find this in the Hyphen dashboard. |
169
169
  | *environment?* | `string` | The environment for your Hyphen project such as `production`. Default uses `process.env.NODE_ENV` |
170
170
  | *context?* | `ToggleContext` | The context object that contains the user and custom attributes. This is optional. |
171
- | *cache?* | `{ ttl: number}` | Whether to use the cache or not. |
171
+ | *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 |
172
172
 
173
173
  ## Toggle API
174
174
 
175
175
  | Method | Parameters | Description |
176
176
  |----------------|----------------|----------------|
177
177
  | *setContext* | `context: ToggleContext` | Set the context for the toggle. This is optional. |
178
- | *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. |
179
- | *getBoolean* | `key: string, defaultValue: boolean, options?: ToggleRequestOptions` | Get the value of a boolean toggle. |
180
- | *getNumber* | `key: string, defaultValue: number, options?: ToggleRequestOptions` | Get the value of a number toggle. |
181
- | *getString* | `key: string, defaultValue: string, options?: ToggleRequestOptions` | Get the value of a string toggle. |
182
- | *getObject<Type>* | `key: string, defaultValue: any, options?: ToggleRequestOptions` | Get the value of a object toggle. |
178
+ | *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. |
179
+ | *getBoolean* | `key: string, defaultValue: boolean, options?: ToggleGetOptions` | Get the value of a boolean toggle. |
180
+ | *getNumber* | `key: string, defaultValue: number, options?: ToggleGetOptions` | Get the value of a number toggle. |
181
+ | *getString* | `key: string, defaultValue: string, options?: ToggleGetOptions` | Get the value of a string toggle. |
182
+ | *getObject<Type>* | `key: string, defaultValue: any, options?: ToggleGetOptions` | Get the value of a object toggle. |
183
183
 
184
184
  ## Toggle Hooks
185
185
 
186
186
  The following hooks are available for Toggle:
187
187
  | Hook | object | Description |
188
188
  |----------------|----------------|----------------|
189
- | *beforeGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleRequestOptions }` | Called before the boolean toggle is fetched. |
190
- | *afterGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleRequestOptions, result: boolean }` | Called after the boolean toggle is fetched. |
191
- | *beforeGetNumber* | `{ key: string, defaultValue:number, options?: ToggleRequestOptions }` | Called before the number toggle is fetched. |
192
- | *afterGetNumber* | `{ key: string, defaultValue:number, options?: ToggleRequestOptions, result: number }` | Called after the number toggle is fetched. |
193
- | *beforeGetString* | `{ key: string, defaultValue:string, options?: ToggleRequestOptions }` | Called before the string toggle is fetched. |
194
- | *afterGetString* | `{ key: string, defaultValue:string, options?: ToggleRequestOptions, result: string }` | Called after the string toggle is fetched. |
195
- | *beforeGetObject* | `{ key: string, defaultValue:any, options?: ToggleRequestOptions }` | Called before the object toggle is fetched. |
196
- | *afterGetObject* | `{ key: string, defaultValue:any, options?: ToggleRequestOptions, result: any }` | Called after the object toggle is fetched. |
189
+ | *beforeGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleGetOptions }` | Called before the boolean toggle is fetched. |
190
+ | *afterGetBoolean* | `{ key: string, defaultValue:boolean, options?: ToggleGetOptions, result: boolean }` | Called after the boolean toggle is fetched. |
191
+ | *beforeGetNumber* | `{ key: string, defaultValue:number, options?: ToggleGetOptions }` | Called before the number toggle is fetched. |
192
+ | *afterGetNumber* | `{ key: string, defaultValue:number, options?: ToggleGetOptions, result: number }` | Called after the number toggle is fetched. |
193
+ | *beforeGetString* | `{ key: string, defaultValue:string, options?: ToggleGetOptions }` | Called before the string toggle is fetched. |
194
+ | *afterGetString* | `{ key: string, defaultValue:string, options?: ToggleGetOptions, result: string }` | Called after the string toggle is fetched. |
195
+ | *beforeGetObject* | `{ key: string, defaultValue:any, options?: ToggleGetOptions }` | Called before the object toggle is fetched. |
196
+ | *afterGetObject* | `{ key: string, defaultValue:any, options?: ToggleGetOptions, result: any }` | Called after the object toggle is fetched. |
197
197
 
198
198
  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.
199
199
 
@@ -312,6 +312,89 @@ try {
312
312
  }
313
313
  ```
314
314
 
315
+ ## Toggle Caching
316
+ 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.
317
+
318
+ ```javascript
319
+ import { Toggle, ToggleContext } from '@hyphen/sdk';
320
+
321
+ const context: ToggleContext = {
322
+ targetingKey: 'user-123',
323
+ ipAddress: '203.0.113.42',
324
+ customAttributes: {
325
+ subscriptionLevel: 'premium',
326
+ region: 'us-east',
327
+ },
328
+ user: {
329
+ id: 'user-123',
330
+ email: 'john.doe@example.com',
331
+ name: 'John Doe',
332
+ customAttributes: {
333
+ role: 'admin',
334
+ },
335
+ },
336
+ };
337
+
338
+ const toggleOptions = {
339
+ publicApiKey: 'your_public_api_key',
340
+ applicationId: 'your_application_id',
341
+ context: context,
342
+ uris: [
343
+ 'https://your-self-hosted-horizon-url',
344
+ ],
345
+ caching: {
346
+ ttl: 60, // Cache for 60 seconds
347
+ };
348
+
349
+ const toggle = new Toggle(toggleOptions);
350
+
351
+ const result = await toggle.getBoolean('hyphen-sdk-boolean', false);
352
+ console.log('Boolean toggle value:', result); // true
353
+ ```
354
+
355
+ If you want to use a custom cache key generation function, you can provide a `generateCacheKeyFn` function in the `caching` option:
356
+
357
+ ```javascript
358
+ import { Toggle, ToggleContext } from '@hyphen/sdk';
359
+
360
+ const context: ToggleContext = {
361
+ targetingKey: 'user-123',
362
+ ipAddress: '203.0.113.42',
363
+ customAttributes: {
364
+ subscriptionLevel: 'premium',
365
+ region: 'us-east',
366
+ },
367
+ user: {
368
+ id: 'user-123',
369
+ email: 'john.doe@example.com',
370
+ name: 'John Doe',
371
+ customAttributes: {
372
+ role: 'admin',
373
+ },
374
+ },
375
+ };
376
+
377
+ const toggleOptions = {
378
+ publicApiKey: 'your_public_api_key',
379
+ applicationId: 'your_application_id',
380
+ context: context,
381
+ uris: [
382
+ 'https://your-self-hosted-horizon-url',
383
+ ],
384
+ caching: {
385
+ ttl: 60, // Cache for 60 seconds
386
+ generateCacheKeyFn: (context) => {
387
+ return `toggle-${context?.targetingKey || 'default'}-hyphen-sdk-boolean`;
388
+ },
389
+ },
390
+ };
391
+
392
+ const toggle = new Toggle(toggleOptions);
393
+
394
+ const result = await toggle.getBoolean('hyphen-sdk-boolean', false);
395
+ console.log('Boolean toggle value:', result); // true
396
+ ```
397
+
315
398
  ## Toggle Self-Hosted
316
399
 
317
400
  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
@@ -57,73 +57,178 @@ var Toggle = class extends import_hookified.Hookified {
57
57
  __name(this, "Toggle");
58
58
  }
59
59
  _applicationId;
60
- _publicKey;
60
+ _publicApiKey = "";
61
61
  _environment;
62
62
  _client;
63
63
  _context;
64
64
  _throwErrors = false;
65
65
  _uris;
66
+ _caching;
67
+ /*
68
+ * Create a new Toggle instance. This will create a new client and set the options.
69
+ * @param {ToggleOptions}
70
+ */
66
71
  constructor(options) {
67
72
  super();
68
73
  this._applicationId = options.applicationId;
69
- this._publicKey = options.publicKey;
74
+ this.setPublicApiKey(options.publicApiKey);
70
75
  this._environment = options.environment ?? import_node_process.default.env.NODE_ENV ?? "development";
71
76
  this._context = options.context;
72
77
  this._throwErrors = options.throwErrors ?? false;
73
78
  this._uris = options.uris;
79
+ this._caching = options.caching;
74
80
  }
81
+ /**
82
+ * Get the application ID
83
+ * @returns {string}
84
+ */
75
85
  get applicationId() {
76
86
  return this._applicationId;
77
87
  }
88
+ /**
89
+ * Set the application ID
90
+ * @param {string} value
91
+ */
78
92
  set applicationId(value) {
79
93
  this._applicationId = value;
80
94
  }
81
- get publicKey() {
82
- return this._publicKey;
95
+ /**
96
+ * Get the public API key
97
+ * @returns {string}
98
+ */
99
+ get publicApiKey() {
100
+ return this._publicApiKey;
83
101
  }
84
- set publicKey(value) {
85
- this._publicKey = value;
102
+ /**
103
+ * Set the public API key
104
+ * @param {string} value
105
+ */
106
+ set publicApiKey(value) {
107
+ this.setPublicApiKey(value);
86
108
  }
109
+ /**
110
+ * Get the environment
111
+ * @returns {string}
112
+ */
87
113
  get environment() {
88
114
  return this._environment;
89
115
  }
116
+ /**
117
+ * Set the environment
118
+ * @param {string} value
119
+ */
90
120
  set environment(value) {
91
121
  this._environment = value;
92
122
  }
123
+ /**
124
+ * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
125
+ * @returns {boolean}
126
+ */
93
127
  get throwErrors() {
94
128
  return this._throwErrors;
95
129
  }
130
+ /**
131
+ * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
132
+ * @param {boolean} value
133
+ */
96
134
  set throwErrors(value) {
97
135
  this._throwErrors = value;
98
136
  }
137
+ /**
138
+ * Get the current context. This is the default context used. You can override this at the get function level.
139
+ * @returns {ToggleContext}
140
+ */
99
141
  get context() {
100
142
  return this._context;
101
143
  }
144
+ /**
145
+ * Set the context. This is the default context used. You can override this at the get function level.
146
+ * @param {ToggleContext} value
147
+ */
102
148
  set context(value) {
103
149
  this._context = value;
104
150
  }
151
+ /**
152
+ * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
153
+ * @returns {Array<string>}
154
+ */
105
155
  get uris() {
106
156
  return this._uris;
107
157
  }
158
+ /**
159
+ * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
160
+ * @param {Array<string>} value
161
+ */
108
162
  set uris(value) {
109
163
  this._uris = value;
110
164
  }
165
+ /**
166
+ * Get the caching options.
167
+ * @returns {ToggleCachingOptions | undefined}
168
+ */
169
+ get caching() {
170
+ return this._caching;
171
+ }
172
+ /**
173
+ * Set the caching options.
174
+ * @param {ToggleCachingOptions | undefined} value
175
+ */
176
+ set caching(value) {
177
+ this._caching = value;
178
+ }
179
+ /**
180
+ * 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
181
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
182
+ * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
183
+ * @param key
184
+ * @returns
185
+ */
186
+ setPublicApiKey(key) {
187
+ if (!key.startsWith("public_")) {
188
+ this.emit("error", new Error("Public API key should start with public_"));
189
+ if (import_node_process.default.env.NODE_ENV !== "production") {
190
+ console.error("Public API key should start with public_");
191
+ }
192
+ return;
193
+ }
194
+ this._publicApiKey = key;
195
+ this._client = void 0;
196
+ }
197
+ /**
198
+ * Set the context. This is the default context used. You can override this at the get function level.
199
+ * @param {ToggleContext} context
200
+ */
111
201
  setContext(context) {
112
202
  this._context = context;
113
203
  this._client = void 0;
114
204
  }
205
+ /**
206
+ * Helper function to get the client. This will create a new client if one does not exist. It will also set the
207
+ * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
208
+ * This is normally only used internally.
209
+ * @returns {Promise<Client>}
210
+ */
115
211
  async getClient() {
116
212
  if (!this._client) {
117
213
  const options = {
118
214
  application: this._applicationId,
119
215
  environment: this._environment,
120
- horizonUrls: this._uris
216
+ horizonUrls: this._uris,
217
+ cache: this._caching
121
218
  };
122
- await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicKey, options));
219
+ await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicApiKey, options));
123
220
  this._client = import_server_sdk.OpenFeature.getClient(this._context);
124
221
  }
125
222
  return this._client;
126
223
  }
224
+ /**
225
+ * This is the main function to get a feature flag value. It will check the type of the default value and call the
226
+ * appropriate function. It will also set the context if it is not set.
227
+ * @param {string} key - The key of the feature flag
228
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
229
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
230
+ * @returns {Promise<T>}
231
+ */
127
232
  async get(key, defaultValue, options) {
128
233
  switch (typeof defaultValue) {
129
234
  case "boolean": {
@@ -140,6 +245,14 @@ var Toggle = class extends import_hookified.Hookified {
140
245
  }
141
246
  }
142
247
  }
248
+ /**
249
+ * Get a boolean value from the feature flag. This will check the type of the default value and call the
250
+ * appropriate function. It will also set the context if it is not set.
251
+ * @param {string} key - The key of the feature flag
252
+ * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
253
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
254
+ * @returns {Promise<boolean>} - The value of the feature flag
255
+ */
143
256
  async getBoolean(key, defaultValue, options) {
144
257
  try {
145
258
  const data = {
@@ -166,6 +279,13 @@ var Toggle = class extends import_hookified.Hookified {
166
279
  }
167
280
  return defaultValue;
168
281
  }
282
+ /**
283
+ * Get a string value from the feature flag.
284
+ * @param {string} key - The key of the feature flag
285
+ * @param {string} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
286
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
287
+ * @returns {Promise<string>} - The value of the feature flag
288
+ */
169
289
  async getString(key, defaultValue, options) {
170
290
  try {
171
291
  const data = {
@@ -218,6 +338,14 @@ var Toggle = class extends import_hookified.Hookified {
218
338
  }
219
339
  return defaultValue;
220
340
  }
341
+ /**
342
+ * Get an object value from the feature flag. This will check the type of the default value and call the
343
+ * appropriate function. It will also set the context if it is not set.
344
+ * @param {string} key - The key of the feature flag
345
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
346
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
347
+ * @returns {Promise<T>} - The value of the feature flag
348
+ */
221
349
  async getObject(key, defaultValue, options) {
222
350
  try {
223
351
  const data = {
package/dist/index.d.cts CHANGED
@@ -12,6 +12,10 @@ 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
21
  * Your application name
@@ -19,10 +23,10 @@ type ToggleOptions = {
19
23
  */
20
24
  applicationId: string;
21
25
  /**
22
- * Your Hyphen API key
26
+ * Your Hyphen Public API key
23
27
  * @type {string}
24
28
  */
25
- publicKey: 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,37 +57,149 @@ type ToggleOptions = {
55
57
  */
56
58
  uris?: string[];
57
59
  };
58
- type ToggleRequestOptions = {
60
+ type ToggleGetOptions = {
61
+ /**
62
+ * The context to use for evaluating feature flags
63
+ * @type {ToggleContext}
64
+ */
59
65
  context?: ToggleContext;
60
66
  };
61
67
  declare class Toggle extends Hookified {
62
68
  private _applicationId;
63
- private _publicKey;
69
+ private _publicApiKey;
64
70
  private _environment;
65
71
  private _client;
66
72
  private _context;
67
73
  private _throwErrors;
68
- private _uris?;
74
+ private _uris;
75
+ private _caching;
69
76
  constructor(options: ToggleOptions);
77
+ /**
78
+ * Get the application ID
79
+ * @returns {string}
80
+ */
70
81
  get applicationId(): string;
82
+ /**
83
+ * Set the application ID
84
+ * @param {string} value
85
+ */
71
86
  set applicationId(value: string);
72
- get publicKey(): string;
73
- set publicKey(value: string);
87
+ /**
88
+ * Get the public API key
89
+ * @returns {string}
90
+ */
91
+ get publicApiKey(): string;
92
+ /**
93
+ * Set the public API key
94
+ * @param {string} value
95
+ */
96
+ set publicApiKey(value: string);
97
+ /**
98
+ * Get the environment
99
+ * @returns {string}
100
+ */
74
101
  get environment(): string;
102
+ /**
103
+ * Set the environment
104
+ * @param {string} value
105
+ */
75
106
  set environment(value: string);
107
+ /**
108
+ * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
109
+ * @returns {boolean}
110
+ */
76
111
  get throwErrors(): boolean;
112
+ /**
113
+ * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
114
+ * @param {boolean} value
115
+ */
77
116
  set throwErrors(value: boolean);
117
+ /**
118
+ * Get the current context. This is the default context used. You can override this at the get function level.
119
+ * @returns {ToggleContext}
120
+ */
78
121
  get context(): ToggleContext | undefined;
122
+ /**
123
+ * Set the context. This is the default context used. You can override this at the get function level.
124
+ * @param {ToggleContext} value
125
+ */
79
126
  set context(value: ToggleContext | undefined);
127
+ /**
128
+ * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
129
+ * @returns {Array<string>}
130
+ */
80
131
  get uris(): string[] | undefined;
132
+ /**
133
+ * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
134
+ * @param {Array<string>} value
135
+ */
81
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);
147
+ /**
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
149
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
150
+ * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
151
+ * @param key
152
+ * @returns
153
+ */
154
+ setPublicApiKey(key: string): void;
155
+ /**
156
+ * Set the context. This is the default context used. You can override this at the get function level.
157
+ * @param {ToggleContext} context
158
+ */
82
159
  setContext(context: ToggleContext): void;
160
+ /**
161
+ * Helper function to get the client. This will create a new client if one does not exist. It will also set the
162
+ * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
163
+ * This is normally only used internally.
164
+ * @returns {Promise<Client>}
165
+ */
83
166
  getClient(): Promise<Client>;
84
- get<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
85
- getBoolean(key: string, defaultValue: boolean, options?: ToggleRequestOptions): Promise<boolean>;
86
- getString(key: string, defaultValue: string, options?: ToggleRequestOptions): Promise<string>;
87
- getNumber(key: string, defaultValue: number, options?: ToggleRequestOptions): Promise<number>;
88
- getObject<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
167
+ /**
168
+ * This is the main function to get a feature flag value. It will check the type of the default value and call the
169
+ * appropriate function. It will also set the context if it is not set.
170
+ * @param {string} key - The key of the feature flag
171
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
172
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
173
+ * @returns {Promise<T>}
174
+ */
175
+ get<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
176
+ /**
177
+ * Get a boolean value from the feature flag. This will check the type of the default value and call the
178
+ * appropriate function. It will also set the context if it is not set.
179
+ * @param {string} key - The key of the feature flag
180
+ * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
181
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
182
+ * @returns {Promise<boolean>} - The value of the feature flag
183
+ */
184
+ getBoolean(key: string, defaultValue: boolean, options?: ToggleGetOptions): Promise<boolean>;
185
+ /**
186
+ * Get a string value from the feature flag.
187
+ * @param {string} key - The key of the feature flag
188
+ * @param {string} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
189
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
190
+ * @returns {Promise<string>} - The value of the feature flag
191
+ */
192
+ getString(key: string, defaultValue: string, options?: ToggleGetOptions): Promise<string>;
193
+ getNumber(key: string, defaultValue: number, options?: ToggleGetOptions): Promise<number>;
194
+ /**
195
+ * Get an object value from the feature flag. This will check the type of the default value and call the
196
+ * appropriate function. It will also set the context if it is not set.
197
+ * @param {string} key - The key of the feature flag
198
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
199
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
200
+ * @returns {Promise<T>} - The value of the feature flag
201
+ */
202
+ getObject<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
89
203
  }
90
204
 
91
- 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,6 +12,10 @@ 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
21
  * Your application name
@@ -19,10 +23,10 @@ type ToggleOptions = {
19
23
  */
20
24
  applicationId: string;
21
25
  /**
22
- * Your Hyphen API key
26
+ * Your Hyphen Public API key
23
27
  * @type {string}
24
28
  */
25
- publicKey: 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,37 +57,149 @@ type ToggleOptions = {
55
57
  */
56
58
  uris?: string[];
57
59
  };
58
- type ToggleRequestOptions = {
60
+ type ToggleGetOptions = {
61
+ /**
62
+ * The context to use for evaluating feature flags
63
+ * @type {ToggleContext}
64
+ */
59
65
  context?: ToggleContext;
60
66
  };
61
67
  declare class Toggle extends Hookified {
62
68
  private _applicationId;
63
- private _publicKey;
69
+ private _publicApiKey;
64
70
  private _environment;
65
71
  private _client;
66
72
  private _context;
67
73
  private _throwErrors;
68
- private _uris?;
74
+ private _uris;
75
+ private _caching;
69
76
  constructor(options: ToggleOptions);
77
+ /**
78
+ * Get the application ID
79
+ * @returns {string}
80
+ */
70
81
  get applicationId(): string;
82
+ /**
83
+ * Set the application ID
84
+ * @param {string} value
85
+ */
71
86
  set applicationId(value: string);
72
- get publicKey(): string;
73
- set publicKey(value: string);
87
+ /**
88
+ * Get the public API key
89
+ * @returns {string}
90
+ */
91
+ get publicApiKey(): string;
92
+ /**
93
+ * Set the public API key
94
+ * @param {string} value
95
+ */
96
+ set publicApiKey(value: string);
97
+ /**
98
+ * Get the environment
99
+ * @returns {string}
100
+ */
74
101
  get environment(): string;
102
+ /**
103
+ * Set the environment
104
+ * @param {string} value
105
+ */
75
106
  set environment(value: string);
107
+ /**
108
+ * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
109
+ * @returns {boolean}
110
+ */
76
111
  get throwErrors(): boolean;
112
+ /**
113
+ * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
114
+ * @param {boolean} value
115
+ */
77
116
  set throwErrors(value: boolean);
117
+ /**
118
+ * Get the current context. This is the default context used. You can override this at the get function level.
119
+ * @returns {ToggleContext}
120
+ */
78
121
  get context(): ToggleContext | undefined;
122
+ /**
123
+ * Set the context. This is the default context used. You can override this at the get function level.
124
+ * @param {ToggleContext} value
125
+ */
79
126
  set context(value: ToggleContext | undefined);
127
+ /**
128
+ * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
129
+ * @returns {Array<string>}
130
+ */
80
131
  get uris(): string[] | undefined;
132
+ /**
133
+ * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
134
+ * @param {Array<string>} value
135
+ */
81
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);
147
+ /**
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
149
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
150
+ * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
151
+ * @param key
152
+ * @returns
153
+ */
154
+ setPublicApiKey(key: string): void;
155
+ /**
156
+ * Set the context. This is the default context used. You can override this at the get function level.
157
+ * @param {ToggleContext} context
158
+ */
82
159
  setContext(context: ToggleContext): void;
160
+ /**
161
+ * Helper function to get the client. This will create a new client if one does not exist. It will also set the
162
+ * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
163
+ * This is normally only used internally.
164
+ * @returns {Promise<Client>}
165
+ */
83
166
  getClient(): Promise<Client>;
84
- get<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
85
- getBoolean(key: string, defaultValue: boolean, options?: ToggleRequestOptions): Promise<boolean>;
86
- getString(key: string, defaultValue: string, options?: ToggleRequestOptions): Promise<string>;
87
- getNumber(key: string, defaultValue: number, options?: ToggleRequestOptions): Promise<number>;
88
- getObject<T>(key: string, defaultValue: T, options?: ToggleRequestOptions): Promise<T>;
167
+ /**
168
+ * This is the main function to get a feature flag value. It will check the type of the default value and call the
169
+ * appropriate function. It will also set the context if it is not set.
170
+ * @param {string} key - The key of the feature flag
171
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
172
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
173
+ * @returns {Promise<T>}
174
+ */
175
+ get<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
176
+ /**
177
+ * Get a boolean value from the feature flag. This will check the type of the default value and call the
178
+ * appropriate function. It will also set the context if it is not set.
179
+ * @param {string} key - The key of the feature flag
180
+ * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
181
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
182
+ * @returns {Promise<boolean>} - The value of the feature flag
183
+ */
184
+ getBoolean(key: string, defaultValue: boolean, options?: ToggleGetOptions): Promise<boolean>;
185
+ /**
186
+ * Get a string value from the feature flag.
187
+ * @param {string} key - The key of the feature flag
188
+ * @param {string} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
189
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
190
+ * @returns {Promise<string>} - The value of the feature flag
191
+ */
192
+ getString(key: string, defaultValue: string, options?: ToggleGetOptions): Promise<string>;
193
+ getNumber(key: string, defaultValue: number, options?: ToggleGetOptions): Promise<number>;
194
+ /**
195
+ * Get an object value from the feature flag. This will check the type of the default value and call the
196
+ * appropriate function. It will also set the context if it is not set.
197
+ * @param {string} key - The key of the feature flag
198
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
199
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
200
+ * @returns {Promise<T>} - The value of the feature flag
201
+ */
202
+ getObject<T>(key: string, defaultValue: T, options?: ToggleGetOptions): Promise<T>;
89
203
  }
90
204
 
91
- 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
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
4
  // src/toggle.ts
5
- import process from "node:process";
5
+ import process from "process";
6
6
  import { Hookified } from "hookified";
7
7
  import { OpenFeature } from "@openfeature/server-sdk";
8
8
  import { HyphenProvider } from "@hyphen/openfeature-server-provider";
@@ -22,73 +22,178 @@ var Toggle = class extends Hookified {
22
22
  __name(this, "Toggle");
23
23
  }
24
24
  _applicationId;
25
- _publicKey;
25
+ _publicApiKey = "";
26
26
  _environment;
27
27
  _client;
28
28
  _context;
29
29
  _throwErrors = false;
30
30
  _uris;
31
+ _caching;
32
+ /*
33
+ * Create a new Toggle instance. This will create a new client and set the options.
34
+ * @param {ToggleOptions}
35
+ */
31
36
  constructor(options) {
32
37
  super();
33
38
  this._applicationId = options.applicationId;
34
- this._publicKey = options.publicKey;
39
+ this.setPublicApiKey(options.publicApiKey);
35
40
  this._environment = options.environment ?? process.env.NODE_ENV ?? "development";
36
41
  this._context = options.context;
37
42
  this._throwErrors = options.throwErrors ?? false;
38
43
  this._uris = options.uris;
44
+ this._caching = options.caching;
39
45
  }
46
+ /**
47
+ * Get the application ID
48
+ * @returns {string}
49
+ */
40
50
  get applicationId() {
41
51
  return this._applicationId;
42
52
  }
53
+ /**
54
+ * Set the application ID
55
+ * @param {string} value
56
+ */
43
57
  set applicationId(value) {
44
58
  this._applicationId = value;
45
59
  }
46
- get publicKey() {
47
- return this._publicKey;
60
+ /**
61
+ * Get the public API key
62
+ * @returns {string}
63
+ */
64
+ get publicApiKey() {
65
+ return this._publicApiKey;
48
66
  }
49
- set publicKey(value) {
50
- this._publicKey = value;
67
+ /**
68
+ * Set the public API key
69
+ * @param {string} value
70
+ */
71
+ set publicApiKey(value) {
72
+ this.setPublicApiKey(value);
51
73
  }
74
+ /**
75
+ * Get the environment
76
+ * @returns {string}
77
+ */
52
78
  get environment() {
53
79
  return this._environment;
54
80
  }
81
+ /**
82
+ * Set the environment
83
+ * @param {string} value
84
+ */
55
85
  set environment(value) {
56
86
  this._environment = value;
57
87
  }
88
+ /**
89
+ * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
90
+ * @returns {boolean}
91
+ */
58
92
  get throwErrors() {
59
93
  return this._throwErrors;
60
94
  }
95
+ /**
96
+ * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
97
+ * @param {boolean} value
98
+ */
61
99
  set throwErrors(value) {
62
100
  this._throwErrors = value;
63
101
  }
102
+ /**
103
+ * Get the current context. This is the default context used. You can override this at the get function level.
104
+ * @returns {ToggleContext}
105
+ */
64
106
  get context() {
65
107
  return this._context;
66
108
  }
109
+ /**
110
+ * Set the context. This is the default context used. You can override this at the get function level.
111
+ * @param {ToggleContext} value
112
+ */
67
113
  set context(value) {
68
114
  this._context = value;
69
115
  }
116
+ /**
117
+ * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
118
+ * @returns {Array<string>}
119
+ */
70
120
  get uris() {
71
121
  return this._uris;
72
122
  }
123
+ /**
124
+ * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
125
+ * @param {Array<string>} value
126
+ */
73
127
  set uris(value) {
74
128
  this._uris = value;
75
129
  }
130
+ /**
131
+ * Get the caching options.
132
+ * @returns {ToggleCachingOptions | undefined}
133
+ */
134
+ get caching() {
135
+ return this._caching;
136
+ }
137
+ /**
138
+ * Set the caching options.
139
+ * @param {ToggleCachingOptions | undefined} value
140
+ */
141
+ set caching(value) {
142
+ this._caching = value;
143
+ }
144
+ /**
145
+ * 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
146
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
147
+ * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
148
+ * @param key
149
+ * @returns
150
+ */
151
+ setPublicApiKey(key) {
152
+ if (!key.startsWith("public_")) {
153
+ this.emit("error", new Error("Public API key should start with public_"));
154
+ if (process.env.NODE_ENV !== "production") {
155
+ console.error("Public API key should start with public_");
156
+ }
157
+ return;
158
+ }
159
+ this._publicApiKey = key;
160
+ this._client = void 0;
161
+ }
162
+ /**
163
+ * Set the context. This is the default context used. You can override this at the get function level.
164
+ * @param {ToggleContext} context
165
+ */
76
166
  setContext(context) {
77
167
  this._context = context;
78
168
  this._client = void 0;
79
169
  }
170
+ /**
171
+ * Helper function to get the client. This will create a new client if one does not exist. It will also set the
172
+ * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
173
+ * This is normally only used internally.
174
+ * @returns {Promise<Client>}
175
+ */
80
176
  async getClient() {
81
177
  if (!this._client) {
82
178
  const options = {
83
179
  application: this._applicationId,
84
180
  environment: this._environment,
85
- horizonUrls: this._uris
181
+ horizonUrls: this._uris,
182
+ cache: this._caching
86
183
  };
87
- await OpenFeature.setProviderAndWait(new HyphenProvider(this._publicKey, options));
184
+ await OpenFeature.setProviderAndWait(new HyphenProvider(this._publicApiKey, options));
88
185
  this._client = OpenFeature.getClient(this._context);
89
186
  }
90
187
  return this._client;
91
188
  }
189
+ /**
190
+ * This is the main function to get a feature flag value. It will check the type of the default value and call the
191
+ * appropriate function. It will also set the context if it is not set.
192
+ * @param {string} key - The key of the feature flag
193
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
194
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
195
+ * @returns {Promise<T>}
196
+ */
92
197
  async get(key, defaultValue, options) {
93
198
  switch (typeof defaultValue) {
94
199
  case "boolean": {
@@ -105,6 +210,14 @@ var Toggle = class extends Hookified {
105
210
  }
106
211
  }
107
212
  }
213
+ /**
214
+ * Get a boolean value from the feature flag. This will check the type of the default value and call the
215
+ * appropriate function. It will also set the context if it is not set.
216
+ * @param {string} key - The key of the feature flag
217
+ * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
218
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
219
+ * @returns {Promise<boolean>} - The value of the feature flag
220
+ */
108
221
  async getBoolean(key, defaultValue, options) {
109
222
  try {
110
223
  const data = {
@@ -131,6 +244,13 @@ var Toggle = class extends Hookified {
131
244
  }
132
245
  return defaultValue;
133
246
  }
247
+ /**
248
+ * Get a string value from the feature flag.
249
+ * @param {string} key - The key of the feature flag
250
+ * @param {string} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
251
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
252
+ * @returns {Promise<string>} - The value of the feature flag
253
+ */
134
254
  async getString(key, defaultValue, options) {
135
255
  try {
136
256
  const data = {
@@ -183,6 +303,14 @@ var Toggle = class extends Hookified {
183
303
  }
184
304
  return defaultValue;
185
305
  }
306
+ /**
307
+ * Get an object value from the feature flag. This will check the type of the default value and call the
308
+ * appropriate function. It will also set the context if it is not set.
309
+ * @param {string} key - The key of the feature flag
310
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
311
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
312
+ * @returns {Promise<T>} - The value of the feature flag
313
+ */
186
314
  async getObject(key, defaultValue, options) {
187
315
  try {
188
316
  const data = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyphen/sdk",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Hyphen SDK for Node.js",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -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",