@cimplify/sdk 0.6.0 → 0.6.2

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
@@ -151,6 +151,63 @@ async function safe(promise) {
151
151
  return err(toCimplifyError(error));
152
152
  }
153
153
  }
154
+ function isRecord(value) {
155
+ return typeof value === "object" && value !== null;
156
+ }
157
+ function readFinalPrice(value) {
158
+ if (!isRecord(value)) return void 0;
159
+ const finalPrice = value.final_price;
160
+ if (typeof finalPrice === "string" || typeof finalPrice === "number") {
161
+ return finalPrice;
162
+ }
163
+ return void 0;
164
+ }
165
+ function normalizeCatalogueProductPayload(product) {
166
+ const normalized = { ...product };
167
+ const defaultPrice = normalized["default_price"];
168
+ if (defaultPrice === void 0 || defaultPrice === null || defaultPrice === "") {
169
+ const derivedDefaultPrice = readFinalPrice(normalized["default_price_info"]) || readFinalPrice(normalized["price_info"]) || (typeof normalized["final_price"] === "string" || typeof normalized["final_price"] === "number" ? normalized["final_price"] : void 0);
170
+ normalized["default_price"] = derivedDefaultPrice ?? "0";
171
+ }
172
+ const variants = normalized["variants"];
173
+ if (Array.isArray(variants)) {
174
+ normalized["variants"] = variants.map((variant) => {
175
+ if (!isRecord(variant)) return variant;
176
+ const normalizedVariant = { ...variant };
177
+ const variantAdjustment = normalizedVariant["price_adjustment"];
178
+ if (variantAdjustment === void 0 || variantAdjustment === null || variantAdjustment === "") {
179
+ normalizedVariant["price_adjustment"] = readFinalPrice(normalizedVariant["price_info"]) ?? "0";
180
+ }
181
+ return normalizedVariant;
182
+ });
183
+ }
184
+ const addOns = normalized["add_ons"];
185
+ if (Array.isArray(addOns)) {
186
+ normalized["add_ons"] = addOns.map((addOn) => {
187
+ if (!isRecord(addOn)) return addOn;
188
+ const normalizedAddOn = { ...addOn };
189
+ const options = normalizedAddOn["options"];
190
+ if (!Array.isArray(options)) return normalizedAddOn;
191
+ normalizedAddOn["options"] = options.map((option) => {
192
+ if (!isRecord(option)) return option;
193
+ const normalizedOption = { ...option };
194
+ const optionPrice = normalizedOption["default_price"];
195
+ if (optionPrice === void 0 || optionPrice === null || optionPrice === "") {
196
+ normalizedOption["default_price"] = readFinalPrice(normalizedOption["default_price_info"]) || readFinalPrice(normalizedOption["price_info"]) || "0";
197
+ }
198
+ return normalizedOption;
199
+ });
200
+ return normalizedAddOn;
201
+ });
202
+ }
203
+ return normalized;
204
+ }
205
+ function findProductBySlug(products, slug) {
206
+ return products.find((product) => {
207
+ const value = product["slug"];
208
+ return typeof value === "string" && value === slug;
209
+ });
210
+ }
154
211
  var CatalogueQueries = class {
155
212
  constructor(client) {
156
213
  this.client = client;
@@ -188,20 +245,34 @@ var CatalogueQueries = class {
188
245
  if (options?.offset) {
189
246
  query2 += `#offset(${options.offset})`;
190
247
  }
191
- return safe(this.client.query(query2));
248
+ const result = await safe(this.client.query(query2));
249
+ if (!result.ok) return result;
250
+ return ok(result.value.map((product) => normalizeCatalogueProductPayload(product)));
192
251
  }
193
252
  async getProduct(id) {
194
- return safe(this.client.query(`products.${id}`));
253
+ const result = await safe(this.client.query(`products.${id}`));
254
+ if (!result.ok) return result;
255
+ return ok(normalizeCatalogueProductPayload(result.value));
195
256
  }
196
257
  async getProductBySlug(slug) {
197
- const result = await safe(
258
+ const filteredResult = await safe(
198
259
  this.client.query(`products[?(@.slug=='${slug}')]`)
199
260
  );
200
- if (!result.ok) return result;
201
- if (!result.value.length) {
261
+ if (!filteredResult.ok) return filteredResult;
262
+ const exactMatch = findProductBySlug(filteredResult.value, slug);
263
+ if (exactMatch) {
264
+ return ok(normalizeCatalogueProductPayload(exactMatch));
265
+ }
266
+ if (filteredResult.value.length === 1) {
267
+ return ok(normalizeCatalogueProductPayload(filteredResult.value[0]));
268
+ }
269
+ const unfilteredResult = await safe(this.client.query("products"));
270
+ if (!unfilteredResult.ok) return unfilteredResult;
271
+ const fallbackMatch = findProductBySlug(unfilteredResult.value, slug);
272
+ if (!fallbackMatch) {
202
273
  return err(new CimplifyError("NOT_FOUND", `Product not found: ${slug}`, false));
203
274
  }
204
- return ok(result.value[0]);
275
+ return ok(normalizeCatalogueProductPayload(fallbackMatch));
205
276
  }
206
277
  async getVariants(productId) {
207
278
  return safe(this.client.query(`products.${productId}.variants`));
@@ -315,6 +386,19 @@ var CatalogueQueries = class {
315
386
  })
316
387
  );
317
388
  }
389
+ async fetchQuote(input) {
390
+ return safe(this.client.call("catalogue.createQuote", input));
391
+ }
392
+ async getQuote(quoteId) {
393
+ return safe(
394
+ this.client.call("catalogue.getQuote", {
395
+ quote_id: quoteId
396
+ })
397
+ );
398
+ }
399
+ async refreshQuote(input) {
400
+ return safe(this.client.call("catalogue.refreshQuote", input));
401
+ }
318
402
  async search(query2, options) {
319
403
  const limit = options?.limit ?? 20;
320
404
  let searchQuery = `products[?(@.name contains '${query2}')]`;
@@ -366,12 +450,20 @@ async function safe2(promise) {
366
450
  return err(toCimplifyError2(error));
367
451
  }
368
452
  }
453
+ function isUICartResponse(value) {
454
+ return "cart" in value;
455
+ }
456
+ function unwrapEnrichedCart(value) {
457
+ return isUICartResponse(value) ? value.cart : value;
458
+ }
369
459
  var CartOperations = class {
370
460
  constructor(client) {
371
461
  this.client = client;
372
462
  }
373
463
  async get() {
374
- return safe2(this.client.query("cart#enriched"));
464
+ const result = await safe2(this.client.query("cart#enriched"));
465
+ if (!result.ok) return result;
466
+ return ok(unwrapEnrichedCart(result.value));
375
467
  }
376
468
  async getRaw() {
377
469
  return safe2(this.client.query("cart"));
@@ -1324,7 +1416,7 @@ function toCheckoutFormData(data) {
1324
1416
  } : void 0,
1325
1417
  special_instructions: data.notes,
1326
1418
  link_address_id: data.address?.id,
1327
- link_payment_method_id: data.payment_method?.id
1419
+ link_payment_method_id: data.payment_method?.type === "card" && data.payment_method?.id ? data.payment_method.id : void 0
1328
1420
  };
1329
1421
  }
1330
1422
  var DEFAULT_LINK_URL = "https://link.cimplify.io";
@@ -2275,169 +2367,27 @@ function parsePrice(value) {
2275
2367
  const parsed = parseFloat(cleaned);
2276
2368
  return isNaN(parsed) ? 0 : parsed;
2277
2369
  }
2278
- function parseTaxInfo(taxInfoStr) {
2279
- try {
2280
- const parts = taxInfoStr.split(":");
2281
- if (parts.length < 4 || parts[0] !== "T") {
2282
- return void 0;
2283
- }
2284
- const taxRate = parseFloat(parts[1]);
2285
- const taxAmount = parseFloat(parts[2]);
2286
- const isInclusive = parts[3] === "I";
2287
- const components = [];
2288
- if (parts.length > 4 && parts[4]) {
2289
- const componentPairs = parts[4].split(",");
2290
- for (const pair of componentPairs) {
2291
- const [name, rateStr] = pair.split(":");
2292
- if (name && rateStr) {
2293
- components.push({
2294
- name: name.trim(),
2295
- rate: parseFloat(rateStr)
2296
- });
2297
- }
2298
- }
2299
- }
2300
- return {
2301
- taxRate,
2302
- taxAmount,
2303
- isInclusive,
2304
- components
2305
- };
2306
- } catch {
2307
- return void 0;
2308
- }
2309
- }
2310
- function parsePricePath(signedPricePath) {
2311
- if (!signedPricePath) {
2312
- return {
2313
- basePrice: 0,
2314
- finalPrice: 0,
2315
- currency: "GHS",
2316
- decisionPath: "",
2317
- isValid: false,
2318
- isExpired: false
2319
- };
2370
+ function getDisplayPrice(product) {
2371
+ if (product.price_info) {
2372
+ return parsePrice(product.price_info.final_price);
2320
2373
  }
2321
- try {
2322
- const parts = signedPricePath.split("\xA7");
2323
- if (parts.length !== 3) {
2324
- return {
2325
- basePrice: 0,
2326
- finalPrice: 0,
2327
- currency: "GHS",
2328
- decisionPath: "",
2329
- isValid: false,
2330
- isExpired: false
2331
- };
2332
- }
2333
- const [pricePath, expiryStr, signature] = parts;
2334
- const expiryTimestamp = parseInt(expiryStr, 10);
2335
- const now = Math.floor(Date.now() / 1e3);
2336
- const isExpired = now > expiryTimestamp;
2337
- const priceComponents = pricePath.split("|");
2338
- if (priceComponents.length < 5) {
2339
- return {
2340
- basePrice: 0,
2341
- finalPrice: 0,
2342
- currency: "GHS",
2343
- decisionPath: "",
2344
- isValid: false,
2345
- isExpired
2346
- };
2347
- }
2348
- const basePrice = parseFloat(priceComponents[0]);
2349
- const finalPrice = parseFloat(priceComponents[1]);
2350
- const currency = priceComponents[2];
2351
- const taxInfoStr = priceComponents[3];
2352
- const decisionPath = priceComponents.slice(4).join("|");
2353
- let taxInfo;
2354
- if (taxInfoStr && taxInfoStr.startsWith("T:")) {
2355
- taxInfo = parseTaxInfo(taxInfoStr);
2356
- } else if (taxInfoStr === "0" || !taxInfoStr) {
2357
- taxInfo = {
2358
- taxRate: 0,
2359
- taxAmount: 0,
2360
- isInclusive: false,
2361
- components: []
2362
- };
2363
- }
2364
- let markupPercentage;
2365
- let markupAmount;
2366
- let discountPercentage;
2367
- if (decisionPath) {
2368
- const pathParts = decisionPath.split(":");
2369
- if (pathParts.length > 1 && pathParts[1]) {
2370
- const adjustments = pathParts[1].split(",");
2371
- for (const adj of adjustments) {
2372
- const adjParts = adj.split("|");
2373
- if (adjParts[0] && adjParts[0].startsWith("ch")) {
2374
- markupAmount = parseFloat(adjParts[1]) || 0;
2375
- markupPercentage = parseFloat(adjParts[2]) || 0;
2376
- break;
2377
- }
2378
- }
2379
- }
2380
- }
2381
- if (markupAmount === void 0 && finalPrice > basePrice) {
2382
- markupAmount = finalPrice - basePrice;
2383
- markupPercentage = basePrice > 0 ? markupAmount / basePrice * 100 : 0;
2384
- } else if (basePrice > finalPrice) {
2385
- discountPercentage = basePrice > 0 ? (basePrice - finalPrice) / basePrice * 100 : 0;
2386
- }
2387
- return {
2388
- basePrice,
2389
- finalPrice,
2390
- currency,
2391
- decisionPath,
2392
- discountPercentage,
2393
- markupPercentage,
2394
- markupAmount,
2395
- taxInfo,
2396
- isValid: !isExpired && signature.length > 0,
2397
- isExpired,
2398
- expiryTimestamp
2399
- };
2400
- } catch {
2401
- return {
2402
- basePrice: 0,
2403
- finalPrice: 0,
2404
- currency: "GHS",
2405
- decisionPath: "",
2406
- isValid: false,
2407
- isExpired: false
2408
- };
2374
+ if (product.final_price !== void 0 && product.final_price !== null) {
2375
+ return parsePrice(product.final_price);
2409
2376
  }
2410
- }
2411
- function parsedPriceToPriceInfo(parsedPrice) {
2412
- return {
2413
- base_price: parsedPrice.basePrice,
2414
- final_price: parsedPrice.finalPrice,
2415
- markup_percentage: parsedPrice.markupPercentage,
2416
- markup_amount: parsedPrice.markupAmount,
2417
- currency: parsedPrice.currency,
2418
- tax_info: parsedPrice.taxInfo,
2419
- decision_path: parsedPrice.decisionPath
2420
- };
2421
- }
2422
- function extractPriceInfo(signedPricePath) {
2423
- const parsed = parsePricePath(signedPricePath);
2424
- return parsedPriceToPriceInfo(parsed);
2425
- }
2426
- function getDisplayPrice(product) {
2427
- if (product.price_path) {
2428
- const priceInfo = extractPriceInfo(product.price_path);
2429
- return priceInfo.final_price;
2430
- } else if (product.price_info) {
2431
- return product.price_info.final_price;
2377
+ if (product.default_price !== void 0 && product.default_price !== null) {
2378
+ return parsePrice(product.default_price);
2432
2379
  }
2433
2380
  return 0;
2434
2381
  }
2435
2382
  function getBasePrice(product) {
2436
- if (product.price_path) {
2437
- const priceInfo = extractPriceInfo(product.price_path);
2438
- return priceInfo.base_price;
2439
- } else if (product.price_info) {
2440
- return product.price_info.base_price;
2383
+ if (product.price_info) {
2384
+ return parsePrice(product.price_info.base_price);
2385
+ }
2386
+ if (product.base_price !== void 0 && product.base_price !== null) {
2387
+ return parsePrice(product.base_price);
2388
+ }
2389
+ if (product.default_price !== void 0 && product.default_price !== null) {
2390
+ return parsePrice(product.default_price);
2441
2391
  }
2442
2392
  return 0;
2443
2393
  }
@@ -2463,12 +2413,12 @@ function getMarkupPercentage(product) {
2463
2413
  return 0;
2464
2414
  }
2465
2415
  function getProductCurrency(product) {
2466
- if (product.price_path) {
2467
- const parsed = parsePricePath(product.price_path);
2468
- return parsed.currency || "GHS";
2469
- } else if (product.price_info?.currency) {
2416
+ if (product.price_info?.currency) {
2470
2417
  return product.price_info.currency;
2471
2418
  }
2419
+ if (product.currency) {
2420
+ return product.currency;
2421
+ }
2472
2422
  return "GHS";
2473
2423
  }
2474
2424
  function formatProductPrice(product, locale = "en-US") {
@@ -2571,6 +2521,95 @@ function normalizePaymentResponse(response) {
2571
2521
  metadata: {}
2572
2522
  };
2573
2523
  }
2524
+ var PAYMENT_SUCCESS_STATUSES = /* @__PURE__ */ new Set([
2525
+ "success",
2526
+ "succeeded",
2527
+ "paid",
2528
+ "captured",
2529
+ "completed",
2530
+ "authorized"
2531
+ ]);
2532
+ var PAYMENT_FAILURE_STATUSES = /* @__PURE__ */ new Set([
2533
+ "failed",
2534
+ "declined",
2535
+ "cancelled",
2536
+ "voided",
2537
+ "error"
2538
+ ]);
2539
+ var PAYMENT_REQUIRES_ACTION_STATUSES = /* @__PURE__ */ new Set([
2540
+ "requires_action",
2541
+ "requires_payment_method",
2542
+ "requires_capture"
2543
+ ]);
2544
+ var PAYMENT_STATUS_ALIAS_MAP = {
2545
+ ok: "success",
2546
+ done: "success",
2547
+ paid: "paid",
2548
+ paid_in_full: "paid",
2549
+ paid_successfully: "paid",
2550
+ succeeded: "success",
2551
+ captured: "captured",
2552
+ completed: "completed",
2553
+ pending_confirmation: "pending_confirmation",
2554
+ requires_authorization: "requires_action",
2555
+ requires_action: "requires_action",
2556
+ requires_payment_method: "requires_payment_method",
2557
+ requires_capture: "requires_capture",
2558
+ partially_paid: "partially_paid",
2559
+ partially_refunded: "partially_refunded",
2560
+ card_declined: "declined",
2561
+ canceled: "cancelled",
2562
+ authorized: "authorized",
2563
+ cancelled: "cancelled",
2564
+ unresolved: "pending"
2565
+ };
2566
+ var KNOWN_PAYMENT_STATUSES = /* @__PURE__ */ new Set([
2567
+ "pending",
2568
+ "processing",
2569
+ "created",
2570
+ "pending_confirmation",
2571
+ "success",
2572
+ "succeeded",
2573
+ "failed",
2574
+ "declined",
2575
+ "authorized",
2576
+ "refunded",
2577
+ "partially_refunded",
2578
+ "partially_paid",
2579
+ "paid",
2580
+ "unpaid",
2581
+ "requires_action",
2582
+ "requires_payment_method",
2583
+ "requires_capture",
2584
+ "captured",
2585
+ "cancelled",
2586
+ "completed",
2587
+ "voided",
2588
+ "error",
2589
+ "unknown"
2590
+ ]);
2591
+ function normalizeStatusToken(status) {
2592
+ return status?.trim().toLowerCase().replace(/[\s-]+/g, "_") ?? "";
2593
+ }
2594
+ function normalizePaymentStatusValue(status) {
2595
+ const normalized = normalizeStatusToken(status);
2596
+ if (Object.prototype.hasOwnProperty.call(PAYMENT_STATUS_ALIAS_MAP, normalized)) {
2597
+ return PAYMENT_STATUS_ALIAS_MAP[normalized];
2598
+ }
2599
+ return KNOWN_PAYMENT_STATUSES.has(normalized) ? normalized : "unknown";
2600
+ }
2601
+ function isPaymentStatusSuccess(status) {
2602
+ const normalizedStatus = normalizePaymentStatusValue(status);
2603
+ return PAYMENT_SUCCESS_STATUSES.has(normalizedStatus);
2604
+ }
2605
+ function isPaymentStatusFailure(status) {
2606
+ const normalizedStatus = normalizePaymentStatusValue(status);
2607
+ return PAYMENT_FAILURE_STATUSES.has(normalizedStatus);
2608
+ }
2609
+ function isPaymentStatusRequiresAction(status) {
2610
+ const normalizedStatus = normalizePaymentStatusValue(status);
2611
+ return PAYMENT_REQUIRES_ACTION_STATUSES.has(normalizedStatus);
2612
+ }
2574
2613
  function normalizeStatusResponse(response) {
2575
2614
  if (!response || typeof response !== "object") {
2576
2615
  return {
@@ -2580,20 +2619,19 @@ function normalizeStatusResponse(response) {
2580
2619
  };
2581
2620
  }
2582
2621
  const res = response;
2583
- const status = res.status?.toLowerCase() || "";
2584
- let standardStatus;
2585
- if (status === "success" || status === "completed" || res.paid === true) {
2586
- standardStatus = "success";
2587
- } else if (status === "failed" || status === "declined" || status === "cancelled") {
2588
- standardStatus = "failed";
2589
- } else if (status === "processing" || status === "pending_confirmation") {
2590
- standardStatus = "processing";
2591
- } else {
2592
- standardStatus = "pending";
2593
- }
2622
+ const normalizedStatus = normalizePaymentStatusValue(res.status ?? void 0);
2623
+ const paidValue = res.paid === true;
2624
+ const derivedPaid = paidValue || [
2625
+ "success",
2626
+ "succeeded",
2627
+ "paid",
2628
+ "captured",
2629
+ "authorized",
2630
+ "completed"
2631
+ ].includes(normalizedStatus);
2594
2632
  return {
2595
- status: standardStatus,
2596
- paid: res.paid || standardStatus === "success",
2633
+ status: normalizedStatus,
2634
+ paid: derivedPaid,
2597
2635
  amount: res.amount,
2598
2636
  currency: res.currency,
2599
2637
  reference: res.reference,
@@ -2664,7 +2702,6 @@ exports.createCimplifyClient = createCimplifyClient;
2664
2702
  exports.createElements = createElements;
2665
2703
  exports.detectMobileMoneyProvider = detectMobileMoneyProvider;
2666
2704
  exports.err = err;
2667
- exports.extractPriceInfo = extractPriceInfo;
2668
2705
  exports.flatMap = flatMap;
2669
2706
  exports.formatMoney = formatMoney;
2670
2707
  exports.formatNumberCompact = formatNumberCompact;
@@ -2685,6 +2722,9 @@ exports.isCimplifyError = isCimplifyError;
2685
2722
  exports.isErr = isErr;
2686
2723
  exports.isOk = isOk;
2687
2724
  exports.isOnSale = isOnSale;
2725
+ exports.isPaymentStatusFailure = isPaymentStatusFailure;
2726
+ exports.isPaymentStatusRequiresAction = isPaymentStatusRequiresAction;
2727
+ exports.isPaymentStatusSuccess = isPaymentStatusSuccess;
2688
2728
  exports.isRetryableError = isRetryableError;
2689
2729
  exports.mapError = mapError;
2690
2730
  exports.mapResult = mapResult;
@@ -2692,8 +2732,6 @@ exports.normalizePaymentResponse = normalizePaymentResponse;
2692
2732
  exports.normalizeStatusResponse = normalizeStatusResponse;
2693
2733
  exports.ok = ok;
2694
2734
  exports.parsePrice = parsePrice;
2695
- exports.parsePricePath = parsePricePath;
2696
- exports.parsedPriceToPriceInfo = parsedPriceToPriceInfo;
2697
2735
  exports.query = query;
2698
2736
  exports.toNullable = toNullable;
2699
2737
  exports.tryCatch = tryCatch;