@cimplify/sdk 0.1.0 → 0.2.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.mjs CHANGED
@@ -869,27 +869,32 @@ var SchedulingService = class {
869
869
  async getServices() {
870
870
  return this.client.query("scheduling.services");
871
871
  }
872
+ /**
873
+ * Get a specific service by ID
874
+ * Note: Filters from all services client-side (no single-service endpoint)
875
+ */
872
876
  async getService(serviceId) {
873
- return this.client.query(`scheduling.services.${serviceId}`);
877
+ const services = await this.getServices();
878
+ return services.find((s) => s.id === serviceId) || null;
874
879
  }
875
880
  // --------------------------------------------------------------------------
876
881
  // AVAILABILITY
877
882
  // --------------------------------------------------------------------------
878
883
  async getAvailableSlots(input) {
879
884
  return this.client.query(
880
- "scheduling.available_slots",
885
+ "scheduling.slots",
881
886
  input
882
887
  );
883
888
  }
884
889
  async checkSlotAvailability(input) {
885
890
  return this.client.query(
886
- "scheduling.check_slot",
891
+ "scheduling.check_availability",
887
892
  input
888
893
  );
889
894
  }
890
895
  async getServiceAvailability(params) {
891
896
  return this.client.query(
892
- "scheduling.service_availability",
897
+ "scheduling.availability",
893
898
  params
894
899
  );
895
900
  }
@@ -897,19 +902,19 @@ var SchedulingService = class {
897
902
  // BOOKINGS
898
903
  // --------------------------------------------------------------------------
899
904
  async getBooking(bookingId) {
900
- return this.client.query(`scheduling.bookings.${bookingId}`);
905
+ return this.client.query(`scheduling.${bookingId}`);
901
906
  }
902
907
  async getCustomerBookings() {
903
- return this.client.query("scheduling.customer_bookings");
908
+ return this.client.query("scheduling");
904
909
  }
905
910
  async getUpcomingBookings() {
906
911
  return this.client.query(
907
- "scheduling.customer_bookings[?(@.status!='completed' && @.status!='cancelled')]#sort(start_time,asc)"
912
+ "scheduling[?(@.status!='completed' && @.status!='cancelled')]#sort(start_time,asc)"
908
913
  );
909
914
  }
910
915
  async getPastBookings(limit = 10) {
911
916
  return this.client.query(
912
- `scheduling.customer_bookings[?(@.status=='completed')]#sort(start_time,desc)#limit(${limit})`
917
+ `scheduling[?(@.status=='completed')]#sort(start_time,desc)#limit(${limit})`
913
918
  );
914
919
  }
915
920
  // --------------------------------------------------------------------------
@@ -1302,23 +1307,354 @@ function query(entity) {
1302
1307
  return new QueryBuilder(entity);
1303
1308
  }
1304
1309
 
1305
- // src/utils/payment.ts
1310
+ // src/utils/price.ts
1306
1311
  var CURRENCY_SYMBOLS = {
1307
- GHS: "GH\u20B5",
1312
+ // Major world currencies
1308
1313
  USD: "$",
1309
1314
  EUR: "\u20AC",
1310
1315
  GBP: "\xA3",
1316
+ JPY: "\xA5",
1317
+ CNY: "\xA5",
1318
+ CHF: "CHF",
1319
+ CAD: "C$",
1320
+ AUD: "A$",
1321
+ NZD: "NZ$",
1322
+ HKD: "HK$",
1323
+ SGD: "S$",
1324
+ INR: "\u20B9",
1325
+ BRL: "R$",
1326
+ MXN: "MX$",
1327
+ KRW: "\u20A9",
1328
+ RUB: "\u20BD",
1329
+ TRY: "\u20BA",
1330
+ THB: "\u0E3F",
1331
+ PLN: "z\u0142",
1332
+ SEK: "kr",
1333
+ NOK: "kr",
1334
+ DKK: "kr",
1335
+ CZK: "K\u010D",
1336
+ HUF: "Ft",
1337
+ ILS: "\u20AA",
1338
+ AED: "\u062F.\u0625",
1339
+ SAR: "\uFDFC",
1340
+ MYR: "RM",
1341
+ PHP: "\u20B1",
1342
+ IDR: "Rp",
1343
+ VND: "\u20AB",
1344
+ TWD: "NT$",
1345
+ // African currencies
1346
+ GHS: "GH\u20B5",
1311
1347
  NGN: "\u20A6",
1312
1348
  KES: "KSh",
1313
1349
  ZAR: "R",
1314
1350
  XOF: "CFA",
1315
- XAF: "FCFA"
1351
+ XAF: "FCFA",
1352
+ EGP: "E\xA3",
1353
+ MAD: "MAD",
1354
+ TZS: "TSh",
1355
+ UGX: "USh",
1356
+ RWF: "FRw",
1357
+ ETB: "Br",
1358
+ ZMW: "ZK",
1359
+ BWP: "P",
1360
+ MUR: "\u20A8",
1361
+ SCR: "\u20A8",
1362
+ NAD: "N$",
1363
+ SZL: "E",
1364
+ LSL: "L",
1365
+ MWK: "MK",
1366
+ AOA: "Kz",
1367
+ CDF: "FC",
1368
+ GMD: "D",
1369
+ GNF: "FG",
1370
+ LRD: "L$",
1371
+ SLL: "Le",
1372
+ MZN: "MT",
1373
+ SDG: "SDG",
1374
+ SSP: "SSP",
1375
+ SOS: "Sh.So.",
1376
+ DJF: "Fdj",
1377
+ ERN: "Nfk",
1378
+ CVE: "$",
1379
+ STN: "Db",
1380
+ KMF: "CF",
1381
+ BIF: "FBu"
1316
1382
  };
1383
+ function getCurrencySymbol(currencyCode) {
1384
+ return CURRENCY_SYMBOLS[currencyCode.toUpperCase()] || currencyCode;
1385
+ }
1386
+ function formatNumberCompact(value, decimals = 1) {
1387
+ const absValue = Math.abs(value);
1388
+ const sign = value < 0 ? "-" : "";
1389
+ if (absValue >= 1e9) {
1390
+ return `${sign}${(absValue / 1e9).toFixed(decimals)}B`;
1391
+ }
1392
+ if (absValue >= 1e6) {
1393
+ return `${sign}${(absValue / 1e6).toFixed(decimals)}M`;
1394
+ }
1395
+ if (absValue >= 1e3) {
1396
+ return `${sign}${(absValue / 1e3).toFixed(decimals)}K`;
1397
+ }
1398
+ return `${sign}${absValue.toFixed(decimals)}`;
1399
+ }
1400
+ function formatPrice(amount, currency = "GHS", locale = "en-US") {
1401
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1402
+ if (isNaN(numAmount)) {
1403
+ return `${getCurrencySymbol(currency)}0.00`;
1404
+ }
1405
+ try {
1406
+ return new Intl.NumberFormat(locale, {
1407
+ style: "currency",
1408
+ currency: currency.toUpperCase(),
1409
+ minimumFractionDigits: 2,
1410
+ maximumFractionDigits: 2
1411
+ }).format(numAmount);
1412
+ } catch {
1413
+ return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
1414
+ }
1415
+ }
1416
+ function formatPriceAdjustment(amount, currency = "GHS", locale = "en-US") {
1417
+ const formatted = formatPrice(Math.abs(amount), currency, locale);
1418
+ if (amount > 0) {
1419
+ return `+${formatted}`;
1420
+ } else if (amount < 0) {
1421
+ return `-${formatted}`;
1422
+ }
1423
+ return formatted;
1424
+ }
1425
+ function formatPriceCompact(amount, currency = "GHS", decimals = 1) {
1426
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1427
+ if (isNaN(numAmount)) {
1428
+ return `${getCurrencySymbol(currency)}0`;
1429
+ }
1430
+ const symbol = getCurrencySymbol(currency);
1431
+ if (Math.abs(numAmount) < 1e3) {
1432
+ return `${symbol}${numAmount.toFixed(2)}`;
1433
+ }
1434
+ return `${symbol}${formatNumberCompact(numAmount, decimals)}`;
1435
+ }
1317
1436
  function formatMoney(amount, currency = "GHS") {
1318
- const symbol = CURRENCY_SYMBOLS[currency.toUpperCase()] || currency;
1437
+ const symbol = getCurrencySymbol(currency);
1319
1438
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1439
+ if (isNaN(numAmount)) {
1440
+ return `${symbol}0.00`;
1441
+ }
1320
1442
  return `${symbol}${numAmount.toFixed(2)}`;
1321
1443
  }
1444
+ function parsePrice(value) {
1445
+ if (value === void 0 || value === null) {
1446
+ return 0;
1447
+ }
1448
+ if (typeof value === "number") {
1449
+ return isNaN(value) ? 0 : value;
1450
+ }
1451
+ const cleaned = value.replace(/[^\d.-]/g, "");
1452
+ const parsed = parseFloat(cleaned);
1453
+ return isNaN(parsed) ? 0 : parsed;
1454
+ }
1455
+ function parseTaxInfo(taxInfoStr) {
1456
+ try {
1457
+ const parts = taxInfoStr.split(":");
1458
+ if (parts.length < 4 || parts[0] !== "T") {
1459
+ return void 0;
1460
+ }
1461
+ const taxRate = parseFloat(parts[1]);
1462
+ const taxAmount = parseFloat(parts[2]);
1463
+ const isInclusive = parts[3] === "I";
1464
+ const components = [];
1465
+ if (parts.length > 4 && parts[4]) {
1466
+ const componentPairs = parts[4].split(",");
1467
+ for (const pair of componentPairs) {
1468
+ const [name, rateStr] = pair.split(":");
1469
+ if (name && rateStr) {
1470
+ components.push({
1471
+ name: name.trim(),
1472
+ rate: parseFloat(rateStr)
1473
+ });
1474
+ }
1475
+ }
1476
+ }
1477
+ return {
1478
+ taxRate,
1479
+ taxAmount,
1480
+ isInclusive,
1481
+ components
1482
+ };
1483
+ } catch {
1484
+ return void 0;
1485
+ }
1486
+ }
1487
+ function parsePricePath(signedPricePath) {
1488
+ if (!signedPricePath) {
1489
+ return {
1490
+ basePrice: 0,
1491
+ finalPrice: 0,
1492
+ currency: "GHS",
1493
+ decisionPath: "",
1494
+ isValid: false,
1495
+ isExpired: false
1496
+ };
1497
+ }
1498
+ try {
1499
+ const parts = signedPricePath.split("\xA7");
1500
+ if (parts.length !== 3) {
1501
+ return {
1502
+ basePrice: 0,
1503
+ finalPrice: 0,
1504
+ currency: "GHS",
1505
+ decisionPath: "",
1506
+ isValid: false,
1507
+ isExpired: false
1508
+ };
1509
+ }
1510
+ const [pricePath, expiryStr, signature] = parts;
1511
+ const expiryTimestamp = parseInt(expiryStr, 10);
1512
+ const now = Math.floor(Date.now() / 1e3);
1513
+ const isExpired = now > expiryTimestamp;
1514
+ const priceComponents = pricePath.split("|");
1515
+ if (priceComponents.length < 5) {
1516
+ return {
1517
+ basePrice: 0,
1518
+ finalPrice: 0,
1519
+ currency: "GHS",
1520
+ decisionPath: "",
1521
+ isValid: false,
1522
+ isExpired
1523
+ };
1524
+ }
1525
+ const basePrice = parseFloat(priceComponents[0]);
1526
+ const finalPrice = parseFloat(priceComponents[1]);
1527
+ const currency = priceComponents[2];
1528
+ const taxInfoStr = priceComponents[3];
1529
+ const decisionPath = priceComponents.slice(4).join("|");
1530
+ let taxInfo;
1531
+ if (taxInfoStr && taxInfoStr.startsWith("T:")) {
1532
+ taxInfo = parseTaxInfo(taxInfoStr);
1533
+ } else if (taxInfoStr === "0" || !taxInfoStr) {
1534
+ taxInfo = {
1535
+ taxRate: 0,
1536
+ taxAmount: 0,
1537
+ isInclusive: false,
1538
+ components: []
1539
+ };
1540
+ }
1541
+ let markupPercentage;
1542
+ let markupAmount;
1543
+ let discountPercentage;
1544
+ if (decisionPath) {
1545
+ const pathParts = decisionPath.split(":");
1546
+ if (pathParts.length > 1 && pathParts[1]) {
1547
+ const adjustments = pathParts[1].split(",");
1548
+ for (const adj of adjustments) {
1549
+ const adjParts = adj.split("|");
1550
+ if (adjParts[0] && adjParts[0].startsWith("ch")) {
1551
+ markupAmount = parseFloat(adjParts[1]) || 0;
1552
+ markupPercentage = parseFloat(adjParts[2]) || 0;
1553
+ break;
1554
+ }
1555
+ }
1556
+ }
1557
+ }
1558
+ if (markupAmount === void 0 && finalPrice > basePrice) {
1559
+ markupAmount = finalPrice - basePrice;
1560
+ markupPercentage = basePrice > 0 ? markupAmount / basePrice * 100 : 0;
1561
+ } else if (basePrice > finalPrice) {
1562
+ discountPercentage = basePrice > 0 ? (basePrice - finalPrice) / basePrice * 100 : 0;
1563
+ }
1564
+ return {
1565
+ basePrice,
1566
+ finalPrice,
1567
+ currency,
1568
+ decisionPath,
1569
+ discountPercentage,
1570
+ markupPercentage,
1571
+ markupAmount,
1572
+ taxInfo,
1573
+ isValid: !isExpired && signature.length > 0,
1574
+ isExpired,
1575
+ expiryTimestamp
1576
+ };
1577
+ } catch {
1578
+ return {
1579
+ basePrice: 0,
1580
+ finalPrice: 0,
1581
+ currency: "GHS",
1582
+ decisionPath: "",
1583
+ isValid: false,
1584
+ isExpired: false
1585
+ };
1586
+ }
1587
+ }
1588
+ function parsedPriceToPriceInfo(parsedPrice) {
1589
+ return {
1590
+ base_price: parsedPrice.basePrice,
1591
+ final_price: parsedPrice.finalPrice,
1592
+ markup_percentage: parsedPrice.markupPercentage,
1593
+ markup_amount: parsedPrice.markupAmount,
1594
+ currency: parsedPrice.currency,
1595
+ tax_info: parsedPrice.taxInfo,
1596
+ decision_path: parsedPrice.decisionPath
1597
+ };
1598
+ }
1599
+ function extractPriceInfo(signedPricePath) {
1600
+ const parsed = parsePricePath(signedPricePath);
1601
+ return parsedPriceToPriceInfo(parsed);
1602
+ }
1603
+ function getDisplayPrice(product) {
1604
+ if (product.price_path) {
1605
+ const priceInfo = extractPriceInfo(product.price_path);
1606
+ return priceInfo.final_price;
1607
+ } else if (product.price_info) {
1608
+ return product.price_info.final_price;
1609
+ }
1610
+ return 0;
1611
+ }
1612
+ function getBasePrice(product) {
1613
+ if (product.price_path) {
1614
+ const priceInfo = extractPriceInfo(product.price_path);
1615
+ return priceInfo.base_price;
1616
+ } else if (product.price_info) {
1617
+ return product.price_info.base_price;
1618
+ }
1619
+ return 0;
1620
+ }
1621
+ function isOnSale(product) {
1622
+ const basePrice = getBasePrice(product);
1623
+ const finalPrice = getDisplayPrice(product);
1624
+ return basePrice > finalPrice && basePrice > 0;
1625
+ }
1626
+ function getDiscountPercentage(product) {
1627
+ const basePrice = getBasePrice(product);
1628
+ const finalPrice = getDisplayPrice(product);
1629
+ if (basePrice > finalPrice && basePrice > 0) {
1630
+ return Math.round((basePrice - finalPrice) / basePrice * 100);
1631
+ }
1632
+ return 0;
1633
+ }
1634
+ function getMarkupPercentage(product) {
1635
+ const basePrice = getBasePrice(product);
1636
+ const finalPrice = getDisplayPrice(product);
1637
+ if (finalPrice > basePrice && basePrice > 0) {
1638
+ return Math.round((finalPrice - basePrice) / basePrice * 100);
1639
+ }
1640
+ return 0;
1641
+ }
1642
+ function getProductCurrency(product) {
1643
+ if (product.price_path) {
1644
+ const parsed = parsePricePath(product.price_path);
1645
+ return parsed.currency || "GHS";
1646
+ } else if (product.price_info?.currency) {
1647
+ return product.price_info.currency;
1648
+ }
1649
+ return "GHS";
1650
+ }
1651
+ function formatProductPrice(product, locale = "en-US") {
1652
+ const price = getDisplayPrice(product);
1653
+ const currency = getProductCurrency(product);
1654
+ return formatPrice(price, currency, locale);
1655
+ }
1656
+
1657
+ // src/utils/payment.ts
1322
1658
  function categorizePaymentError(error, errorCode) {
1323
1659
  let message = "An unexpected error occurred during payment processing. Please try again or contact support.";
1324
1660
  let recoverable = true;
@@ -1457,4 +1793,4 @@ function detectMobileMoneyProvider(phoneNumber) {
1457
1793
  return null;
1458
1794
  }
1459
1795
 
1460
- export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, createCimplifyClient, detectMobileMoneyProvider, formatMoney, normalizePaymentResponse, normalizeStatusResponse, query };
1796
+ export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, createCimplifyClient, detectMobileMoneyProvider, extractPriceInfo, formatMoney, formatNumberCompact, formatPrice, formatPriceAdjustment, formatPriceCompact, formatProductPrice, getBasePrice, getCurrencySymbol, getDiscountPercentage, getDisplayPrice, getMarkupPercentage, getProductCurrency, isOnSale, normalizePaymentResponse, normalizeStatusResponse, parsePrice, parsePricePath, parsedPriceToPriceInfo, query };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cimplify/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Cimplify Commerce SDK for storefronts",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",