@storecraft/sdk 1.0.14 → 1.0.16

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { StorecraftSDKConfig } from './types.js'
2
+ * @import { Fetcher, StorecraftSDKConfig } from './types.js'
3
3
  */
4
4
  import Auth from './src/auth.js'
5
5
  import Customers from './src/customers.js'
@@ -21,7 +21,10 @@ import Notifications from './src/notifications.js'
21
21
  import Storage from './src/storage.js'
22
22
  import AI from './src/ai.js'
23
23
  import Search from './src/search.js'
24
- import { fetchApiWithAuth, fetchOnlyApiResponseWithAuth } from './src/utils.api.fetch.js'
24
+ import {
25
+ fetchApiWithAuth, fetchOnlyApiResponseWithAuth
26
+ } from './src/utils.api.fetch.js'
27
+ import Email from './src/email.js'
25
28
 
26
29
  /**
27
30
  * @description The official `storecraft` universal **SDK** for `javascript`
@@ -29,13 +32,19 @@ import { fetchApiWithAuth, fetchOnlyApiResponseWithAuth } from './src/utils.api.
29
32
  export class StorecraftSDK {
30
33
 
31
34
  /**@type {StorecraftSDKConfig} */
32
- #_config = undefined;
35
+ #config = undefined;
36
+ /**@type {Fetcher} */
37
+ #fetcher = undefined;
33
38
 
34
39
  /**
35
- * @param {StorecraftSDKConfig} [config]
40
+ * @param {StorecraftSDKConfig} [config] the `sdk` configuration
41
+ * @param {Fetcher} [fetcher] Alternative `fetch` implementation.
42
+ * This is useful for testing purposes, or if you want to use a
43
+ * different `fetch` implementation
36
44
  */
37
- constructor(config) {
38
- this.#_config = config;
45
+ constructor(config, fetcher) {
46
+ this.#config = config;
47
+ this.#fetcher = fetcher ?? ((input, init) => fetch(input, init));
39
48
 
40
49
  this.ai = new AI(this);
41
50
  this.search = new Search(this);
@@ -57,8 +66,13 @@ export class StorecraftSDK {
57
66
  this.checkout = new Checkout(this);
58
67
  this.settings = new Settings(this);
59
68
  this.notifications = new Notifications(this);
69
+ this.emails = new Email(this);
60
70
  }
61
71
 
72
+ get fetcher() {
73
+ return this.#fetcher
74
+ }
75
+
62
76
  /**
63
77
  * @description
64
78
  * - Prepends `backend` endpoint.
@@ -66,15 +80,11 @@ export class StorecraftSDK {
66
80
  * - Refreshed `auth` if needed.
67
81
  * - Throws a `json` representation of the `error`,
68
82
  * if the request is `bad`
69
- *
70
83
  * @template {any} [R=any]
71
- *
72
84
  * @param {string} path relative path in api
73
85
  * @param {RequestInit} [init] request `init` type
74
86
  * @param {URLSearchParams} [query] url search params
75
- *
76
87
  * @throws {error}
77
- *
78
88
  * @returns {Promise<R>}
79
89
  */
80
90
  fetchApiWithAuth = (path, init, query) => {
@@ -88,11 +98,9 @@ export class StorecraftSDK {
88
98
  * - Prepends `backend` endpoint.
89
99
  * - Fetches with `authentication` middleware.
90
100
  * - Refreshed `auth` if needed.
91
- *
92
101
  * @param {string} path relative path in api
93
102
  * @param {RequestInit} [init] request `init` type
94
103
  * @param {URLSearchParams} [query] url search params
95
- *
96
104
  * @returns {Promise<Response>}
97
105
  */
98
106
  fetchOnlyApiResponseWithAuth = (path, init, query) => {
@@ -105,13 +113,14 @@ export class StorecraftSDK {
105
113
  * @param {StorecraftSDKConfig} [config]
106
114
  */
107
115
  updateConfig(config) {
108
- this.#_config = config;
116
+ this.#config = {
117
+ ...config
118
+ };
109
119
  }
110
120
 
111
121
  get config() {
112
- return this.#_config
122
+ return this.#config
113
123
  }
114
-
115
124
  }
116
125
 
117
126
  /**
@@ -126,7 +135,6 @@ export const validateConfig = (config) => {
126
135
  */
127
136
  export const create = (config) => {
128
137
  const sdk = new StorecraftSDK(config);
129
-
130
138
  return sdk;
131
139
  }
132
140
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storecraft/sdk",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "Official storecraft Universal Javascript SDK",
5
5
  "license": "MIT",
6
6
  "author": "Tomer Shalev (https://github.com/store-craft)",
package/src/ai.js CHANGED
@@ -21,11 +21,11 @@ const HEADER_STORECRAFT_THREAD_ID = /** @satisfies {HEADER_STORECRAFT_THREAD_ID_
21
21
  export default class AI {
22
22
 
23
23
  /**
24
- *
25
24
  * @param {StorecraftSDK} sdk
26
25
  */
27
26
  constructor(sdk) {
28
27
  this.sdk = sdk;
28
+
29
29
  }
30
30
 
31
31
  /**
@@ -36,7 +36,7 @@ export default class AI {
36
36
  * @returns {Promise<AgentRunResponse>}
37
37
  */
38
38
  speak = async (agent_handle, params) => {
39
- const response = await fetch(
39
+ const response = await this.sdk.fetcher(
40
40
  url(this.sdk.config, `ai/agents/${agent_handle}/run`),
41
41
  {
42
42
  method: 'post',
@@ -55,8 +55,9 @@ export default class AI {
55
55
  * @param {string} agent_handle agent identifier
56
56
  * @param {AgentRunParameters} params
57
57
  */
58
- streamSpeak = async function(agent_handle, params) {
59
- const response = await fetch(
58
+ streamSpeak = async (agent_handle, params) => {
59
+
60
+ const response = await this.sdk.fetcher(
60
61
  url(this.sdk.config, `ai/agents/${agent_handle}/stream`),
61
62
  {
62
63
  method: 'post',
@@ -160,7 +161,6 @@ export const SSEGenerator = async function *(stream) {
160
161
  */
161
162
 
162
163
  /**
163
- *
164
164
  * @param {string[]} lines
165
165
  * @returns {SSEFrame}
166
166
  */
package/src/auth.js CHANGED
@@ -8,9 +8,13 @@
8
8
  * @import { SdkConfigAuth } from '../types.js';
9
9
  */
10
10
 
11
- import { api_query_to_searchparams } from '@storecraft/core/api/utils.query.js';
11
+ import {
12
+ api_query_to_searchparams
13
+ } from '@storecraft/core/api/utils.query.js';
12
14
  import { StorecraftSDK } from '../index.js';
13
- import { count_query_of_resource, fetchApiWithAuth, url } from './utils.api.fetch.js';
15
+ import {
16
+ count_query_of_resource, fetchApiWithAuth, url
17
+ } from './utils.api.fetch.js';
14
18
  import { assert } from './utils.functional.js';
15
19
 
16
20
 
@@ -22,14 +26,12 @@ import { assert } from './utils.functional.js';
22
26
  *
23
27
  * @typedef {(payload: SubscriberCallbackPayload) => void
24
28
  * } SubscriberCallback Subscribe to `auth` updates for `JWT` auth
25
- *
26
29
  */
27
30
 
28
31
 
29
32
  /**
30
33
  * @description `Storecraft` authentication module:
31
34
  * - Supports `subscribtion` to `auth` events
32
- *
33
35
  */
34
36
  export default class Auth {
35
37
 
@@ -48,13 +50,11 @@ export default class Auth {
48
50
  }
49
51
 
50
52
  /**
51
- *
52
53
  * @description Get the current `auth` config, which is one of:
53
- *
54
54
  * 1. `JWT` with `access_token`, `refresh_token`, `claims`
55
55
  * 2. `Api Key` with a single value, which can be used as is in:
56
- * - `Authorization: Basic <api-key>`, or
57
- * - `X-API-KEY: <api-key>`
56
+ * - `Authorization: Basic <api-key>`, or
57
+ * - `X-API-KEY: <api-key>`
58
58
  *
59
59
  * Notes:
60
60
  *
@@ -64,7 +64,6 @@ export default class Auth {
64
64
  * **Api Key** represents a user which always makes the `backend` to verify
65
65
  * the authentication and authorization and therefore may be slower, because
66
66
  * the `backend` will verify against the database.
67
- *
68
67
  */
69
68
  get currentAuth() {
70
69
  return this.#sdk?.config?.auth;
@@ -82,42 +81,38 @@ export default class Auth {
82
81
  }
83
82
 
84
83
  /**
85
- *
86
84
  * @description Get a working token, by the following strategy:
87
- *
88
85
  * - If you are in `JWT` strategy:
89
- * - If the current `access_token` will expire soon or is already expired
90
- * - then, use `refresh_token` to re-authenticate
91
- *
86
+ * - If the current `access_token` will expire soon or is already expired
87
+ * - then, use `refresh_token` to re-authenticate
92
88
  * - If you are in `Api Key` strategy, simply returns the `apikey`
93
- *
94
89
  * @param {boolean} [force_reauth=false]
95
- *
96
90
  */
97
91
  async working_auth_token(force_reauth=false) {
98
- if(this.currentAuth) {
99
- if('apikey' in this.currentAuth) {
100
- return this.currentAuth.apikey;
92
+ // console.log({currentAuthStrategy: this.currentAuthStrategy})
93
+
94
+ switch(this.currentAuthStrategy) {
95
+ case 'apikey': {
96
+ const auth = /** @type {ApiKeyResult} */(this.currentAuth);
97
+ return auth?.apikey;
101
98
  }
102
- else if('access_token' in this.currentAuth) {
99
+ case 'jwt': {
100
+ const auth = /** @type {ApiAuthResult} */(this.currentAuth);
103
101
  if(force_reauth || !this.isAuthenticated)
104
102
  await this.reAuthenticateIfNeeded(force_reauth);
105
- return this.currentAuth.access_token.token;
103
+ return auth?.access_token?.token;
104
+ }
105
+ default: {
106
106
  }
107
107
  }
108
-
109
108
  return undefined;
110
109
  }
111
110
 
112
111
 
113
112
  /**
114
- *
115
113
  * @description Perform re-authentication for `JWT` auth, which means:
116
- *
117
114
  * - use the `refresh_token` to gain a new `access_token`
118
- *
119
115
  * @param {boolean} [force=false]
120
- *
121
116
  */
122
117
  async reAuthenticateIfNeeded(force=false) {
123
118
  if(!this.currentAuth)
@@ -127,7 +122,7 @@ export default class Auth {
127
122
  return;
128
123
 
129
124
  if('access_token' in this.currentAuth) {
130
- const auth_res = await fetch(
125
+ const auth_res = await this.#sdk.fetcher(
131
126
  url(this.#sdk.config, '/auth/refresh'),
132
127
  {
133
128
  method: 'post',
@@ -149,7 +144,7 @@ export default class Auth {
149
144
  payload = await auth_res.json();
150
145
  }
151
146
 
152
- this.#_update_and_notify_subscribers(payload);
147
+ this.#update_and_notify_subscribers(payload);
153
148
 
154
149
  return payload;
155
150
  }
@@ -180,49 +175,49 @@ export default class Auth {
180
175
  }
181
176
  }
182
177
 
183
- get authStrategy() {
184
- if(this.currentAuth) {
178
+ get currentAuthStrategy() {
179
+ // console.log({currentAuthStrategy:this.currentAuth})
180
+
181
+ if(
182
+ this.currentAuth &&
183
+ (typeof this.currentAuth === 'object')
184
+ ) {
185
185
  if('apikey' in this.currentAuth)
186
186
  return 'apikey';
187
187
  else if('access_token' in this.currentAuth)
188
188
  return 'jwt';
189
189
  }
190
-
191
190
  return 'unknown';
192
191
  }
193
192
 
194
193
  get isAuthenticated() {
195
-
196
- if(this.currentAuth) {
197
- if('apikey' in this.currentAuth) {
198
- return Boolean(this.currentAuth.apikey);
194
+ switch(this.currentAuthStrategy) {
195
+ case 'apikey': {
196
+ const auth = /** @type {ApiKeyResult} */(this.currentAuth);
197
+ return Boolean(auth.apikey);
199
198
  }
200
- else if('access_token' in this.currentAuth) {
201
- const exp = this.currentAuth?.access_token?.claims?.exp;
202
-
203
- return exp && (Date.now() < (exp - 60)*1000);
199
+ case 'jwt': {
200
+ const auth = /** @type {ApiAuthResult} */(this.currentAuth);
201
+ const exp = auth?.access_token?.claims?.exp;
202
+ return exp && (Date.now() < (exp - 60)*1000);
204
203
  }
204
+ default:
205
+ return false;
205
206
  }
206
-
207
- return false;
208
207
  }
209
208
 
210
209
  /**
211
- *
212
210
  * @param {ApiAuthResult} user
213
211
  */
214
- #_update_and_notify_subscribers = (user) => {
212
+ #update_and_notify_subscribers = (user) => {
215
213
  this.currentAuth = user
216
214
  this.notify_subscribers();
217
215
  }
218
216
 
219
217
 
220
218
  /**
221
- *
222
219
  * @param {string} email
223
220
  * @param {string} password
224
- *
225
- *
226
221
  * @returns {Promise<ApiAuthResult>}
227
222
  */
228
223
  signin = async (email, password) => {
@@ -233,7 +228,7 @@ export default class Auth {
233
228
  email, password
234
229
  }
235
230
 
236
- const res = await fetch(
231
+ const res = await this.#sdk.fetcher(
237
232
  url(this.#sdk.config, `/auth/signin`),
238
233
  {
239
234
  method: 'post',
@@ -260,24 +255,22 @@ export default class Auth {
260
255
  }
261
256
 
262
257
  throw error_payload;
263
- }
258
+ }
259
+
264
260
  // assert(res.ok, 'auth/error2');
265
261
 
266
262
  /** @type {ApiAuthResult} */
267
263
  const payload = await res.json();
268
-
269
- // console.log('auth_result', payload)
270
-
271
- this.#_update_and_notify_subscribers(
264
+
265
+ this.#update_and_notify_subscribers(
272
266
  payload
273
267
  );
274
-
268
+
275
269
  return payload;
276
270
  }
277
271
 
278
272
 
279
273
  /**
280
- *
281
274
  * @param {string} email
282
275
  * @param {string} password
283
276
  * @param {string} [firstname]
@@ -290,7 +283,7 @@ export default class Auth {
290
283
  firstname, lastname
291
284
  }
292
285
 
293
- const res = await fetch(
286
+ const res = await this.#sdk.fetcher(
294
287
  url(this.#sdk.config, `/auth/signup`),
295
288
  {
296
289
  method: 'post',
@@ -306,7 +299,7 @@ export default class Auth {
306
299
  /** @type {ApiAuthResult} */
307
300
  const payload = await res.json();
308
301
 
309
- this.#_update_and_notify_subscribers(
302
+ this.#update_and_notify_subscribers(
310
303
  payload
311
304
  );
312
305
 
@@ -315,13 +308,11 @@ export default class Auth {
315
308
 
316
309
 
317
310
  /**
318
- *
319
311
  * @param {ApiAuthChangePasswordType} params
320
312
  */
321
-
322
313
  changePassword = async (params) => {
323
314
 
324
- const res = await fetch(
315
+ const res = await this.#sdk.fetcher(
325
316
  url(this.#sdk.config, `/auth/change-password`),
326
317
  {
327
318
  method: 'post',
@@ -353,25 +344,21 @@ export default class Auth {
353
344
  /** @type {ApiAuthResult} */
354
345
  const payload = await res.json();
355
346
 
356
- this.#_update_and_notify_subscribers(
347
+ this.#update_and_notify_subscribers(
357
348
  payload
358
349
  );
359
350
 
360
351
  return payload;
361
352
  }
362
353
 
363
-
364
-
365
354
  signout = async () => {
366
355
  console.log('signout');
367
356
 
368
- this.#_update_and_notify_subscribers(
357
+ this.#update_and_notify_subscribers(
369
358
  undefined
370
359
  );
371
-
372
360
  }
373
361
 
374
-
375
362
  create_api_key = async () => {
376
363
  /** @type {ApiKeyResult} */
377
364
  const item = await fetchApiWithAuth(
@@ -381,14 +368,10 @@ export default class Auth {
381
368
  method: 'post',
382
369
  }
383
370
  );
384
-
385
- return item.apikey;
371
+ return item;
386
372
  }
387
373
 
388
-
389
374
  /**
390
- *
391
- *
392
375
  * @param {string} email_or_id
393
376
  */
394
377
  get_auth_user = async (email_or_id) => {
@@ -400,15 +383,12 @@ export default class Auth {
400
383
  method: 'get'
401
384
  }
402
385
  );
403
-
404
386
  return item;
405
387
  }
406
388
 
407
389
  /**
408
- *
409
- *
410
390
  * @param {string} email_or_id
411
- *
391
+ * @returns {Promise<boolean>}
412
392
  */
413
393
  remove_auth_user = async (email_or_id) => {
414
394
  return fetchApiWithAuth(
@@ -440,7 +420,7 @@ export default class Auth {
440
420
  * @param {ApiQuery<AuthUserType>} query
441
421
  */
442
422
  count_auth_users_query = async (query) => {
443
- const sq = api_query_to_searchparams(query);
423
+ // const sq = api_query_to_searchparams(query);
444
424
  return count_query_of_resource(
445
425
  this.#sdk,
446
426
  `/auth/users`,
@@ -448,9 +428,7 @@ export default class Auth {
448
428
  )
449
429
  }
450
430
 
451
-
452
431
  list_api_keys_auth_users = async () => {
453
-
454
432
  /** @type {AuthUserType[]} */
455
433
  const items = await fetchApiWithAuth(
456
434
  this.#sdk,
@@ -459,7 +437,6 @@ export default class Auth {
459
437
  method: 'get'
460
438
  }
461
439
  );
462
-
463
440
  return items;
464
441
  }
465
442
 
@@ -476,7 +453,6 @@ export default class Auth {
476
453
  }
477
454
 
478
455
  /**
479
- *
480
456
  * @param {OAuthProviderCreateURIParams} params
481
457
  * @returns {Promise<OAuthProviderCreateURIResponse>}
482
458
  */
@@ -516,7 +492,7 @@ export default class Auth {
516
492
  }
517
493
  );
518
494
 
519
- this.#_update_and_notify_subscribers(result);
495
+ this.#update_and_notify_subscribers(result);
520
496
 
521
497
  return result;
522
498
  }
package/src/checkout.js CHANGED
@@ -1,5 +1,8 @@
1
1
  /**
2
- * @import { CheckoutCreateType, OrderData, PricingData } from '@storecraft/core/api'
2
+ * @import {
3
+ * CheckoutCreateType, CheckoutCreateTypeAfterValidation,
4
+ * OrderData, PricingData
5
+ * } from '@storecraft/core/api'
3
6
  */
4
7
  import { StorecraftSDK } from '../index.js'
5
8
  import { fetchApiWithAuth } from './utils.api.fetch.js';
@@ -28,7 +31,6 @@ export default class Checkout {
28
31
  */
29
32
  create = async (input, gateway_handle) => {
30
33
 
31
- console.log('input', input)
32
34
  const result = await fetchApiWithAuth(
33
35
  this.sdk,
34
36
  `checkout/create?gateway=${gateway_handle}`,
@@ -65,11 +67,9 @@ export default class Checkout {
65
67
  }
66
68
 
67
69
  /**
68
- * @description calculate the pricing of an `order`. Using auto-discounts,
69
- * coupons, shipping and line-items.
70
- *
71
- * @param {Partial<OrderData>} order
72
- *
70
+ * @description calculate the pricing of an `order`.
71
+ * Using auto-discounts, coupons, shipping and line-items.
72
+ * @param {CheckoutCreateTypeAfterValidation} order
73
73
  * @returns {Promise<Partial<PricingData>>}
74
74
  */
75
75
  pricing = async (order) => {
@@ -17,7 +17,6 @@ import {
17
17
  export default class Collections extends collection_base {
18
18
 
19
19
  /**
20
- *
21
20
  * @param {StorecraftSDK} sdk
22
21
  */
23
22
  constructor(sdk) {
@@ -28,12 +27,10 @@ export default class Collections extends collection_base {
28
27
  * @description Export a collection of `products` into the `storage`. This is
29
28
  * beneficial for `collections`, that hardly change and therefore can be
30
29
  * efficiently stored in a cost-effective `storage` and **CDN** network.
31
- *
32
30
  * @param {string} collection_handle
33
31
  * @param {number} limit
34
32
  */
35
33
  publish = async (collection_handle, limit=1000) => {
36
-
37
34
  const result = await fetchApiWithAuth(
38
35
  this.sdk,
39
36
  `collections/${collection_handle}/export`,
@@ -41,7 +38,6 @@ export default class Collections extends collection_base {
41
38
  method: 'post'
42
39
  }
43
40
  );
44
-
45
41
  return result
46
42
  }
47
43
 
@@ -49,7 +45,6 @@ export default class Collections extends collection_base {
49
45
  * @description List all the tags of products in a collection, This is helpful
50
46
  * for building a filter system in the frontend if you know in advance all
51
47
  * the tags of the products in a collection
52
- *
53
48
  * @param {string} id_or_handle Collection `id` or `handle`
54
49
  * @return {Promise<string[]>} List of tags
55
50
  */
@@ -67,7 +62,6 @@ export default class Collections extends collection_base {
67
62
 
68
63
  /**
69
64
  * @description Query the `products` in a collection
70
- *
71
65
  * @param {string} id_or_handle Collection `id` or `handle`
72
66
  * @param {ApiQuery<(ProductType | VariantType)>} query query
73
67
  * @return {Promise<(ProductType | VariantType)[]>} List of products in collection
@@ -83,7 +77,6 @@ export default class Collections extends collection_base {
83
77
 
84
78
  /**
85
79
  * @description Count the number of `products` in a collection by a query
86
- *
87
80
  * @param {string} id_or_handle Collection `id` or `handle`
88
81
  * @param {ApiQuery<(ProductType | VariantType)>} query query
89
82
  * @return {Promise<number>} count
package/src/customers.js CHANGED
@@ -27,7 +27,6 @@ export default class Customers extends collection_base {
27
27
  /**
28
28
  * @description Query customer orders, this is only available to admin and
29
29
  * the customer (with auth token)
30
- *
31
30
  * @param {string} id_or_handle customer `id` or `handle` or `email`
32
31
  * @param {ApiQuery<OrderData>} query query
33
32
  * @return {Promise<OrderData[]>} List of orders of customer
@@ -44,7 +43,6 @@ export default class Customers extends collection_base {
44
43
  /**
45
44
  * @description Count the number of orders of a specific
46
45
  * customer with a query
47
- *
48
46
  * @param {string} id_or_handle customer `id` or `handle` or `email`
49
47
  * @param {ApiQuery<OrderData>} query query
50
48
  * @return {Promise<number>} count
package/src/discounts.js CHANGED
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * @import {
3
3
  * ApiQuery, DiscountType, DiscountTypeUpsert,
4
- ProductType,
5
- VariantType
4
+ * ProductType, VariantType
6
5
  * } from '@storecraft/core/api'
7
6
  */
8
7
  import { StorecraftSDK } from '../index.js'
@@ -20,7 +19,6 @@ import {
20
19
  export default class Discounts extends collection_base {
21
20
 
22
21
  /**
23
- *
24
22
  * @param {StorecraftSDK} sdk
25
23
  */
26
24
  constructor(sdk) {
@@ -30,7 +28,6 @@ export default class Discounts extends collection_base {
30
28
  /**
31
29
  * @description Each discount has eligible products,
32
30
  * you can query and filter these products by discount
33
- *
34
31
  * @param {string} id_or_handle discount `id` or `handle`
35
32
  * @param {ApiQuery<ProductType | VariantType>} query query
36
33
  * @return {Promise<(ProductType | VariantType)[]>} List of discounts
@@ -47,7 +44,6 @@ export default class Discounts extends collection_base {
47
44
  /**
48
45
  * @description Each discount has eligible products,
49
46
  * you can count the query products by discount
50
- *
51
47
  * @param {string} id_or_handle discount `id` or `handle`
52
48
  * @param {ApiQuery<ProductType | VariantType>} query query
53
49
  * @return {Promise<number>} count
@@ -64,7 +60,6 @@ export default class Discounts extends collection_base {
64
60
  * @description List all the tags of products in a collection, This is helpful
65
61
  * for building a filter system in the frontend if you know in advance all
66
62
  * the tags of the products in a collection
67
- *
68
63
  * @param {string} id_or_handle Discount `id` or `handle`
69
64
  * @return {Promise<string[]>} List of tags
70
65
  */
@@ -76,7 +71,6 @@ export default class Discounts extends collection_base {
76
71
  method: 'get'
77
72
  }
78
73
  );
79
-
80
74
  return result
81
75
  }
82
76