@youidian/sdk 3.3.6 → 3.3.10

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
@@ -396,7 +396,7 @@ var LOGIN_CALLBACK_RETURN_HASH_PARAM = "yd_login_return_hash";
396
396
  var LOGIN_CALLBACK_STATE_PARAM = "yd_login_state";
397
397
  var LOGIN_CALLBACK_STORAGE_PREFIX = "yd-login-callback:";
398
398
  var LOGIN_CALLBACK_CURRENT_PAGE_STORAGE_KEY = "yd-login-current-page-callback";
399
- var DEFAULT_IFRAME_LOAD_TIMEOUT_MS = 1500;
399
+ var DEFAULT_IFRAME_LOAD_TIMEOUT_MS = 6e3;
400
400
  function decodeCallbackPayload(value) {
401
401
  try {
402
402
  const padded = value.padEnd(
@@ -801,7 +801,7 @@ var LoginUI = class extends HostedFrameModal {
801
801
  this.iframeLoadingPanel.parentNode.removeChild(this.iframeLoadingPanel);
802
802
  }
803
803
  this.iframeLoadingPanel = null;
804
- if (loginOptions?.fallbackRedirectMode !== "manual") {
804
+ if (loginOptions?.fallbackRedirectMode === "auto") {
805
805
  const panel2 = createLoginRedirectingPanel({
806
806
  description: loginOptions?.fallbackDescription || "The embedded login page is taking longer than expected. Redirecting you to the login page now.",
807
807
  title: loginOptions?.fallbackTitle || "Redirecting to login page"
@@ -1105,6 +1105,43 @@ handleLoginCallbackIfPresent({ autoClose: false });
1105
1105
 
1106
1106
  // src/client.ts
1107
1107
  var PaymentUI = class extends HostedFrameModal {
1108
+ constructor() {
1109
+ super(...arguments);
1110
+ __publicField(this, "activeCheckoutAppId", null);
1111
+ __publicField(this, "activeCheckoutBaseUrl", null);
1112
+ __publicField(this, "activeOrderId", null);
1113
+ __publicField(this, "paymentCompleted", false);
1114
+ __publicField(this, "cancelRequestedOrderId", null);
1115
+ }
1116
+ cancelHostedOrder(reason = "user_cancel", orderId) {
1117
+ const targetOrderId = orderId || this.activeOrderId;
1118
+ if (!targetOrderId || !this.activeCheckoutAppId || !this.activeCheckoutBaseUrl || this.paymentCompleted || this.cancelRequestedOrderId === targetOrderId) {
1119
+ return;
1120
+ }
1121
+ this.cancelRequestedOrderId = targetOrderId;
1122
+ const url = `${this.activeCheckoutBaseUrl}/api/internal/checkout/cancel-order`;
1123
+ const payload = JSON.stringify({
1124
+ appId: this.activeCheckoutAppId,
1125
+ orderId: targetOrderId,
1126
+ reason
1127
+ });
1128
+ if (typeof navigator !== "undefined" && navigator.sendBeacon) {
1129
+ const sent = navigator.sendBeacon(
1130
+ url,
1131
+ new Blob([payload], { type: "application/json" })
1132
+ );
1133
+ if (sent) return;
1134
+ }
1135
+ void fetch(url, {
1136
+ method: "POST",
1137
+ body: payload,
1138
+ headers: { "Content-Type": "text/plain;charset=UTF-8" },
1139
+ keepalive: true,
1140
+ mode: "no-cors"
1141
+ }).catch(() => {
1142
+ this.cancelRequestedOrderId = null;
1143
+ });
1144
+ }
1108
1145
  /**
1109
1146
  * Opens the payment checkout page in an iframe modal.
1110
1147
  * @param urlOrParams - The checkout page URL or payment parameters
@@ -1114,11 +1151,25 @@ var PaymentUI = class extends HostedFrameModal {
1114
1151
  if (typeof document === "undefined") return;
1115
1152
  if (this.modal) return;
1116
1153
  let checkoutUrl;
1154
+ this.activeOrderId = null;
1155
+ this.paymentCompleted = false;
1156
+ this.cancelRequestedOrderId = null;
1117
1157
  if (typeof urlOrParams === "string") {
1118
1158
  checkoutUrl = urlOrParams;
1159
+ try {
1160
+ const parsedUrl = new URL(checkoutUrl);
1161
+ this.activeCheckoutBaseUrl = parsedUrl.origin;
1162
+ const parts = parsedUrl.pathname.split("/").filter(Boolean);
1163
+ const checkoutIndex = parts.indexOf("checkout");
1164
+ this.activeCheckoutAppId = checkoutIndex >= 0 ? parts[checkoutIndex + 1] || null : null;
1165
+ } catch {
1166
+ this.activeCheckoutAppId = null;
1167
+ this.activeCheckoutBaseUrl = null;
1168
+ }
1119
1169
  } else {
1120
1170
  const {
1121
1171
  appId,
1172
+ orderId,
1122
1173
  productId,
1123
1174
  priceId,
1124
1175
  productCode,
@@ -1128,9 +1179,10 @@ var PaymentUI = class extends HostedFrameModal {
1128
1179
  baseUrl = "https://pay.imgto.link"
1129
1180
  } = urlOrParams;
1130
1181
  const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
1131
- const query = new URLSearchParams({
1132
- userId
1133
- });
1182
+ this.activeCheckoutAppId = appId;
1183
+ this.activeCheckoutBaseUrl = base;
1184
+ const query = new URLSearchParams();
1185
+ if (userId) query.set("userId", userId);
1134
1186
  if (customAmount) {
1135
1187
  const amount = Number(customAmount.amount);
1136
1188
  const currency = customAmount.currency.trim().toUpperCase();
@@ -1147,13 +1199,22 @@ var PaymentUI = class extends HostedFrameModal {
1147
1199
  query.set("customAmount", String(amount));
1148
1200
  query.set("customCurrency", currency);
1149
1201
  }
1150
- if (productCode) {
1202
+ if (orderId) {
1203
+ const cleanOrderId = orderId.trim();
1204
+ if (!cleanOrderId) {
1205
+ throw new Error("orderId is required");
1206
+ }
1207
+ this.activeOrderId = cleanOrderId;
1208
+ checkoutUrl = `${base}/checkout/${appId}/orders/${cleanOrderId}`;
1209
+ const queryString = query.toString();
1210
+ if (queryString) checkoutUrl += `?${queryString}`;
1211
+ } else if (productCode) {
1151
1212
  checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?${query.toString()}`;
1152
1213
  } else if (productId && priceId) {
1153
1214
  checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?${query.toString()}`;
1154
1215
  } else {
1155
1216
  throw new Error(
1156
- "Either productCode or both productId and priceId are required"
1217
+ "Either orderId, productCode, or both productId and priceId are required"
1157
1218
  );
1158
1219
  }
1159
1220
  }
@@ -1163,13 +1224,23 @@ var PaymentUI = class extends HostedFrameModal {
1163
1224
  );
1164
1225
  this.openHostedFrame(finalUrl, {
1165
1226
  allowedOrigin: options?.allowedOrigin,
1166
- onCloseButton: () => options?.onCancel?.(),
1227
+ onCloseButton: () => {
1228
+ this.cancelHostedOrder("modal_close");
1229
+ options?.onCancel?.(this.activeOrderId || void 0);
1230
+ },
1167
1231
  onMessage: (data, container) => {
1168
1232
  switch (data.type) {
1233
+ case "PAYMENT_STARTED":
1234
+ if (data.orderId) {
1235
+ this.activeOrderId = data.orderId;
1236
+ }
1237
+ break;
1169
1238
  case "PAYMENT_SUCCESS":
1239
+ this.paymentCompleted = true;
1170
1240
  options?.onSuccess?.(data.orderId);
1171
1241
  break;
1172
1242
  case "PAYMENT_CANCELLED":
1243
+ this.cancelHostedOrder("payment_cancelled", data.orderId);
1173
1244
  options?.onCancel?.(data.orderId);
1174
1245
  break;
1175
1246
  case "PAYMENT_RESIZE":
@@ -1180,6 +1251,7 @@ var PaymentUI = class extends HostedFrameModal {
1180
1251
  }
1181
1252
  break;
1182
1253
  case "PAYMENT_CLOSE":
1254
+ this.cancelHostedOrder("payment_close", data.orderId);
1183
1255
  this.close();
1184
1256
  options?.onClose?.();
1185
1257
  break;
@@ -1396,6 +1468,48 @@ var PaymentClient = class {
1396
1468
  const path = params.toString() ? `/products?${params.toString()}` : "/products";
1397
1469
  return this.request("GET", path);
1398
1470
  }
1471
+ /**
1472
+ * Fetch the realtime stock snapshot for a single product.
1473
+ */
1474
+ async getProductStock(productIdOrCode, options) {
1475
+ const value = productIdOrCode?.trim();
1476
+ if (!value) {
1477
+ throw new Error("productIdOrCode is required");
1478
+ }
1479
+ const params = new URLSearchParams();
1480
+ params.set("productIdOrCode", value);
1481
+ if (options?.lookupBy) params.set("lookupBy", options.lookupBy);
1482
+ if (options?.locale) params.set("locale", options.locale);
1483
+ if (options?.currency) params.set("currency", options.currency);
1484
+ return this.request(
1485
+ "GET",
1486
+ `/products/${encodeURIComponent(value)}/stock?${params.toString()}`
1487
+ );
1488
+ }
1489
+ async getProductStocks(params, options) {
1490
+ const productIds = [
1491
+ ...new Set(
1492
+ (params.productIds || []).map((item) => item.trim()).filter(Boolean)
1493
+ )
1494
+ ];
1495
+ const productCodes = [
1496
+ ...new Set(
1497
+ (params.productCodes || []).map((item) => item.trim()).filter(Boolean)
1498
+ )
1499
+ ];
1500
+ if (productIds.length === 0 && productCodes.length === 0) {
1501
+ throw new Error("productIds or productCodes is required");
1502
+ }
1503
+ const queryOptions = options || params;
1504
+ const query = new URLSearchParams();
1505
+ if (productIds.length > 0) query.set("productIds", productIds.join(","));
1506
+ if (productCodes.length > 0)
1507
+ query.set("productCodes", productCodes.join(","));
1508
+ if (queryOptions.lookupBy) query.set("lookupBy", queryOptions.lookupBy);
1509
+ if (queryOptions.locale) query.set("locale", queryOptions.locale);
1510
+ if (queryOptions.currency) query.set("currency", queryOptions.currency);
1511
+ return this.request("GET", `/products/stocks?${query.toString()}`);
1512
+ }
1399
1513
  /**
1400
1514
  * Create a new order
1401
1515
  * @param params - Order creation parameters
@@ -1404,6 +1518,17 @@ var PaymentClient = class {
1404
1518
  async createOrder(params) {
1405
1519
  return this.request("POST", "/orders", params);
1406
1520
  }
1521
+ /**
1522
+ * Create a paid manual bank transfer order.
1523
+ * @param params - Order creation parameters without channel
1524
+ * @returns Paid order details
1525
+ */
1526
+ async createBankTransferOrder(params) {
1527
+ return this.request("POST", "/orders", {
1528
+ ...params,
1529
+ channel: "BANK_TRANSFER"
1530
+ });
1531
+ }
1407
1532
  /**
1408
1533
  * Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
1409
1534
  * @param params - Mini program order parameters
@@ -1426,6 +1551,36 @@ var PaymentClient = class {
1426
1551
  async payOrder(orderId, params) {
1427
1552
  return this.request("POST", `/orders/${orderId}/pay`, params);
1428
1553
  }
1554
+ /**
1555
+ * Cancel a pending order and release its inventory reservation.
1556
+ * Paid/refunded/failed orders are returned unchanged by the gateway.
1557
+ */
1558
+ async cancelOrder(orderId, params) {
1559
+ const value = orderId?.trim();
1560
+ if (!value) {
1561
+ throw new Error("orderId is required");
1562
+ }
1563
+ return this.request(
1564
+ "POST",
1565
+ `/orders/${encodeURIComponent(value)}/cancel`,
1566
+ params || {}
1567
+ );
1568
+ }
1569
+ /**
1570
+ * Complete a zero-amount FREE order.
1571
+ * This marks the pending order as paid and triggers normal paid-order side effects.
1572
+ */
1573
+ async completeFreeOrder(orderId) {
1574
+ const value = orderId?.trim();
1575
+ if (!value) {
1576
+ throw new Error("orderId is required");
1577
+ }
1578
+ return this.request(
1579
+ "POST",
1580
+ `/orders/${encodeURIComponent(value)}/free/complete`,
1581
+ {}
1582
+ );
1583
+ }
1429
1584
  /**
1430
1585
  * Query order status
1431
1586
  * @param orderId - The order ID to query