@cimplify/sdk 0.6.7 → 0.6.9

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.js CHANGED
@@ -1,6 +1,16 @@
1
1
  'use strict';
2
2
 
3
3
  // src/types/common.ts
4
+ function money(value) {
5
+ return value;
6
+ }
7
+ function moneyFromNumber(value) {
8
+ return value.toFixed(2);
9
+ }
10
+ var ZERO = "0.00";
11
+ function currencyCode(value) {
12
+ return value;
13
+ }
4
14
  var ErrorCode = {
5
15
  // General
6
16
  UNKNOWN_ERROR: "UNKNOWN_ERROR",
@@ -219,6 +229,74 @@ function combineObject(results) {
219
229
  return ok(values);
220
230
  }
221
231
 
232
+ // src/query/builder.ts
233
+ function escapeQueryValue(value) {
234
+ return value.replace(/'/g, "\\'");
235
+ }
236
+ var QueryBuilder = class {
237
+ constructor(entity) {
238
+ this.filters = [];
239
+ this.modifiers = [];
240
+ this.pathSegments = [];
241
+ this.entity = entity;
242
+ }
243
+ path(segment) {
244
+ this.pathSegments.push(segment);
245
+ return this;
246
+ }
247
+ where(field, op, value) {
248
+ const v = typeof value === "string" ? `'${escapeQueryValue(value)}'` : value;
249
+ if (op === "contains" || op === "startsWith") {
250
+ this.filters.push(`@.${field} ${op} ${v}`);
251
+ } else {
252
+ this.filters.push(`@.${field}${op}${v}`);
253
+ }
254
+ return this;
255
+ }
256
+ and(field, op, value) {
257
+ return this.where(field, op, value);
258
+ }
259
+ sort(field, order = "asc") {
260
+ this.modifiers.push(`sort(${field},${order})`);
261
+ return this;
262
+ }
263
+ limit(n) {
264
+ this.modifiers.push(`limit(${n})`);
265
+ return this;
266
+ }
267
+ offset(n) {
268
+ this.modifiers.push(`offset(${n})`);
269
+ return this;
270
+ }
271
+ count() {
272
+ this.modifiers.push("count");
273
+ return this;
274
+ }
275
+ enriched() {
276
+ this.modifiers.push("enriched");
277
+ return this;
278
+ }
279
+ build() {
280
+ let query2 = this.entity;
281
+ if (this.pathSegments.length > 0) {
282
+ query2 += "." + this.pathSegments.join(".");
283
+ }
284
+ if (this.filters.length > 0) {
285
+ query2 += `[?(${this.filters.join(" && ")})]`;
286
+ }
287
+ for (const mod of this.modifiers) {
288
+ query2 += `#${mod}`;
289
+ }
290
+ return query2;
291
+ }
292
+ toString() {
293
+ return this.build();
294
+ }
295
+ };
296
+ function query(entity) {
297
+ return new QueryBuilder(entity);
298
+ }
299
+
222
300
  // src/catalogue.ts
223
301
  function toCimplifyError(error) {
224
302
  if (error instanceof CimplifyError) return enrichError(error);
@@ -299,7 +377,7 @@ var CatalogueQueries = class {
299
377
  let query2 = "products";
300
378
  const filters = [];
301
379
  if (options?.category) {
302
- filters.push(`@.category_id=='${options.category}'`);
380
+ filters.push(`@.category_id=='${escapeQueryValue(options.category)}'`);
303
381
  }
304
382
  if (options?.featured !== void 0) {
305
383
  filters.push(`@.featured==${options.featured}`);
@@ -308,7 +386,7 @@ var CatalogueQueries = class {
308
386
  filters.push(`@.in_stock==${options.in_stock}`);
309
387
  }
310
388
  if (options?.search) {
311
- filters.push(`@.name contains '${options.search}'`);
389
+ filters.push(`@.name contains '${escapeQueryValue(options.search)}'`);
312
390
  }
313
391
  if (options?.min_price !== void 0) {
314
392
  filters.push(`@.price>=${options.min_price}`);
@@ -339,7 +417,9 @@ var CatalogueQueries = class {
339
417
  }
340
418
  async getProductBySlug(slug) {
341
419
  const filteredResult = await safe(
342
- this.client.query(`products[?(@.slug=='${slug}')]`)
420
+ this.client.query(
421
+ `products[?(@.slug=='${escapeQueryValue(slug)}')]`
422
+ )
343
423
  );
344
424
  if (!filteredResult.ok) return filteredResult;
345
425
  const exactMatch = findProductBySlug(filteredResult.value, slug);
@@ -391,7 +471,7 @@ var CatalogueQueries = class {
391
471
  }
392
472
  async getCategoryBySlug(slug) {
393
473
  const result = await safe(
394
- this.client.query(`categories[?(@.slug=='${slug}')]`)
474
+ this.client.query(`categories[?(@.slug=='${escapeQueryValue(slug)}')]`)
395
475
  );
396
476
  if (!result.ok) return result;
397
477
  if (!result.value.length) {
@@ -400,7 +480,11 @@ var CatalogueQueries = class {
400
480
  return ok(result.value[0]);
401
481
  }
402
482
  async getCategoryProducts(categoryId) {
403
- return safe(this.client.query(`products[?(@.category_id=='${categoryId}')]`));
483
+ return safe(
484
+ this.client.query(
485
+ `products[?(@.category_id=='${escapeQueryValue(categoryId)}')]`
486
+ )
487
+ );
404
488
  }
405
489
  async getCollections() {
406
490
  return safe(this.client.query("collections"));
@@ -410,7 +494,9 @@ var CatalogueQueries = class {
410
494
  }
411
495
  async getCollectionBySlug(slug) {
412
496
  const result = await safe(
413
- this.client.query(`collections[?(@.slug=='${slug}')]`)
497
+ this.client.query(
498
+ `collections[?(@.slug=='${escapeQueryValue(slug)}')]`
499
+ )
414
500
  );
415
501
  if (!result.ok) return result;
416
502
  if (!result.value.length) {
@@ -423,7 +509,9 @@ var CatalogueQueries = class {
423
509
  }
424
510
  async searchCollections(query2, limit = 20) {
425
511
  return safe(
426
- this.client.query(`collections[?(@.name contains '${query2}')]#limit(${limit})`)
512
+ this.client.query(
513
+ `collections[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
514
+ )
427
515
  );
428
516
  }
429
517
  async getBundles() {
@@ -434,7 +522,9 @@ var CatalogueQueries = class {
434
522
  }
435
523
  async getBundleBySlug(slug) {
436
524
  const result = await safe(
437
- this.client.query(`bundles[?(@.slug=='${slug}')]`)
525
+ this.client.query(
526
+ `bundles[?(@.slug=='${escapeQueryValue(slug)}')]`
527
+ )
438
528
  );
439
529
  if (!result.ok) return result;
440
530
  if (!result.value.length) {
@@ -444,7 +534,9 @@ var CatalogueQueries = class {
444
534
  }
445
535
  async searchBundles(query2, limit = 20) {
446
536
  return safe(
447
- this.client.query(`bundles[?(@.name contains '${query2}')]#limit(${limit})`)
537
+ this.client.query(
538
+ `bundles[?(@.name contains '${escapeQueryValue(query2)}')]#limit(${limit})`
539
+ )
448
540
  );
449
541
  }
450
542
  async getComposites(options) {
@@ -484,9 +576,9 @@ var CatalogueQueries = class {
484
576
  }
485
577
  async search(query2, options) {
486
578
  const limit = options?.limit ?? 20;
487
- let searchQuery = `products[?(@.name contains '${query2}')]`;
579
+ let searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}')]`;
488
580
  if (options?.category) {
489
- searchQuery = `products[?(@.name contains '${query2}' && @.category_id=='${options.category}')]`;
581
+ searchQuery = `products[?(@.name contains '${escapeQueryValue(query2)}' && @.category_id=='${escapeQueryValue(options.category)}')]`;
490
582
  }
491
583
  searchQuery += `#limit(${limit})`;
492
584
  return safe(this.client.query(searchQuery));
@@ -503,7 +595,7 @@ var CatalogueQueries = class {
503
595
  async getMenu(options) {
504
596
  let query2 = "menu";
505
597
  if (options?.category) {
506
- query2 = `menu[?(@.category=='${options.category}')]`;
598
+ query2 = `menu[?(@.category=='${escapeQueryValue(options.category)}')]`;
507
599
  }
508
600
  if (options?.limit) {
509
601
  query2 += `#limit(${options.limit})`;
@@ -820,8 +912,8 @@ var CURRENCY_SYMBOLS = {
820
912
  KMF: "CF",
821
913
  BIF: "FBu"
822
914
  };
823
- function getCurrencySymbol(currencyCode) {
824
- return CURRENCY_SYMBOLS[currencyCode.toUpperCase()] || currencyCode;
915
+ function getCurrencySymbol(currencyCode2) {
916
+ return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
825
917
  }
826
918
  function formatNumberCompact(value, decimals = 1) {
827
919
  const absValue = Math.abs(value);
@@ -1145,6 +1237,8 @@ function normalizeStatusResponse(response) {
1145
1237
  }
1146
1238
  const res = response;
1147
1239
  const normalizedStatus = normalizePaymentStatusValue(res.status ?? void 0);
1240
+ const normalizedAmount = typeof res.amount === "string" ? money(res.amount) : typeof res.amount === "number" && Number.isFinite(res.amount) ? moneyFromNumber(res.amount) : void 0;
1241
+ const normalizedCurrency = typeof res.currency === "string" && res.currency.trim().length > 0 ? currencyCode(res.currency) : void 0;
1148
1242
  const paidValue = res.paid === true;
1149
1243
  const derivedPaid = paidValue || [
1150
1244
  "success",
@@ -1157,8 +1251,8 @@ function normalizeStatusResponse(response) {
1157
1251
  return {
1158
1252
  status: normalizedStatus,
1159
1253
  paid: derivedPaid,
1160
- amount: res.amount,
1161
- currency: res.currency,
1254
+ amount: normalizedAmount,
1255
+ currency: normalizedCurrency,
1162
1256
  reference: res.reference,
1163
1257
  message: res.message || ""
1164
1258
  };
@@ -1865,14 +1959,17 @@ var CheckoutService = class {
1865
1959
  pay_currency: data.pay_currency,
1866
1960
  fx_quote_id: data.fx_quote_id
1867
1961
  };
1868
- const baseCurrency = (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase();
1962
+ const baseCurrency = currencyCode(
1963
+ (cart.pricing.currency || checkoutData.pay_currency || "GHS").toUpperCase()
1964
+ );
1869
1965
  const payCurrency = data.pay_currency?.trim().toUpperCase();
1966
+ const payCurrencyCode = payCurrency ? currencyCode(payCurrency) : void 0;
1870
1967
  const cartTotalAmount = Number.parseFloat(cart.pricing.total_price || "0");
1871
- if (payCurrency && payCurrency !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
1968
+ if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && Number.isFinite(cartTotalAmount) && cartTotalAmount > 0) {
1872
1969
  const fxQuoteResult = await this.client.fx.lockQuote({
1873
1970
  from: baseCurrency,
1874
- to: payCurrency,
1875
- amount: cartTotalAmount
1971
+ to: payCurrencyCode,
1972
+ amount: cart.pricing.total_price
1876
1973
  });
1877
1974
  if (!fxQuoteResult.ok) {
1878
1975
  return ok(
@@ -1883,7 +1980,7 @@ var CheckoutService = class {
1883
1980
  )
1884
1981
  );
1885
1982
  }
1886
- checkoutData.pay_currency = payCurrency;
1983
+ checkoutData.pay_currency = payCurrencyCode;
1887
1984
  checkoutData.fx_quote_id = fxQuoteResult.value.id;
1888
1985
  }
1889
1986
  data.on_status_change?.("processing", {});
@@ -1988,6 +2085,9 @@ var LinkService = class {
1988
2085
  constructor(client) {
1989
2086
  this.client = client;
1990
2087
  }
2088
+ async getProfile() {
2089
+ return safe5(this.client.linkGet("/v1/link/profile"));
2090
+ }
1991
2091
  async requestOtp(input) {
1992
2092
  return safe5(this.client.linkPost("/v1/link/auth/request-otp", input));
1993
2093
  }
@@ -2015,13 +2115,13 @@ var LinkService = class {
2015
2115
  );
2016
2116
  }
2017
2117
  async getLinkData() {
2018
- return safe5(this.client.query(LINK_QUERY.DATA));
2118
+ return safe5(this.client.linkGet("/v1/link/data"));
2019
2119
  }
2020
2120
  async getAddresses() {
2021
- return safe5(this.client.query(LINK_QUERY.ADDRESSES));
2121
+ return safe5(this.client.linkGet("/v1/link/addresses"));
2022
2122
  }
2023
2123
  async getMobileMoney() {
2024
- return safe5(this.client.query(LINK_QUERY.MOBILE_MONEY));
2124
+ return safe5(this.client.linkGet("/v1/link/mobile-money"));
2025
2125
  }
2026
2126
  async getPreferences() {
2027
2127
  return safe5(this.client.query(LINK_QUERY.PREFERENCES));
@@ -2044,10 +2144,10 @@ var LinkService = class {
2044
2144
  return safe5(this.client.call(LINK_MUTATION.UPDATE_ADDRESS, input));
2045
2145
  }
2046
2146
  async deleteAddress(addressId) {
2047
- return safe5(this.client.call(LINK_MUTATION.DELETE_ADDRESS, addressId));
2147
+ return safe5(this.client.linkDelete(`/v1/link/addresses/${addressId}`));
2048
2148
  }
2049
2149
  async setDefaultAddress(addressId) {
2050
- return safe5(this.client.call(LINK_MUTATION.SET_DEFAULT_ADDRESS, addressId));
2150
+ return safe5(this.client.linkPost(`/v1/link/addresses/${addressId}/default`));
2051
2151
  }
2052
2152
  async trackAddressUsage(addressId) {
2053
2153
  return safe5(
@@ -2060,11 +2160,13 @@ var LinkService = class {
2060
2160
  return safe5(this.client.call(LINK_MUTATION.CREATE_MOBILE_MONEY, input));
2061
2161
  }
2062
2162
  async deleteMobileMoney(mobileMoneyId) {
2063
- return safe5(this.client.call(LINK_MUTATION.DELETE_MOBILE_MONEY, mobileMoneyId));
2163
+ return safe5(
2164
+ this.client.linkDelete(`/v1/link/mobile-money/${mobileMoneyId}`)
2165
+ );
2064
2166
  }
2065
2167
  async setDefaultMobileMoney(mobileMoneyId) {
2066
2168
  return safe5(
2067
- this.client.call(LINK_MUTATION.SET_DEFAULT_MOBILE_MONEY, mobileMoneyId)
2169
+ this.client.linkPost(`/v1/link/mobile-money/${mobileMoneyId}/default`)
2068
2170
  );
2069
2171
  }
2070
2172
  async trackMobileMoneyUsage(mobileMoneyId) {
@@ -3229,7 +3331,7 @@ var CimplifyClient = class {
3229
3331
  this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
3230
3332
  this.hooks = config.hooks ?? {};
3231
3333
  this.accessToken = this.loadAccessToken();
3232
- if (!this.publicKey) {
3334
+ if (!this.publicKey && !config.suppressPublicKeyWarning) {
3233
3335
  console.warn(
3234
3336
  '[Cimplify] No public key found. Set NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY in your environment, or pass { publicKey: "pk_..." } to createCimplifyClient().'
3235
3337
  );
@@ -3342,9 +3444,12 @@ var CimplifyClient = class {
3342
3444
  }
3343
3445
  getHeaders() {
3344
3446
  const headers = {
3345
- "Content-Type": "application/json",
3346
- "X-API-Key": this.publicKey
3447
+ "Content-Type": "application/json"
3347
3448
  };
3449
+ const trimmedPublicKey = this.publicKey.trim();
3450
+ if (trimmedPublicKey) {
3451
+ headers["X-API-Key"] = trimmedPublicKey;
3452
+ }
3348
3453
  if (this.accessToken) {
3349
3454
  headers["Authorization"] = `Bearer ${this.accessToken}`;
3350
3455
  }
@@ -3373,7 +3478,7 @@ var CimplifyClient = class {
3373
3478
  signal: controller.signal
3374
3479
  });
3375
3480
  clearTimeout(timeoutId);
3376
- if (response.ok || response.status >= 400 && response.status < 500) {
3481
+ if (response.ok) {
3377
3482
  this.hooks.onRequestSuccess?.({
3378
3483
  ...context,
3379
3484
  status: response.status,
@@ -3381,6 +3486,21 @@ var CimplifyClient = class {
3381
3486
  });
3382
3487
  return response;
3383
3488
  }
3489
+ if (response.status >= 400 && response.status < 500) {
3490
+ this.hooks.onRequestError?.({
3491
+ ...context,
3492
+ error: new CimplifyError(
3493
+ `HTTP_${response.status}`,
3494
+ `Request failed with status ${response.status}`,
3495
+ false
3496
+ ),
3497
+ status: response.status,
3498
+ durationMs: Date.now() - startTime,
3499
+ retryCount,
3500
+ retryable: false
3501
+ });
3502
+ return response;
3503
+ }
3384
3504
  if (response.status >= 500 && attempt < this.maxRetries) {
3385
3505
  retryCount++;
3386
3506
  const delay = this.retryDelay * Math.pow(2, attempt);
@@ -3393,10 +3513,17 @@ var CimplifyClient = class {
3393
3513
  await sleep(delay);
3394
3514
  continue;
3395
3515
  }
3396
- this.hooks.onRequestSuccess?.({
3516
+ this.hooks.onRequestError?.({
3397
3517
  ...context,
3518
+ error: new CimplifyError(
3519
+ "SERVER_ERROR",
3520
+ `Server error ${response.status} after ${retryCount} retries`,
3521
+ false
3522
+ ),
3398
3523
  status: response.status,
3399
- durationMs: Date.now() - startTime
3524
+ durationMs: Date.now() - startTime,
3525
+ retryCount,
3526
+ retryable: false
3400
3527
  });
3401
3528
  return response;
3402
3529
  } catch (error) {
@@ -3670,71 +3797,6 @@ function createCimplifyClient(config = {}) {
3670
3797
  return new CimplifyClient(config);
3671
3798
  }
3672
3799
 
3673
- // src/query/builder.ts
3674
- var QueryBuilder = class {
3675
- constructor(entity) {
3676
- this.filters = [];
3677
- this.modifiers = [];
3678
- this.pathSegments = [];
3679
- this.entity = entity;
3680
- }
3681
- path(segment) {
3682
- this.pathSegments.push(segment);
3683
- return this;
3684
- }
3685
- where(field, op, value) {
3686
- const v = typeof value === "string" ? `'${value}'` : value;
3687
- if (op === "contains" || op === "startsWith") {
3688
- this.filters.push(`@.${field} ${op} ${v}`);
3689
- } else {
3690
- this.filters.push(`@.${field}${op}${v}`);
3691
- }
3692
- return this;
3693
- }
3694
- and(field, op, value) {
3695
- return this.where(field, op, value);
3696
- }
3697
- sort(field, order = "asc") {
3698
- this.modifiers.push(`sort(${field},${order})`);
3699
- return this;
3700
- }
3701
- limit(n) {
3702
- this.modifiers.push(`limit(${n})`);
3703
- return this;
3704
- }
3705
- offset(n) {
3706
- this.modifiers.push(`offset(${n})`);
3707
- return this;
3708
- }
3709
- count() {
3710
- this.modifiers.push("count");
3711
- return this;
3712
- }
3713
- enriched() {
3714
- this.modifiers.push("enriched");
3715
- return this;
3716
- }
3717
- build() {
3718
- let query2 = this.entity;
3719
- if (this.pathSegments.length > 0) {
3720
- query2 += "." + this.pathSegments.join(".");
3721
- }
3722
- if (this.filters.length > 0) {
3723
- query2 += `[?(${this.filters.join(" && ")})]`;
3724
- }
3725
- for (const mod of this.modifiers) {
3726
- query2 += `#${mod}`;
3727
- }
3728
- return query2;
3729
- }
3730
- toString() {
3731
- return this.build();
3732
- }
3733
- };
3734
- function query(entity) {
3735
- return new QueryBuilder(entity);
3736
- }
3737
-
3738
3800
  exports.AUTHORIZATION_TYPE = AUTHORIZATION_TYPE;
3739
3801
  exports.AUTH_MUTATION = AUTH_MUTATION;
3740
3802
  exports.AuthService = AuthService;
@@ -3777,11 +3839,13 @@ exports.PAYMENT_STATE = PAYMENT_STATE;
3777
3839
  exports.PICKUP_TIME_TYPE = PICKUP_TIME_TYPE;
3778
3840
  exports.QueryBuilder = QueryBuilder;
3779
3841
  exports.SchedulingService = SchedulingService;
3842
+ exports.ZERO = ZERO;
3780
3843
  exports.categorizePaymentError = categorizePaymentError;
3781
3844
  exports.combine = combine;
3782
3845
  exports.combineObject = combineObject;
3783
3846
  exports.createCimplifyClient = createCimplifyClient;
3784
3847
  exports.createElements = createElements;
3848
+ exports.currencyCode = currencyCode;
3785
3849
  exports.detectMobileMoneyProvider = detectMobileMoneyProvider;
3786
3850
  exports.enrichError = enrichError;
3787
3851
  exports.err = err;
@@ -3812,6 +3876,8 @@ exports.isPaymentStatusSuccess = isPaymentStatusSuccess;
3812
3876
  exports.isRetryableError = isRetryableError;
3813
3877
  exports.mapError = mapError;
3814
3878
  exports.mapResult = mapResult;
3879
+ exports.money = money;
3880
+ exports.moneyFromNumber = moneyFromNumber;
3815
3881
  exports.normalizePaymentResponse = normalizePaymentResponse;
3816
3882
  exports.normalizeStatusResponse = normalizeStatusResponse;
3817
3883
  exports.ok = ok;