@hyphen/sdk 1.11.0 → 1.12.1

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/dist/index.cjs CHANGED
@@ -34,507 +34,535 @@ __export(index_exports, {
34
34
  Hyphen: () => Hyphen,
35
35
  Toggle: () => Toggle,
36
36
  ToggleHooks: () => ToggleHooks,
37
+ env: () => env,
37
38
  loadEnv: () => loadEnv
38
39
  });
39
40
  module.exports = __toCommonJS(index_exports);
40
41
 
41
- // src/toggle.ts
42
+ // src/env.ts
43
+ var import_node_fs = __toESM(require("fs"), 1);
44
+ var import_node_path = __toESM(require("path"), 1);
42
45
  var import_node_process = __toESM(require("process"), 1);
46
+ var import_dotenv = require("dotenv");
47
+ function env(options) {
48
+ const local = options?.local ?? true;
49
+ const currentWorkingDirectory = options?.path ?? import_node_process.default.cwd();
50
+ const envPath = import_node_path.default.resolve(currentWorkingDirectory, ".env");
51
+ if (import_node_fs.default.existsSync(envPath)) {
52
+ (0, import_dotenv.config)({
53
+ path: envPath,
54
+ quiet: true,
55
+ debug: false
56
+ });
57
+ }
58
+ if (local) {
59
+ const localEnvPath = import_node_path.default.resolve(currentWorkingDirectory, ".env.local");
60
+ if (import_node_fs.default.existsSync(localEnvPath)) {
61
+ (0, import_dotenv.config)({
62
+ path: localEnvPath,
63
+ override: true,
64
+ quiet: true,
65
+ debug: false
66
+ });
67
+ }
68
+ }
69
+ const environment = options?.environment ?? import_node_process.default.env.NODE_ENV;
70
+ if (environment) {
71
+ const envSpecificPath = import_node_path.default.resolve(currentWorkingDirectory, `.env.${environment}`);
72
+ if (import_node_fs.default.existsSync(envSpecificPath)) {
73
+ (0, import_dotenv.config)({
74
+ path: envSpecificPath,
75
+ override: true,
76
+ quiet: true,
77
+ debug: false
78
+ });
79
+ }
80
+ if (local) {
81
+ const envLocalPath = import_node_path.default.resolve(currentWorkingDirectory, `.env.${environment}.local`);
82
+ if (import_node_fs.default.existsSync(envLocalPath)) {
83
+ (0, import_dotenv.config)({
84
+ path: envLocalPath,
85
+ override: true,
86
+ quiet: true,
87
+ debug: false
88
+ });
89
+ }
90
+ }
91
+ }
92
+ }
93
+ __name(env, "env");
94
+ var loadEnv = env;
95
+
96
+ // src/hyphen.ts
97
+ var import_hookified3 = require("hookified");
98
+
99
+ // src/link.ts
100
+ var import_node_buffer = require("buffer");
101
+ var import_node_process2 = __toESM(require("process"), 1);
102
+
103
+ // src/base-service.ts
104
+ var import_axios = __toESM(require("axios"), 1);
105
+ var import_cacheable = require("cacheable");
43
106
  var import_hookified = require("hookified");
44
- var import_dotenv = __toESM(require("dotenv"), 1);
45
- var import_server_sdk = require("@openfeature/server-sdk");
46
- var import_openfeature_server_provider = require("@hyphen/openfeature-server-provider");
47
- import_dotenv.default.config();
48
- var ToggleHooks = /* @__PURE__ */ function(ToggleHooks2) {
49
- ToggleHooks2["beforeGetBoolean"] = "beforeGetBoolean";
50
- ToggleHooks2["afterGetBoolean"] = "afterGetBoolean";
51
- ToggleHooks2["beforeGetString"] = "beforeGetString";
52
- ToggleHooks2["afterGetString"] = "afterGetString";
53
- ToggleHooks2["beforeGetNumber"] = "beforeGetNumber";
54
- ToggleHooks2["afterGetNumber"] = "afterGetNumber";
55
- ToggleHooks2["beforeGetObject"] = "beforeGetObject";
56
- ToggleHooks2["afterGetObject"] = "afterGetObject";
57
- return ToggleHooks2;
107
+ var import_pino = __toESM(require("pino"), 1);
108
+ var ErrorMessages = /* @__PURE__ */ function(ErrorMessages2) {
109
+ ErrorMessages2["API_KEY_REQUIRED"] = "API key is required. Please provide it via options or set the HYPHEN_API_KEY environment variable.";
110
+ ErrorMessages2["PUBLIC_API_KEY_SHOULD_NOT_BE_USED"] = "The provided API key is a public API key. Please provide a valid non public API key for authentication.";
111
+ return ErrorMessages2;
58
112
  }({});
59
- var Toggle = class extends import_hookified.Hookified {
113
+ var BaseService = class extends import_hookified.Hookified {
60
114
  static {
61
- __name(this, "Toggle");
115
+ __name(this, "BaseService");
62
116
  }
63
- _applicationId = import_node_process.default.env.HYPHEN_APPLICATION_ID;
64
- _publicApiKey = import_node_process.default.env.HYPHEN_PUBLIC_API_KEY;
65
- _environment;
66
- _client;
67
- _context;
117
+ _log = (0, import_pino.default)();
118
+ _cache = new import_cacheable.Cacheable();
68
119
  _throwErrors = false;
69
- _uris;
70
- _caching;
71
- /*
72
- * Create a new Toggle instance. This will create a new client and set the options.
73
- * @param {ToggleOptions}
74
- */
75
120
  constructor(options) {
76
- super();
77
- this._throwErrors = options?.throwErrors ?? false;
78
- this._applicationId = options?.applicationId;
79
- if (options?.publicApiKey) {
80
- this.setPublicApiKey(options.publicApiKey);
121
+ super(options);
122
+ if (options && options.throwErrors !== void 0) {
123
+ this._throwErrors = options.throwErrors;
81
124
  }
82
- this._environment = options?.environment ?? import_node_process.default.env.NODE_ENV ?? "development";
83
- this._context = options?.context;
84
- this._uris = options?.uris;
85
- this._caching = options?.caching;
86
125
  }
87
- /**
88
- * Get the application ID
89
- * @returns {string | undefined}
90
- */
91
- get applicationId() {
92
- return this._applicationId;
93
- }
94
- /**
95
- * Set the application ID
96
- * @param {string | undefined} value
97
- */
98
- set applicationId(value) {
99
- this._applicationId = value;
100
- }
101
- /**
102
- * Get the public API key
103
- * @returns {string}
104
- */
105
- get publicApiKey() {
106
- return this._publicApiKey;
126
+ get log() {
127
+ return this._log;
107
128
  }
108
- /**
109
- * Set the public API key
110
- * @param {string} value
111
- */
112
- set publicApiKey(value) {
113
- if (!value) {
114
- this._publicApiKey = void 0;
115
- this._client = void 0;
116
- return;
117
- }
118
- this.setPublicApiKey(value);
129
+ set log(value) {
130
+ this._log = value;
119
131
  }
120
- /**
121
- * Get the environment
122
- * @returns {string}
123
- */
124
- get environment() {
125
- return this._environment;
132
+ get cache() {
133
+ return this._cache;
126
134
  }
127
- /**
128
- * Set the environment
129
- * @param {string} value
130
- */
131
- set environment(value) {
132
- this._environment = value;
135
+ set cache(value) {
136
+ this._cache = value;
133
137
  }
134
- /**
135
- * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
136
- * @returns {boolean}
137
- */
138
138
  get throwErrors() {
139
139
  return this._throwErrors;
140
140
  }
141
- /**
142
- * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
143
- * @param {boolean} value
144
- */
145
141
  set throwErrors(value) {
146
142
  this._throwErrors = value;
147
143
  }
144
+ error(message, ...args) {
145
+ this._log.error(message, ...args);
146
+ this.emit("error", message, ...args);
147
+ if (this.throwErrors) {
148
+ throw new Error(message);
149
+ }
150
+ }
151
+ warn(message, ...args) {
152
+ this._log.warn(message, ...args);
153
+ this.emit("warn", message, ...args);
154
+ }
155
+ info(message, ...args) {
156
+ this._log.info(message, ...args);
157
+ this.emit("info", message, ...args);
158
+ }
159
+ async get(url, config2) {
160
+ return import_axios.default.get(url, config2);
161
+ }
162
+ async post(url, data, config2) {
163
+ return import_axios.default.post(url, data, config2);
164
+ }
165
+ async put(url, data, config2) {
166
+ return import_axios.default.put(url, data, config2);
167
+ }
168
+ async delete(url, config2) {
169
+ if (config2?.headers) {
170
+ delete config2.headers["content-type"];
171
+ }
172
+ return import_axios.default.delete(url, config2);
173
+ }
174
+ async patch(url, data, config2) {
175
+ return import_axios.default.patch(url, data, config2);
176
+ }
177
+ createHeaders(apiKey) {
178
+ const headers = {
179
+ "content-type": "application/json",
180
+ accept: "application/json"
181
+ };
182
+ if (apiKey) {
183
+ headers["x-api-key"] = apiKey;
184
+ }
185
+ return headers;
186
+ }
187
+ };
188
+
189
+ // src/link.ts
190
+ env();
191
+ var defaultLinkUris = [
192
+ "https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"
193
+ ];
194
+ var Link = class extends BaseService {
195
+ static {
196
+ __name(this, "Link");
197
+ }
198
+ _uris = defaultLinkUris;
199
+ _organizationId;
200
+ _apiKey;
201
+ constructor(options) {
202
+ super(options);
203
+ this._uris = options?.uris ?? defaultLinkUris;
204
+ this._organizationId = options?.organizationId;
205
+ if (options?.apiKey) {
206
+ this.setApiKey(options.apiKey);
207
+ }
208
+ if (!this._apiKey && import_node_process2.default.env.HYPHEN_API_KEY) {
209
+ this.setApiKey(import_node_process2.default.env.HYPHEN_API_KEY);
210
+ }
211
+ if (!this._organizationId && import_node_process2.default.env.HYPHEN_ORGANIZATION_ID) {
212
+ this._organizationId = import_node_process2.default.env.HYPHEN_ORGANIZATION_ID;
213
+ }
214
+ }
148
215
  /**
149
- * Get the current context. This is the default context used. You can override this at the get function level.
150
- * @returns {ToggleContext}
216
+ * Get the URIs for the link service. The default is `["https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"]`.
217
+ * @returns {string[]} The URIs for the link service.
151
218
  */
152
- get context() {
153
- return this._context;
219
+ get uris() {
220
+ return this._uris;
154
221
  }
155
222
  /**
156
- * Set the context. This is the default context used. You can override this at the get function level.
157
- * @param {ToggleContext} value
223
+ * Set the URIs for the link service. The default is `["https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"]`.
224
+ * @param {string[]} uris - The URIs to set.
158
225
  */
159
- set context(value) {
160
- this._context = value;
226
+ set uris(uris) {
227
+ this._uris = uris;
161
228
  }
162
229
  /**
163
- * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
164
- * @returns {Array<string>}
230
+ * Get the organization ID for the link service. This is required to access the link service.
231
+ * @returns {string | undefined} The organization ID.
165
232
  */
166
- get uris() {
167
- return this._uris;
233
+ get organizationId() {
234
+ return this._organizationId;
168
235
  }
169
236
  /**
170
- * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
171
- * @param {Array<string>} value
237
+ * Set the organization ID for the link service. This is required to access the link service.
238
+ * @param {string | undefined} organizationId - The organization ID to set.
172
239
  */
173
- set uris(value) {
174
- this._uris = value;
240
+ set organizationId(organizationId) {
241
+ this._organizationId = organizationId;
175
242
  }
176
243
  /**
177
- * Get the caching options.
178
- * @returns {ToggleCachingOptions | undefined}
244
+ * Get the API key for the link service. This is required to access the link service.
245
+ * @returns {string | undefined} The API key.
179
246
  */
180
- get caching() {
181
- return this._caching;
247
+ get apiKey() {
248
+ return this._apiKey;
182
249
  }
183
250
  /**
184
- * Set the caching options.
185
- * @param {ToggleCachingOptions | undefined} value
251
+ * Set the API key for the link service. This is required to access the link service.
252
+ * @param {string | undefined} apiKey - The API key to set.
186
253
  */
187
- set caching(value) {
188
- this._caching = value;
254
+ set apiKey(apiKey) {
255
+ this.setApiKey(apiKey);
189
256
  }
190
257
  /**
191
- * 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
192
- * does set it will also set the client to undefined to force a new one to be created. If it does not,
193
- * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
194
- * @param key
195
- * @returns
258
+ * Set the API key for the link service. If the API key starts with 'public_', an error is thrown.
259
+ * This is to ensure that the API key is not a public key, which should not be used for authenticated requests.
260
+ * @param {string} apiKey
196
261
  */
197
- setPublicApiKey(key) {
198
- if (!key.startsWith("public_")) {
199
- this.emit("error", new Error("Public API key should start with public_"));
200
- if (import_node_process.default.env.NODE_ENV !== "production") {
201
- console.error("Public API key should start with public_");
202
- }
203
- return;
262
+ setApiKey(apiKey) {
263
+ if (apiKey?.startsWith("public_")) {
264
+ throw new Error('API key cannot start with "public_"');
265
+ }
266
+ if (apiKey) {
267
+ this._apiKey = apiKey;
204
268
  }
205
- this._publicApiKey = key;
206
- this._client = void 0;
207
269
  }
208
270
  /**
209
- * Set the context. This is the default context used. You can override this at the get function level.
210
- * @param {ToggleContext} context
271
+ * Get the URI for a specific organization and code. This is used internally to construct the URI for the link service.
272
+ * @param {string} organizationId The ID of the organization.
273
+ * @param {string} code The code to include in the URI.
274
+ * @returns {string} The constructed URI.
211
275
  */
212
- setContext(context) {
213
- this._context = context;
214
- this._client = void 0;
276
+ getUri(organizationId, prefix1, prefix2, prefix3) {
277
+ if (!organizationId) {
278
+ throw new Error("Organization ID is required to get the URI.");
279
+ }
280
+ let url = this._uris[0].replace("{organizationId}", organizationId);
281
+ if (prefix1) {
282
+ url = url.endsWith("/") ? `${url}${prefix1}/` : `${url}/${prefix1}`;
283
+ }
284
+ if (prefix2) {
285
+ url = url.endsWith("/") ? `${url}${prefix2}/` : `${url}/${prefix2}`;
286
+ }
287
+ if (prefix3) {
288
+ url = url.endsWith("/") ? `${url}${prefix3}/` : `${url}/${prefix3}`;
289
+ }
290
+ if (url.endsWith("/")) {
291
+ url = url.slice(0, -1);
292
+ }
293
+ return url;
215
294
  }
216
295
  /**
217
- * Helper function to get the client. This will create a new client if one does not exist. It will also set the
218
- * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
219
- * This is normally only used internally.
220
- * @returns {Promise<Client>}
296
+ * Create a short code for a long URL.
297
+ * @param {string} longUrl The long URL to shorten.
298
+ * @param {string} domain The domain to use for the short code.
299
+ * @param {CreateShortCodeOptions} options Optional parameters for creating the short code.
300
+ * @returns {Promise<CreateShortCodeResponse>} A promise that resolves to the created short code details.
221
301
  */
222
- async getClient() {
223
- if (!this._client) {
224
- if (this._applicationId === void 0 || this._applicationId.length === 0) {
225
- const errorMessage = "Application ID is not set. You must set it before using the client or have the HYPHEN_APPLICATION_ID environment variable set.";
226
- this.emit("error", new Error(errorMessage));
227
- if (this._throwErrors) {
228
- throw new Error(errorMessage);
229
- }
230
- }
231
- const options = {
232
- application: this._applicationId,
233
- environment: this._environment,
234
- horizonUrls: this._uris,
235
- cache: this._caching
236
- };
237
- if (this._publicApiKey && this._publicApiKey.length > 0) {
238
- await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicApiKey, options));
239
- } else {
240
- 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."));
241
- if (this._throwErrors) {
242
- throw new Error("Public API key is not set");
243
- }
244
- }
245
- this._client = import_server_sdk.OpenFeature.getClient(this._context);
302
+ async createShortCode(longUrl, domain, options) {
303
+ if (!this._organizationId) {
304
+ throw new Error("Organization ID is required to create a short code.");
246
305
  }
247
- return this._client;
306
+ const url = this.getUri(this._organizationId);
307
+ const body = {
308
+ long_url: longUrl,
309
+ domain,
310
+ code: options?.code,
311
+ title: options?.title,
312
+ tags: options?.tags
313
+ };
314
+ const headers = this.createHeaders(this._apiKey);
315
+ const response = await this.post(url, body, {
316
+ headers
317
+ });
318
+ if (response.status === 201) {
319
+ return response.data;
320
+ }
321
+ throw new Error(`Failed to create short code: ${response.statusText}`);
248
322
  }
249
323
  /**
250
- * This is the main function to get a feature flag value. It will check the type of the default value and call the
251
- * appropriate function. It will also set the context if it is not set.
252
- * @param {string} key - The key of the feature flag
253
- * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
254
- * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
255
- * @returns {Promise<T>}
324
+ * Get a short code by its code.
325
+ * @param {string} code The short code to retrieve. Example: 'code_686bed403c3991bd676bba4d'
326
+ * @returns {Promise<GetShortCodeResponse>} A promise that resolves to the short code details.
256
327
  */
257
- async get(key, defaultValue, options) {
258
- switch (typeof defaultValue) {
259
- case "boolean": {
260
- return this.getBoolean(key, defaultValue, options);
261
- }
262
- case "string": {
263
- return this.getString(key, defaultValue, options);
264
- }
265
- case "number": {
266
- return this.getNumber(key, defaultValue, options);
267
- }
268
- default: {
269
- return this.getObject(key, defaultValue, options);
270
- }
328
+ async getShortCode(code) {
329
+ if (!this._organizationId) {
330
+ throw new Error("Organization ID is required to get a short code.");
331
+ }
332
+ const url = this.getUri(this._organizationId, code);
333
+ const headers = this.createHeaders(this._apiKey);
334
+ const response = await this.get(url, {
335
+ headers
336
+ });
337
+ if (response.status === 200) {
338
+ return response.data;
271
339
  }
340
+ throw new Error(`Failed to get short code: ${response.statusText}`);
272
341
  }
273
342
  /**
274
- * Get a boolean value from the feature flag. This will check the type of the default value and call the
275
- * appropriate function. It will also set the context if it is not set.
276
- * @param {string} key - The key of the feature flag
277
- * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
278
- * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
279
- * @returns {Promise<boolean>} - The value of the feature flag
343
+ * Get all short codes for the organization.
344
+ * @param {string} titleSearch Optional search term to filter short codes by title.
345
+ * @param {string[]} tags Optional tags to filter short codes.
346
+ * @param {number} pageNumber The page number to retrieve. Default is 1.
347
+ * @param {number} pageSize The number of short codes per page. Default is 100.
348
+ * @returns {Promise<GetShortCodesResponse>} A promise that resolves to the list of short codes.
280
349
  */
281
- async getBoolean(key, defaultValue, options) {
282
- try {
283
- const data = {
284
- key,
285
- defaultValue,
286
- options
287
- };
288
- await this.hook("beforeGetBoolean", data);
289
- const client = await this.getClient();
290
- const result = await client.getBooleanValue(data.key, data.defaultValue, data.options?.context);
291
- const resultData = {
292
- key,
293
- defaultValue,
294
- options,
295
- result
296
- };
297
- await this.hook("afterGetBoolean", resultData);
298
- return resultData.result;
299
- } catch (error) {
300
- this.emit("error", error);
301
- if (this._throwErrors) {
302
- throw error;
303
- }
350
+ async getShortCodes(titleSearch, tags, pageNumber = 1, pageSize = 100) {
351
+ if (!this._organizationId) {
352
+ throw new Error("Organization ID is required to get short codes.");
304
353
  }
305
- return defaultValue;
354
+ const url = this.getUri(this._organizationId);
355
+ const headers = this.createHeaders(this._apiKey);
356
+ const parameters = {};
357
+ if (titleSearch) {
358
+ parameters.title = titleSearch;
359
+ }
360
+ if (tags && tags.length > 0) {
361
+ parameters.tags = tags.join(",");
362
+ }
363
+ parameters.pageNum = pageNumber.toString();
364
+ parameters.pageSize = pageSize.toString();
365
+ const response = await this.get(url, {
366
+ headers,
367
+ params: parameters
368
+ });
369
+ if (response.status === 200) {
370
+ return response.data;
371
+ }
372
+ throw new Error(`Failed to get short codes: ${response.statusText}`);
306
373
  }
307
374
  /**
308
- * Get a string value from the feature flag.
309
- * @param {string} key - The key of the feature flag
310
- * @param {string} 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<string>} - The value of the feature flag
375
+ * Get all tags associated with the organization's short codes.
376
+ * @returns {Promise<string[]>} A promise that resolves to an array of tags.
313
377
  */
314
- async getString(key, defaultValue, options) {
315
- try {
316
- const data = {
317
- key,
318
- defaultValue,
319
- options
320
- };
321
- await this.hook("beforeGetString", data);
322
- const client = await this.getClient();
323
- const result = await client.getStringValue(data.key, data.defaultValue, data.options?.context);
324
- const resultData = {
325
- key,
326
- defaultValue,
327
- options,
328
- result
329
- };
330
- await this.hook("afterGetString", resultData);
331
- return resultData.result;
332
- } catch (error) {
333
- this.emit("error", error);
334
- if (this._throwErrors) {
335
- throw error;
336
- }
378
+ async getTags() {
379
+ if (!this._organizationId) {
380
+ throw new Error("Organization ID is required to get tags.");
337
381
  }
338
- return defaultValue;
382
+ const url = this.getUri(this._organizationId, "tags");
383
+ const headers = this.createHeaders(this._apiKey);
384
+ const response = await this.get(url, {
385
+ headers
386
+ });
387
+ if (response.status === 200) {
388
+ return response.data;
389
+ }
390
+ throw new Error(`Failed to get tags: ${response.statusText}`);
339
391
  }
340
- async getNumber(key, defaultValue, options) {
341
- try {
342
- const data = {
343
- key,
344
- defaultValue,
345
- options
346
- };
347
- await this.hook("beforeGetNumber", data);
348
- const client = await this.getClient();
349
- const result = await client.getNumberValue(data.key, data.defaultValue, data.options?.context);
350
- const resultData = {
351
- key,
352
- defaultValue,
353
- options,
354
- result
355
- };
356
- await this.hook("afterGetNumber", resultData);
357
- return resultData.result;
358
- } catch (error) {
359
- this.emit("error", error);
360
- if (this._throwErrors) {
361
- throw error;
362
- }
392
+ /**
393
+ * Get statistics for a specific short code.
394
+ * @param code The short code to retrieve statistics for.
395
+ * @returns {Promise<GetCodeStatsResponse>} A promise that resolves to the code statistics.
396
+ */
397
+ async getCodeStats(code, startDate, endDate) {
398
+ if (!this._organizationId) {
399
+ throw new Error("Organization ID is required to get code stats.");
363
400
  }
364
- return defaultValue;
401
+ const url = this.getUri(this._organizationId, code, "stats");
402
+ const headers = this.createHeaders(this._apiKey);
403
+ const parameters = {
404
+ startDate: startDate.toISOString(),
405
+ endDate: endDate.toISOString()
406
+ };
407
+ const response = await this.get(url, {
408
+ headers,
409
+ params: parameters
410
+ });
411
+ if (response.status === 200) {
412
+ return response.data;
413
+ }
414
+ throw new Error(`Failed to get code stats: ${response.statusText}`);
365
415
  }
366
416
  /**
367
- * Get an object value from the feature flag. This will check the type of the default value and call the
368
- * appropriate function. It will also set the context if it is not set.
369
- * @param {string} key - The key of the feature flag
370
- * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
371
- * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
372
- * @returns {Promise<T>} - The value of the feature flag
417
+ * Update a short code.
418
+ * @param {string} code The short code to update. Example: 'code_686bed403c3991bd676bba4d'
419
+ * @param {UpdateShortCodeOptions} options The options to update the short code with.
420
+ * @returns {Promise<UpdateShortCodeResponse>} A promise that resolves to the updated short code details.
373
421
  */
374
- async getObject(key, defaultValue, options) {
375
- try {
376
- const data = {
377
- key,
378
- defaultValue,
379
- options
380
- };
381
- await this.hook("beforeGetObject", data);
382
- const client = await this.getClient();
383
- const result = await client.getObjectValue(key, defaultValue, data.options?.context);
384
- const resultData = {
385
- key,
386
- defaultValue,
387
- options,
388
- result
389
- };
390
- await this.hook("afterGetObject", resultData);
391
- return resultData.result;
392
- } catch (error) {
393
- this.emit("error", error);
394
- if (this._throwErrors) {
395
- throw error;
396
- }
422
+ async updateShortCode(code, options) {
423
+ if (!this._organizationId) {
424
+ throw new Error("Organization ID is required to update a short code.");
397
425
  }
398
- return defaultValue;
399
- }
400
- };
401
-
402
- // src/env.ts
403
- var import_node_process2 = __toESM(require("process"), 1);
404
- var import_node_fs = __toESM(require("fs"), 1);
405
- var import_node_path = __toESM(require("path"), 1);
406
- var import_dotenv2 = require("dotenv");
407
- function loadEnv(options) {
408
- const local = options?.local ?? true;
409
- const currentWorkingDirectory = options?.path ?? import_node_process2.default.cwd();
410
- const envPath = import_node_path.default.resolve(currentWorkingDirectory, ".env");
411
- if (import_node_fs.default.existsSync(envPath)) {
412
- (0, import_dotenv2.config)({
413
- path: envPath
426
+ const url = this.getUri(this._organizationId, code);
427
+ const headers = this.createHeaders(this._apiKey);
428
+ const response = await this.patch(url, options, {
429
+ headers
414
430
  });
431
+ if (response.status === 200) {
432
+ return response.data;
433
+ }
434
+ throw new Error(`Failed to update short code: ${response.statusText}`);
415
435
  }
416
- if (local) {
417
- const localEnvPath = import_node_path.default.resolve(currentWorkingDirectory, ".env.local");
418
- if (import_node_fs.default.existsSync(localEnvPath)) {
419
- (0, import_dotenv2.config)({
420
- path: localEnvPath,
421
- override: true
422
- });
436
+ /**
437
+ * Delete a short code.
438
+ * @param {string} code The short code to delete. Example: 'code_686bed403c3991bd676bba4d'
439
+ * @returns {Promise<boolean>} A promise that resolves to true if the short code was deleted successfully, or false if it was not.
440
+ */
441
+ async deleteShortCode(code) {
442
+ if (!this._organizationId) {
443
+ throw new Error("Organization ID is required to delete a short code.");
444
+ }
445
+ const url = this.getUri(this._organizationId, code);
446
+ const headers = this.createHeaders(this._apiKey);
447
+ const response = await this.delete(url, {
448
+ headers
449
+ });
450
+ if (response.status === 204) {
451
+ return true;
423
452
  }
453
+ throw new Error(`Failed to delete short code: ${response.statusText}`);
424
454
  }
425
- const environment = options?.environment ?? import_node_process2.default.env.NODE_ENV;
426
- if (environment) {
427
- const envSpecificPath = import_node_path.default.resolve(currentWorkingDirectory, `.env.${environment}`);
428
- if (import_node_fs.default.existsSync(envSpecificPath)) {
429
- (0, import_dotenv2.config)({
430
- path: envSpecificPath,
431
- override: true
432
- });
455
+ /**
456
+ * Create a QR code for a specific short code.
457
+ * @param {string} code The short code to create a QR code for.
458
+ * @param {CreateQrCodeOptions} options The options for creating the QR code.
459
+ * @returns {Promise<CreateQrCodeResponse>} A promise that resolves to the created QR code details.
460
+ */
461
+ async createQrCode(code, options) {
462
+ if (!this._organizationId) {
463
+ throw new Error("Organization ID is required to create a QR code.");
433
464
  }
434
- if (local) {
435
- const envLocalPath = import_node_path.default.resolve(currentWorkingDirectory, `.env.${environment}.local`);
436
- if (import_node_fs.default.existsSync(envLocalPath)) {
437
- (0, import_dotenv2.config)({
438
- path: envLocalPath,
439
- override: true
440
- });
465
+ const url = this.getUri(this._organizationId, code, "qrs");
466
+ const headers = this.createHeaders(this._apiKey);
467
+ const body = {
468
+ title: options?.title,
469
+ backgroundColor: options?.backgroundColor,
470
+ color: options?.color,
471
+ size: options?.size,
472
+ logo: options?.logo
473
+ };
474
+ const response = await this.post(url, body, {
475
+ headers
476
+ });
477
+ if (response.status === 201) {
478
+ const result = response.data;
479
+ if (result.qrCode) {
480
+ const buffer = import_node_buffer.Buffer.from(result.qrCode, "base64");
481
+ result.qrCodeBytes = new Uint16Array(buffer);
441
482
  }
483
+ return result;
442
484
  }
485
+ throw new Error(`Failed to create QR code: ${response.statusText}`);
443
486
  }
444
- }
445
- __name(loadEnv, "loadEnv");
446
-
447
- // src/hyphen.ts
448
- var import_hookified3 = require("hookified");
449
-
450
- // src/net-info.ts
451
- var import_node_process3 = __toESM(require("process"), 1);
452
-
453
- // src/base-service.ts
454
- var import_hookified2 = require("hookified");
455
- var import_cacheable = require("cacheable");
456
- var import_axios = __toESM(require("axios"), 1);
457
- var import_pino = __toESM(require("pino"), 1);
458
- var ErrorMessages = /* @__PURE__ */ function(ErrorMessages2) {
459
- ErrorMessages2["API_KEY_REQUIRED"] = "API key is required. Please provide it via options or set the HYPHEN_API_KEY environment variable.";
460
- ErrorMessages2["PUBLIC_API_KEY_SHOULD_NOT_BE_USED"] = "The provided API key is a public API key. Please provide a valid non public API key for authentication.";
461
- return ErrorMessages2;
462
- }({});
463
- var BaseService = class extends import_hookified2.Hookified {
464
- static {
465
- __name(this, "BaseService");
466
- }
467
- _log = (0, import_pino.default)();
468
- _cache = new import_cacheable.Cacheable();
469
- _throwErrors = false;
470
- constructor(options) {
471
- super(options);
472
- if (options && options.throwErrors !== void 0) {
473
- this._throwErrors = options.throwErrors;
487
+ /**
488
+ * Get a QR code by its ID.
489
+ * @param code The short code associated with the QR code.
490
+ * @param qr The ID of the QR code to retrieve.
491
+ * @returns The details of the requested QR code.
492
+ */
493
+ async getQrCode(code, qr) {
494
+ if (!this._organizationId) {
495
+ throw new Error("Organization ID is required to get a QR code.");
474
496
  }
475
- }
476
- get log() {
477
- return this._log;
478
- }
479
- set log(value) {
480
- this._log = value;
481
- }
482
- get cache() {
483
- return this._cache;
484
- }
485
- set cache(value) {
486
- this._cache = value;
487
- }
488
- get throwErrors() {
489
- return this._throwErrors;
490
- }
491
- set throwErrors(value) {
492
- this._throwErrors = value;
493
- }
494
- error(message, ...args) {
495
- this._log.error(message, ...args);
496
- this.emit("error", message, ...args);
497
- if (this.throwErrors) {
498
- throw new Error(message);
497
+ const url = this.getUri(this._organizationId, code, "qrs", qr);
498
+ const headers = this.createHeaders(this._apiKey);
499
+ const response = await this.get(url, {
500
+ headers
501
+ });
502
+ if (response.status === 200) {
503
+ const result = response.data;
504
+ if (result.qrCode) {
505
+ const buffer = import_node_buffer.Buffer.from(result.qrCode, "base64");
506
+ result.qrCodeBytes = new Uint16Array(buffer);
507
+ }
508
+ return result;
499
509
  }
510
+ throw new Error(`Failed to get QR code: ${response.statusText}`);
500
511
  }
501
- warn(message, ...args) {
502
- this._log.warn(message, ...args);
503
- this.emit("warn", message, ...args);
504
- }
505
- info(message, ...args) {
506
- this._log.info(message, ...args);
507
- this.emit("info", message, ...args);
508
- }
509
- async get(url, config2) {
510
- return import_axios.default.get(url, config2);
511
- }
512
- async post(url, data, config2) {
513
- return import_axios.default.post(url, data, config2);
514
- }
515
- async put(url, data, config2) {
516
- return import_axios.default.put(url, data, config2);
517
- }
518
- async delete(url, config2) {
519
- return import_axios.default.delete(url, config2);
520
- }
521
- async patch(url, data, config2) {
522
- return import_axios.default.patch(url, data, config2);
512
+ async getQrCodes(code, pageNumber, pageSize) {
513
+ if (!this._organizationId) {
514
+ throw new Error("Organization ID is required to get QR codes.");
515
+ }
516
+ const url = this.getUri(this._organizationId, code, "qrs");
517
+ const headers = this.createHeaders(this._apiKey);
518
+ const parameters = {};
519
+ if (pageNumber) {
520
+ parameters.pageNum = pageNumber.toString();
521
+ }
522
+ if (pageSize) {
523
+ parameters.pageSize = pageSize.toString();
524
+ }
525
+ const response = await this.get(url, {
526
+ headers,
527
+ params: parameters
528
+ });
529
+ if (response.status === 200) {
530
+ const result = response.data;
531
+ for (const qrCode of result.data) {
532
+ if (qrCode.qrCode) {
533
+ const buffer = import_node_buffer.Buffer.from(qrCode.qrCode, "base64");
534
+ qrCode.qrCodeBytes = new Uint16Array(buffer);
535
+ }
536
+ }
537
+ return result;
538
+ }
539
+ throw new Error(`Failed to get QR codes: ${response.statusText}`);
523
540
  }
524
- createHeaders(apiKey) {
525
- const headers = {
526
- "content-type": "application/json",
527
- accept: "application/json"
528
- };
529
- if (apiKey) {
530
- headers["x-api-key"] = apiKey;
541
+ /**
542
+ * Delete a QR code by its ID.
543
+ * @param {string} code The short code associated with the QR code.
544
+ * @param {string} qr The ID of the QR code to delete.
545
+ * @returns {Promise<boolean>} A promise that resolves to true if the QR code was deleted successfully, or false if it was not.
546
+ */
547
+ async deleteQrCode(code, qr) {
548
+ if (!this._organizationId) {
549
+ throw new Error("Organization ID is required to delete a QR code.");
531
550
  }
532
- return headers;
551
+ const url = this.getUri(this._organizationId, code, "qrs", qr);
552
+ const headers = this.createHeaders(this._apiKey);
553
+ const response = await this.delete(url, {
554
+ headers
555
+ });
556
+ if (response.status === 204) {
557
+ return true;
558
+ }
559
+ throw new Error(`Failed to delete QR code: ${response.statusText}`);
533
560
  }
534
561
  };
535
562
 
536
563
  // src/net-info.ts
537
- loadEnv();
564
+ var import_node_process3 = __toESM(require("process"), 1);
565
+ env();
538
566
  var NetInfo = class extends BaseService {
539
567
  static {
540
568
  __name(this, "NetInfo");
@@ -555,31 +583,31 @@ var NetInfo = class extends BaseService {
555
583
  }
556
584
  }
557
585
  /**
558
- * Gets or sets the API key for authentication.
559
- * If not set, it will try to use the `HYPHEN_API_KEY` environment variable.
560
- * @type {string | undefined}
561
- */
586
+ * Gets or sets the API key for authentication.
587
+ * If not set, it will try to use the `HYPHEN_API_KEY` environment variable.
588
+ * @type {string | undefined}
589
+ */
562
590
  get apiKey() {
563
591
  return this._apiKey;
564
592
  }
565
593
  /**
566
- * Sets the API key for authentication.
567
- * @param {string | undefined} value - The API key to set.
568
- */
594
+ * Sets the API key for authentication.
595
+ * @param {string | undefined} value - The API key to set.
596
+ */
569
597
  set apiKey(value) {
570
598
  this.setApiKey(value);
571
599
  }
572
600
  /**
573
- * Gets or sets the base URI for the API.
574
- * @type {string}
575
- */
601
+ * Gets or sets the base URI for the API.
602
+ * @type {string}
603
+ */
576
604
  get baseUri() {
577
605
  return this._baseUri;
578
606
  }
579
607
  /**
580
- * Sets the base URI for the API.
581
- * @param {string} value - The base URI to set.
582
- */
608
+ * Sets the base URI for the API.
609
+ * @param {string} value - The base URI to set.
610
+ */
583
611
  set baseUri(value) {
584
612
  this._baseUri = value;
585
613
  }
@@ -591,10 +619,10 @@ var NetInfo = class extends BaseService {
591
619
  this._apiKey = value;
592
620
  }
593
621
  /**
594
- * Fetches GeoIP information for a given IP address.
595
- * @param {string} ip - The IP address to fetch GeoIP information for.
596
- * @returns {Promise<ipInfo | ipInfoError>} - A promise that resolves to the ip information or an error.
597
- */
622
+ * Fetches GeoIP information for a given IP address.
623
+ * @param {string} ip - The IP address to fetch GeoIP information for.
624
+ * @returns {Promise<ipInfo | ipInfoError>} - A promise that resolves to the ip information or an error.
625
+ */
598
626
  async getIpInfo(ip) {
599
627
  try {
600
628
  if (!this._apiKey) {
@@ -661,188 +689,364 @@ var NetInfo = class extends BaseService {
661
689
  }
662
690
  };
663
691
 
664
- // src/link.ts
692
+ // src/toggle.ts
665
693
  var import_node_process4 = __toESM(require("process"), 1);
666
- loadEnv();
667
- var defaultLinkUris = [
668
- "https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"
669
- ];
670
- var Link = class extends BaseService {
694
+ var import_openfeature_server_provider = require("@hyphen/openfeature-server-provider");
695
+ var import_server_sdk = require("@openfeature/server-sdk");
696
+ var import_dotenv2 = __toESM(require("dotenv"), 1);
697
+ var import_hookified2 = require("hookified");
698
+ import_dotenv2.default.config();
699
+ var ToggleHooks = /* @__PURE__ */ function(ToggleHooks2) {
700
+ ToggleHooks2["beforeGetBoolean"] = "beforeGetBoolean";
701
+ ToggleHooks2["afterGetBoolean"] = "afterGetBoolean";
702
+ ToggleHooks2["beforeGetString"] = "beforeGetString";
703
+ ToggleHooks2["afterGetString"] = "afterGetString";
704
+ ToggleHooks2["beforeGetNumber"] = "beforeGetNumber";
705
+ ToggleHooks2["afterGetNumber"] = "afterGetNumber";
706
+ ToggleHooks2["beforeGetObject"] = "beforeGetObject";
707
+ ToggleHooks2["afterGetObject"] = "afterGetObject";
708
+ return ToggleHooks2;
709
+ }({});
710
+ var Toggle = class extends import_hookified2.Hookified {
671
711
  static {
672
- __name(this, "Link");
712
+ __name(this, "Toggle");
673
713
  }
674
- _uris = defaultLinkUris;
675
- _organizationId;
676
- _apiKey;
714
+ _applicationId = import_node_process4.default.env.HYPHEN_APPLICATION_ID;
715
+ _publicApiKey = import_node_process4.default.env.HYPHEN_PUBLIC_API_KEY;
716
+ _environment;
717
+ _client;
718
+ _context;
719
+ _throwErrors = false;
720
+ _uris;
721
+ _caching;
722
+ /*
723
+ * Create a new Toggle instance. This will create a new client and set the options.
724
+ * @param {ToggleOptions}
725
+ */
677
726
  constructor(options) {
678
- super(options);
679
- this._uris = options?.uris ?? defaultLinkUris;
680
- this._organizationId = options?.organizationId;
681
- if (options?.apiKey) {
682
- this.setApiKey(options.apiKey);
683
- }
684
- if (!this._apiKey && import_node_process4.default.env.HYPHEN_API_KEY) {
685
- this.setApiKey(import_node_process4.default.env.HYPHEN_API_KEY);
686
- }
687
- if (!this._organizationId && import_node_process4.default.env.HYPHEN_ORGANIZATION_ID) {
688
- this._organizationId = import_node_process4.default.env.HYPHEN_ORGANIZATION_ID;
727
+ super();
728
+ this._throwErrors = options?.throwErrors ?? false;
729
+ this._applicationId = options?.applicationId;
730
+ if (options?.publicApiKey) {
731
+ this.setPublicApiKey(options.publicApiKey);
689
732
  }
733
+ this._environment = options?.environment ?? import_node_process4.default.env.NODE_ENV ?? "development";
734
+ this._context = options?.context;
735
+ this._uris = options?.uris;
736
+ this._caching = options?.caching;
690
737
  }
691
738
  /**
692
- * Get the URIs for the link service. The default is `["https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"]`.
693
- * @returns {string[]} The URIs for the link service.
739
+ * Get the application ID
740
+ * @returns {string | undefined}
694
741
  */
695
- get uris() {
696
- return this._uris;
742
+ get applicationId() {
743
+ return this._applicationId;
697
744
  }
698
745
  /**
699
- * Set the URIs for the link service. The default is `["https://api.hyphen.ai/api/organizations/{organizationId}/link/codes/"]`.
700
- * @param {string[]} uris - The URIs to set.
746
+ * Set the application ID
747
+ * @param {string | undefined} value
701
748
  */
702
- set uris(uris) {
703
- this._uris = uris;
749
+ set applicationId(value) {
750
+ this._applicationId = value;
704
751
  }
705
752
  /**
706
- * Get the organization ID for the link service. This is required to access the link service.
707
- * @returns {string | undefined} The organization ID.
753
+ * Get the public API key
754
+ * @returns {string}
708
755
  */
709
- get organizationId() {
710
- return this._organizationId;
756
+ get publicApiKey() {
757
+ return this._publicApiKey;
711
758
  }
712
759
  /**
713
- * Set the organization ID for the link service. This is required to access the link service.
714
- * @param {string | undefined} organizationId - The organization ID to set.
760
+ * Set the public API key
761
+ * @param {string} value
715
762
  */
716
- set organizationId(organizationId) {
717
- this._organizationId = organizationId;
763
+ set publicApiKey(value) {
764
+ if (!value) {
765
+ this._publicApiKey = void 0;
766
+ this._client = void 0;
767
+ return;
768
+ }
769
+ this.setPublicApiKey(value);
718
770
  }
719
771
  /**
720
- * Get the API key for the link service. This is required to access the link service.
721
- * @returns {string | undefined} The API key.
772
+ * Get the environment
773
+ * @returns {string}
722
774
  */
723
- get apiKey() {
724
- return this._apiKey;
775
+ get environment() {
776
+ return this._environment;
725
777
  }
726
778
  /**
727
- * Set the API key for the link service. This is required to access the link service.
728
- * @param {string | undefined} apiKey - The API key to set.
779
+ * Set the environment
780
+ * @param {string} value
729
781
  */
730
- set apiKey(apiKey) {
731
- this.setApiKey(apiKey);
782
+ set environment(value) {
783
+ this._environment = value;
732
784
  }
733
785
  /**
734
- * Set the API key for the link service. If the API key starts with 'public_', an error is thrown.
735
- * This is to ensure that the API key is not a public key, which should not be used for authenticated requests.
736
- * @param {string} apiKey
786
+ * Get the throwErrors. If true, errors will be thrown in addition to being emitted.
787
+ * @returns {boolean}
737
788
  */
738
- setApiKey(apiKey) {
739
- if (apiKey?.startsWith("public_")) {
740
- throw new Error('API key cannot start with "public_"');
741
- }
742
- if (apiKey) {
743
- this._apiKey = apiKey;
744
- }
789
+ get throwErrors() {
790
+ return this._throwErrors;
745
791
  }
746
792
  /**
747
- * Get the URI for a specific organization and code. This is used internally to construct the URI for the link service.
748
- * @param {string} organizationId The ID of the organization.
749
- * @param {string} code The code to include in the URI.
750
- * @returns {string} The constructed URI.
793
+ * Set the throwErrors. If true, errors will be thrown in addition to being emitted.
794
+ * @param {boolean} value
751
795
  */
752
- getUri(organizationId, code) {
753
- if (!organizationId) {
754
- throw new Error("Organization ID is required to get the URI.");
755
- }
756
- let url = this._uris[0].replace("{organizationId}", organizationId);
757
- if (code) {
758
- url = url.endsWith("/") ? `${url}${code}/` : `${url}/${code}/`;
759
- }
760
- return url;
796
+ set throwErrors(value) {
797
+ this._throwErrors = value;
761
798
  }
762
- async createShortCode(longUrl, domain, options) {
763
- if (!this._organizationId) {
764
- throw new Error("Organization ID is required to create a short code.");
765
- }
766
- const url = this.getUri(this._organizationId);
767
- const body = {
768
- // eslint-disable-next-line @typescript-eslint/naming-convention
769
- long_url: longUrl,
770
- domain,
771
- code: options?.code,
772
- title: options?.title,
773
- tags: options?.tags
774
- };
775
- const headers = this.createHeaders(this._apiKey);
776
- const response = await this.post(url, body, {
777
- headers
778
- });
779
- if (response.status === 201) {
780
- return response.data;
781
- }
782
- throw new Error(`Failed to create short code: ${response.statusText}`);
799
+ /**
800
+ * Get the current context. This is the default context used. You can override this at the get function level.
801
+ * @returns {ToggleContext}
802
+ */
803
+ get context() {
804
+ return this._context;
783
805
  }
784
806
  /**
785
- * Get a short code by its code.
786
- * @param {string} code The short code to retrieve. Example: 'code_686bed403c3991bd676bba4d'
787
- * @returns {Promise<GetShortCodeResponse>} A promise that resolves to the short code details.
807
+ * Set the context. This is the default context used. You can override this at the get function level.
808
+ * @param {ToggleContext} value
788
809
  */
789
- async getShortCode(code) {
790
- if (!this._organizationId) {
791
- throw new Error("Organization ID is required to get a short code.");
810
+ set context(value) {
811
+ this._context = value;
812
+ }
813
+ /**
814
+ * Get the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
815
+ * @returns {Array<string>}
816
+ */
817
+ get uris() {
818
+ return this._uris;
819
+ }
820
+ /**
821
+ * Set the URIs. This is used to override the default URIs for testing or if you are using a self-hosted version.
822
+ * @param {Array<string>} value
823
+ */
824
+ set uris(value) {
825
+ this._uris = value;
826
+ }
827
+ /**
828
+ * Get the caching options.
829
+ * @returns {ToggleCachingOptions | undefined}
830
+ */
831
+ get caching() {
832
+ return this._caching;
833
+ }
834
+ /**
835
+ * Set the caching options.
836
+ * @param {ToggleCachingOptions | undefined} value
837
+ */
838
+ set caching(value) {
839
+ this._caching = value;
840
+ }
841
+ /**
842
+ * 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
843
+ * does set it will also set the client to undefined to force a new one to be created. If it does not,
844
+ * it will emit an error and console warning and not set the key. Used by the constructor and publicApiKey setter.
845
+ * @param key
846
+ * @returns
847
+ */
848
+ setPublicApiKey(key) {
849
+ if (!key.startsWith("public_")) {
850
+ this.emit("error", new Error("Public API key should start with public_"));
851
+ if (import_node_process4.default.env.NODE_ENV !== "production") {
852
+ console.error("Public API key should start with public_");
853
+ }
854
+ return;
792
855
  }
793
- const url = this.getUri(this._organizationId, code);
794
- const headers = this.createHeaders(this._apiKey);
795
- const response = await this.get(url, {
796
- headers
797
- });
798
- if (response.status === 200) {
799
- return response.data;
856
+ this._publicApiKey = key;
857
+ this._client = void 0;
858
+ }
859
+ /**
860
+ * Set the context. This is the default context used. You can override this at the get function level.
861
+ * @param {ToggleContext} context
862
+ */
863
+ setContext(context) {
864
+ this._context = context;
865
+ this._client = void 0;
866
+ }
867
+ /**
868
+ * Helper function to get the client. This will create a new client if one does not exist. It will also set the
869
+ * application ID, environment, and URIs if they are not set. This is used by the get function to get the client.
870
+ * This is normally only used internally.
871
+ * @returns {Promise<Client>}
872
+ */
873
+ async getClient() {
874
+ if (!this._client) {
875
+ if (this._applicationId === void 0 || this._applicationId.length === 0) {
876
+ const errorMessage = "Application ID is not set. You must set it before using the client or have the HYPHEN_APPLICATION_ID environment variable set.";
877
+ this.emit("error", new Error(errorMessage));
878
+ if (this._throwErrors) {
879
+ throw new Error(errorMessage);
880
+ }
881
+ }
882
+ const options = {
883
+ application: this._applicationId,
884
+ environment: this._environment,
885
+ horizonUrls: this._uris,
886
+ cache: this._caching
887
+ };
888
+ if (this._publicApiKey && this._publicApiKey.length > 0) {
889
+ await import_server_sdk.OpenFeature.setProviderAndWait(new import_openfeature_server_provider.HyphenProvider(this._publicApiKey, options));
890
+ } else {
891
+ 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."));
892
+ if (this._throwErrors) {
893
+ throw new Error("Public API key is not set");
894
+ }
895
+ }
896
+ this._client = import_server_sdk.OpenFeature.getClient(this._context);
800
897
  }
801
- throw new Error(`Failed to get short code: ${response.statusText}`);
898
+ return this._client;
802
899
  }
803
- async getShortCodes(titleSearch, tags, pageNumber = 1, pageSize = 100) {
804
- if (!this._organizationId) {
805
- throw new Error("Organization ID is required to get short codes.");
900
+ /**
901
+ * This is the main function to get a feature flag value. It will check the type of the default value and call the
902
+ * appropriate function. It will also set the context if it is not set.
903
+ * @param {string} key - The key of the feature flag
904
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
905
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
906
+ * @returns {Promise<T>}
907
+ */
908
+ async get(key, defaultValue, options) {
909
+ switch (typeof defaultValue) {
910
+ case "boolean": {
911
+ return this.getBoolean(key, defaultValue, options);
912
+ }
913
+ case "string": {
914
+ return this.getString(key, defaultValue, options);
915
+ }
916
+ case "number": {
917
+ return this.getNumber(key, defaultValue, options);
918
+ }
919
+ default: {
920
+ return this.getObject(key, defaultValue, options);
921
+ }
806
922
  }
807
- const url = this.getUri(this._organizationId);
808
- const headers = this.createHeaders(this._apiKey);
809
- const parameters = {};
810
- if (titleSearch) {
811
- parameters.title = titleSearch;
923
+ }
924
+ /**
925
+ * Get a boolean value from the feature flag. This will check the type of the default value and call the
926
+ * appropriate function. It will also set the context if it is not set.
927
+ * @param {string} key - The key of the feature flag
928
+ * @param {boolean} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
929
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
930
+ * @returns {Promise<boolean>} - The value of the feature flag
931
+ */
932
+ async getBoolean(key, defaultValue, options) {
933
+ try {
934
+ const data = {
935
+ key,
936
+ defaultValue,
937
+ options
938
+ };
939
+ await this.hook("beforeGetBoolean", data);
940
+ const client = await this.getClient();
941
+ const result = await client.getBooleanValue(data.key, data.defaultValue, data.options?.context);
942
+ const resultData = {
943
+ key,
944
+ defaultValue,
945
+ options,
946
+ result
947
+ };
948
+ await this.hook("afterGetBoolean", resultData);
949
+ return resultData.result;
950
+ } catch (error) {
951
+ this.emit("error", error);
952
+ if (this._throwErrors) {
953
+ throw error;
954
+ }
812
955
  }
813
- if (tags && tags.length > 0) {
814
- parameters.tags = tags.join(",");
956
+ return defaultValue;
957
+ }
958
+ /**
959
+ * Get a string value from the feature flag.
960
+ * @param {string} key - The key of the feature flag
961
+ * @param {string} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
962
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
963
+ * @returns {Promise<string>} - The value of the feature flag
964
+ */
965
+ async getString(key, defaultValue, options) {
966
+ try {
967
+ const data = {
968
+ key,
969
+ defaultValue,
970
+ options
971
+ };
972
+ await this.hook("beforeGetString", data);
973
+ const client = await this.getClient();
974
+ const result = await client.getStringValue(data.key, data.defaultValue, data.options?.context);
975
+ const resultData = {
976
+ key,
977
+ defaultValue,
978
+ options,
979
+ result
980
+ };
981
+ await this.hook("afterGetString", resultData);
982
+ return resultData.result;
983
+ } catch (error) {
984
+ this.emit("error", error);
985
+ if (this._throwErrors) {
986
+ throw error;
987
+ }
815
988
  }
816
- parameters.pageNum = pageNumber.toString();
817
- parameters.pageSize = pageSize.toString();
818
- const response = await this.get(url, {
819
- headers,
820
- params: parameters
821
- });
822
- if (response.status === 200) {
823
- return response.data;
989
+ return defaultValue;
990
+ }
991
+ async getNumber(key, defaultValue, options) {
992
+ try {
993
+ const data = {
994
+ key,
995
+ defaultValue,
996
+ options
997
+ };
998
+ await this.hook("beforeGetNumber", data);
999
+ const client = await this.getClient();
1000
+ const result = await client.getNumberValue(data.key, data.defaultValue, data.options?.context);
1001
+ const resultData = {
1002
+ key,
1003
+ defaultValue,
1004
+ options,
1005
+ result
1006
+ };
1007
+ await this.hook("afterGetNumber", resultData);
1008
+ return resultData.result;
1009
+ } catch (error) {
1010
+ this.emit("error", error);
1011
+ if (this._throwErrors) {
1012
+ throw error;
1013
+ }
824
1014
  }
825
- throw new Error(`Failed to get short codes: ${response.statusText}`);
1015
+ return defaultValue;
826
1016
  }
827
1017
  /**
828
- * Delete a short code.
829
- * @param {string} code The short code to delete. Example: 'code_686bed403c3991bd676bba4d'
830
- * @returns {Promise<boolean>} A promise that resolves to true if the short code was deleted successfully, or false if it was not.
1018
+ * Get an object value from the feature flag. This will check the type of the default value and call the
1019
+ * appropriate function. It will also set the context if it is not set.
1020
+ * @param {string} key - The key of the feature flag
1021
+ * @param {T} defaultValue - The default value to return if the feature flag is not set or does not evaluate.
1022
+ * @param {ToggleRequestOptions} options - The options to use for the request. This can be used to override the context.
1023
+ * @returns {Promise<T>} - The value of the feature flag
831
1024
  */
832
- async deleteShortCode(code) {
833
- if (!this._organizationId) {
834
- throw new Error("Organization ID is required to delete a short code.");
835
- }
836
- const url = this.getUri(this._organizationId, code);
837
- const headers = this.createHeaders(this._apiKey);
838
- delete headers["content-type"];
839
- const response = await this.delete(url, {
840
- headers
841
- });
842
- if (response.status === 204) {
843
- return true;
1025
+ async getObject(key, defaultValue, options) {
1026
+ try {
1027
+ const data = {
1028
+ key,
1029
+ defaultValue,
1030
+ options
1031
+ };
1032
+ await this.hook("beforeGetObject", data);
1033
+ const client = await this.getClient();
1034
+ const result = await client.getObjectValue(key, defaultValue, data.options?.context);
1035
+ const resultData = {
1036
+ key,
1037
+ defaultValue,
1038
+ options,
1039
+ result
1040
+ };
1041
+ await this.hook("afterGetObject", resultData);
1042
+ return resultData.result;
1043
+ } catch (error) {
1044
+ this.emit("error", error);
1045
+ if (this._throwErrors) {
1046
+ throw error;
1047
+ }
844
1048
  }
845
- throw new Error(`Failed to delete short code: ${response.statusText}`);
1049
+ return defaultValue;
846
1050
  }
847
1051
  };
848
1052
 
@@ -968,5 +1172,6 @@ var Hyphen = class extends import_hookified3.Hookified {
968
1172
  Hyphen,
969
1173
  Toggle,
970
1174
  ToggleHooks,
1175
+ env,
971
1176
  loadEnv
972
1177
  });