markpdfdown 0.3.1 → 0.4.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/main/index.js
CHANGED
|
@@ -4358,10 +4358,58 @@ class AuthManager {
|
|
|
4358
4358
|
}
|
|
4359
4359
|
}
|
|
4360
4360
|
const authManager = AuthManager.getInstance();
|
|
4361
|
+
const PAYMENT_STATUSES = /* @__PURE__ */ new Set(["pending", "completed", "failed", "refunded"]);
|
|
4362
|
+
const PAYMENT_PROVIDER_STATUSES = /* @__PURE__ */ new Set([
|
|
4363
|
+
"pending",
|
|
4364
|
+
"processing",
|
|
4365
|
+
"completed",
|
|
4366
|
+
"failed",
|
|
4367
|
+
"canceled",
|
|
4368
|
+
"expired",
|
|
4369
|
+
"refunded",
|
|
4370
|
+
"unknown"
|
|
4371
|
+
]);
|
|
4361
4372
|
class CloudService {
|
|
4362
4373
|
static instance;
|
|
4363
4374
|
constructor() {
|
|
4364
4375
|
}
|
|
4376
|
+
normalizeCheckoutStatus(data) {
|
|
4377
|
+
if (!data || typeof data !== "object") {
|
|
4378
|
+
return null;
|
|
4379
|
+
}
|
|
4380
|
+
const sessionId = typeof data.session_id === "string" ? data.session_id.trim() : "";
|
|
4381
|
+
const status = typeof data.status === "string" ? data.status : "";
|
|
4382
|
+
const providerStatus = typeof data.provider_status === "string" ? data.provider_status : "";
|
|
4383
|
+
const amountUsd = Number(data.amount_usd);
|
|
4384
|
+
const creditsAdded = Number(data.credits_added);
|
|
4385
|
+
const createdAt = typeof data.created_at === "string" ? data.created_at : "";
|
|
4386
|
+
if (!sessionId || !PAYMENT_STATUSES.has(status)) {
|
|
4387
|
+
return null;
|
|
4388
|
+
}
|
|
4389
|
+
if (!providerStatus || !PAYMENT_PROVIDER_STATUSES.has(providerStatus)) {
|
|
4390
|
+
return null;
|
|
4391
|
+
}
|
|
4392
|
+
if (!Number.isFinite(amountUsd) || !Number.isFinite(creditsAdded)) {
|
|
4393
|
+
return null;
|
|
4394
|
+
}
|
|
4395
|
+
if (typeof data.is_final !== "boolean" || typeof data.changed !== "boolean") {
|
|
4396
|
+
return null;
|
|
4397
|
+
}
|
|
4398
|
+
if (!createdAt) {
|
|
4399
|
+
return null;
|
|
4400
|
+
}
|
|
4401
|
+
return {
|
|
4402
|
+
session_id: sessionId,
|
|
4403
|
+
order_id: typeof data.order_id === "string" ? data.order_id : void 0,
|
|
4404
|
+
status,
|
|
4405
|
+
provider_status: providerStatus,
|
|
4406
|
+
is_final: data.is_final,
|
|
4407
|
+
changed: data.changed,
|
|
4408
|
+
amount_usd: amountUsd,
|
|
4409
|
+
credits_added: creditsAdded,
|
|
4410
|
+
created_at: createdAt
|
|
4411
|
+
};
|
|
4412
|
+
}
|
|
4365
4413
|
static getInstance() {
|
|
4366
4414
|
if (!CloudService.instance) {
|
|
4367
4415
|
CloudService.instance = new CloudService();
|
|
@@ -4688,6 +4736,116 @@ class CloudService {
|
|
|
4688
4736
|
};
|
|
4689
4737
|
}
|
|
4690
4738
|
}
|
|
4739
|
+
/**
|
|
4740
|
+
* Create payment checkout session
|
|
4741
|
+
*/
|
|
4742
|
+
async createCheckout(amountUsd) {
|
|
4743
|
+
try {
|
|
4744
|
+
if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
|
|
4745
|
+
return { success: false, error: "Invalid top-up amount" };
|
|
4746
|
+
}
|
|
4747
|
+
const res = await authManager.fetchWithAuth(`${API_BASE_URL}/api/v1/payment/checkout`, {
|
|
4748
|
+
method: "POST",
|
|
4749
|
+
headers: { "Content-Type": "application/json" },
|
|
4750
|
+
body: JSON.stringify({ amount_usd: amountUsd })
|
|
4751
|
+
});
|
|
4752
|
+
const responseJson = await res.json().catch(() => null);
|
|
4753
|
+
if (!res.ok || !responseJson?.success) {
|
|
4754
|
+
const serverMessage = responseJson?.error?.message;
|
|
4755
|
+
const allowedAmounts = responseJson?.error?.details?.allowed_amounts_usd;
|
|
4756
|
+
const allowedSuffix = Array.isArray(allowedAmounts) && allowedAmounts.length > 0 ? ` (allowed: ${allowedAmounts.join(", ")})` : "";
|
|
4757
|
+
return {
|
|
4758
|
+
success: false,
|
|
4759
|
+
error: serverMessage ? `${serverMessage}${allowedSuffix}` : `Failed to create checkout session: ${res.status}`
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4762
|
+
if (!responseJson.data?.checkout_url || !responseJson.data?.session_id) {
|
|
4763
|
+
return { success: false, error: "Invalid checkout response" };
|
|
4764
|
+
}
|
|
4765
|
+
return { success: true, data: responseJson.data };
|
|
4766
|
+
} catch (error) {
|
|
4767
|
+
console.error("[CloudService] createCheckout error:", error);
|
|
4768
|
+
return {
|
|
4769
|
+
success: false,
|
|
4770
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4771
|
+
};
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
/**
|
|
4775
|
+
* Query checkout order status by session_id (supports long polling)
|
|
4776
|
+
*/
|
|
4777
|
+
async getCheckoutStatus(sessionId, waitSeconds = 10) {
|
|
4778
|
+
try {
|
|
4779
|
+
const normalizedSessionId = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
4780
|
+
if (!normalizedSessionId) {
|
|
4781
|
+
return { success: false, error: "Invalid checkout session id" };
|
|
4782
|
+
}
|
|
4783
|
+
if (!Number.isFinite(waitSeconds)) {
|
|
4784
|
+
return { success: false, error: "Invalid wait_seconds" };
|
|
4785
|
+
}
|
|
4786
|
+
const normalizedWaitSeconds = Math.min(30, Math.max(0, Math.floor(waitSeconds)));
|
|
4787
|
+
const params = new URLSearchParams({
|
|
4788
|
+
wait_seconds: String(normalizedWaitSeconds)
|
|
4789
|
+
});
|
|
4790
|
+
const requestTimeoutMs = Math.max((normalizedWaitSeconds + 20) * 1e3, 3e4);
|
|
4791
|
+
const res = await authManager.fetchWithAuth(
|
|
4792
|
+
`${API_BASE_URL}/api/v1/payment/checkout/${encodeURIComponent(normalizedSessionId)}/status?${params.toString()}`,
|
|
4793
|
+
{},
|
|
4794
|
+
{ timeoutMs: requestTimeoutMs }
|
|
4795
|
+
);
|
|
4796
|
+
const responseJson = await res.json().catch(() => null);
|
|
4797
|
+
if (!res.ok || !responseJson?.success) {
|
|
4798
|
+
return {
|
|
4799
|
+
success: false,
|
|
4800
|
+
error: responseJson?.error?.message || `Failed to query checkout status: ${res.status}`
|
|
4801
|
+
};
|
|
4802
|
+
}
|
|
4803
|
+
const data = this.normalizeCheckoutStatus(responseJson.data);
|
|
4804
|
+
if (!data) {
|
|
4805
|
+
return { success: false, error: "Invalid checkout status response" };
|
|
4806
|
+
}
|
|
4807
|
+
return { success: true, data };
|
|
4808
|
+
} catch (error) {
|
|
4809
|
+
console.error("[CloudService] getCheckoutStatus error:", error);
|
|
4810
|
+
return {
|
|
4811
|
+
success: false,
|
|
4812
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4813
|
+
};
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
/**
|
|
4817
|
+
* Trigger proactive reconciliation for a checkout session
|
|
4818
|
+
*/
|
|
4819
|
+
async reconcileCheckout(sessionId) {
|
|
4820
|
+
try {
|
|
4821
|
+
const normalizedSessionId = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
4822
|
+
if (!normalizedSessionId) {
|
|
4823
|
+
return { success: false, error: "Invalid checkout session id" };
|
|
4824
|
+
}
|
|
4825
|
+
const res = await authManager.fetchWithAuth(
|
|
4826
|
+
`${API_BASE_URL}/api/v1/payment/checkout/${encodeURIComponent(normalizedSessionId)}/reconcile`,
|
|
4827
|
+
{ method: "POST" }
|
|
4828
|
+
);
|
|
4829
|
+
const responseJson = await res.json().catch(() => null);
|
|
4830
|
+
if (!res.ok || !responseJson?.success) {
|
|
4831
|
+
return {
|
|
4832
|
+
success: false,
|
|
4833
|
+
error: responseJson?.error?.message || `Failed to reconcile checkout: ${res.status}`
|
|
4834
|
+
};
|
|
4835
|
+
}
|
|
4836
|
+
const data = this.normalizeCheckoutStatus(responseJson.data);
|
|
4837
|
+
if (!data) {
|
|
4838
|
+
return { success: false, error: "Invalid checkout reconcile response" };
|
|
4839
|
+
}
|
|
4840
|
+
return { success: true, data };
|
|
4841
|
+
} catch (error) {
|
|
4842
|
+
console.error("[CloudService] reconcileCheckout error:", error);
|
|
4843
|
+
return {
|
|
4844
|
+
success: false,
|
|
4845
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4846
|
+
};
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4691
4849
|
/**
|
|
4692
4850
|
* Get credits info from the cloud API
|
|
4693
4851
|
*/
|
|
@@ -4753,6 +4911,42 @@ class CloudService {
|
|
|
4753
4911
|
};
|
|
4754
4912
|
}
|
|
4755
4913
|
}
|
|
4914
|
+
/**
|
|
4915
|
+
* Get payment history from the cloud API
|
|
4916
|
+
*/
|
|
4917
|
+
async getPaymentHistory(page = 1, pageSize = 20) {
|
|
4918
|
+
try {
|
|
4919
|
+
const params = new URLSearchParams({
|
|
4920
|
+
page: String(page),
|
|
4921
|
+
page_size: String(pageSize)
|
|
4922
|
+
});
|
|
4923
|
+
const res = await authManager.fetchWithAuth(
|
|
4924
|
+
`${API_BASE_URL}/api/v1/payment/history?${params.toString()}`
|
|
4925
|
+
);
|
|
4926
|
+
if (!res.ok) {
|
|
4927
|
+
const errorBody = await res.json().catch(() => null);
|
|
4928
|
+
return {
|
|
4929
|
+
success: false,
|
|
4930
|
+
error: errorBody?.error?.message || `Failed to fetch payment history: ${res.status}`
|
|
4931
|
+
};
|
|
4932
|
+
}
|
|
4933
|
+
const responseJson = await res.json();
|
|
4934
|
+
if (!responseJson.success) {
|
|
4935
|
+
return { success: false, error: responseJson.error?.message || "Invalid payment history response" };
|
|
4936
|
+
}
|
|
4937
|
+
return {
|
|
4938
|
+
success: true,
|
|
4939
|
+
data: responseJson.data,
|
|
4940
|
+
pagination: responseJson.pagination
|
|
4941
|
+
};
|
|
4942
|
+
} catch (error) {
|
|
4943
|
+
console.error("[CloudService] getPaymentHistory error:", error);
|
|
4944
|
+
return {
|
|
4945
|
+
success: false,
|
|
4946
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4947
|
+
};
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4756
4950
|
/**
|
|
4757
4951
|
* Delete a cloud task (only terminal states can be deleted)
|
|
4758
4952
|
* Terminal states: FAILED=0, COMPLETED=6, CANCELLED=7, PARTIAL_FAILED=8
|
|
@@ -5200,6 +5394,54 @@ function registerCloudHandlers() {
|
|
|
5200
5394
|
};
|
|
5201
5395
|
}
|
|
5202
5396
|
});
|
|
5397
|
+
ipcMain.handle("cloud:createCheckout", async (_, params) => {
|
|
5398
|
+
try {
|
|
5399
|
+
if (!params || typeof params.amountUsd !== "number" || !Number.isFinite(params.amountUsd) || params.amountUsd <= 0) {
|
|
5400
|
+
return { success: false, error: "Invalid amountUsd" };
|
|
5401
|
+
}
|
|
5402
|
+
return await cloudService.createCheckout(params.amountUsd);
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
console.error("[IPC] cloud:createCheckout error:", error);
|
|
5405
|
+
return {
|
|
5406
|
+
success: false,
|
|
5407
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5408
|
+
};
|
|
5409
|
+
}
|
|
5410
|
+
});
|
|
5411
|
+
ipcMain.handle("cloud:getCheckoutStatus", async (_, params) => {
|
|
5412
|
+
try {
|
|
5413
|
+
const sessionId = typeof params?.sessionId === "string" ? params.sessionId.trim() : "";
|
|
5414
|
+
if (!sessionId) {
|
|
5415
|
+
return { success: false, error: "Invalid sessionId" };
|
|
5416
|
+
}
|
|
5417
|
+
const waitSeconds = params?.waitSeconds ?? 10;
|
|
5418
|
+
if (typeof waitSeconds !== "number" || !Number.isFinite(waitSeconds)) {
|
|
5419
|
+
return { success: false, error: "Invalid waitSeconds" };
|
|
5420
|
+
}
|
|
5421
|
+
return await cloudService.getCheckoutStatus(sessionId, waitSeconds);
|
|
5422
|
+
} catch (error) {
|
|
5423
|
+
console.error("[IPC] cloud:getCheckoutStatus error:", error);
|
|
5424
|
+
return {
|
|
5425
|
+
success: false,
|
|
5426
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5427
|
+
};
|
|
5428
|
+
}
|
|
5429
|
+
});
|
|
5430
|
+
ipcMain.handle("cloud:reconcileCheckout", async (_, params) => {
|
|
5431
|
+
try {
|
|
5432
|
+
const sessionId = typeof params?.sessionId === "string" ? params.sessionId.trim() : "";
|
|
5433
|
+
if (!sessionId) {
|
|
5434
|
+
return { success: false, error: "Invalid sessionId" };
|
|
5435
|
+
}
|
|
5436
|
+
return await cloudService.reconcileCheckout(sessionId);
|
|
5437
|
+
} catch (error) {
|
|
5438
|
+
console.error("[IPC] cloud:reconcileCheckout error:", error);
|
|
5439
|
+
return {
|
|
5440
|
+
success: false,
|
|
5441
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5442
|
+
};
|
|
5443
|
+
}
|
|
5444
|
+
});
|
|
5203
5445
|
ipcMain.handle("cloud:getCredits", async () => {
|
|
5204
5446
|
try {
|
|
5205
5447
|
return await cloudService.getCredits();
|
|
@@ -5222,6 +5464,23 @@ function registerCloudHandlers() {
|
|
|
5222
5464
|
};
|
|
5223
5465
|
}
|
|
5224
5466
|
});
|
|
5467
|
+
ipcMain.handle("cloud:getPaymentHistory", async (_, params) => {
|
|
5468
|
+
try {
|
|
5469
|
+
if (!params || typeof params.page !== "number" || !Number.isFinite(params.page) || params.page < 1) {
|
|
5470
|
+
return { success: false, error: "Invalid page" };
|
|
5471
|
+
}
|
|
5472
|
+
if (!params || typeof params.pageSize !== "number" || !Number.isFinite(params.pageSize) || params.pageSize < 1) {
|
|
5473
|
+
return { success: false, error: "Invalid pageSize" };
|
|
5474
|
+
}
|
|
5475
|
+
return await cloudService.getPaymentHistory(params.page, params.pageSize);
|
|
5476
|
+
} catch (error) {
|
|
5477
|
+
console.error("[IPC] cloud:getPaymentHistory error:", error);
|
|
5478
|
+
return {
|
|
5479
|
+
success: false,
|
|
5480
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5481
|
+
};
|
|
5482
|
+
}
|
|
5483
|
+
});
|
|
5225
5484
|
ipcMain.handle("cloud:sseConnect", async () => {
|
|
5226
5485
|
try {
|
|
5227
5486
|
await cloudSSEManager.connect();
|
|
@@ -5494,6 +5753,29 @@ function getIconPath() {
|
|
|
5494
5753
|
return possiblePaths[0];
|
|
5495
5754
|
}
|
|
5496
5755
|
const PROTOCOL_NAME = "markpdfdown";
|
|
5756
|
+
const PAYMENT_CALLBACK_EVENT = "payment:callback";
|
|
5757
|
+
let pendingPaymentCallback = null;
|
|
5758
|
+
function toNullableNumber(value) {
|
|
5759
|
+
if (value === null || value.trim() === "") {
|
|
5760
|
+
return null;
|
|
5761
|
+
}
|
|
5762
|
+
const parsed = Number(value);
|
|
5763
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
5764
|
+
}
|
|
5765
|
+
function dispatchPaymentCallback(payload) {
|
|
5766
|
+
if (!mainWindow) {
|
|
5767
|
+
pendingPaymentCallback = payload;
|
|
5768
|
+
return;
|
|
5769
|
+
}
|
|
5770
|
+
const sendPayload = () => {
|
|
5771
|
+
mainWindow?.webContents.send(PAYMENT_CALLBACK_EVENT, payload);
|
|
5772
|
+
};
|
|
5773
|
+
if (mainWindow.webContents.isLoadingMainFrame()) {
|
|
5774
|
+
mainWindow.webContents.once("did-finish-load", sendPayload);
|
|
5775
|
+
return;
|
|
5776
|
+
}
|
|
5777
|
+
sendPayload();
|
|
5778
|
+
}
|
|
5497
5779
|
protocol.registerSchemesAsPrivileged([
|
|
5498
5780
|
{
|
|
5499
5781
|
scheme: "local-file",
|
|
@@ -5518,15 +5800,18 @@ function handleProtocolUrl(url) {
|
|
|
5518
5800
|
console.warn("[Main] Ignoring URL with unexpected scheme");
|
|
5519
5801
|
return;
|
|
5520
5802
|
}
|
|
5803
|
+
let parsed;
|
|
5804
|
+
let host;
|
|
5805
|
+
let pathname;
|
|
5521
5806
|
try {
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5807
|
+
parsed = new URL(url);
|
|
5808
|
+
host = parsed.host.toLowerCase();
|
|
5809
|
+
pathname = parsed.pathname.replace(/\/+/g, "/").replace(/\/+$/, "");
|
|
5525
5810
|
if (parsed.host.includes("%")) {
|
|
5526
5811
|
console.warn("[Main] Ignoring protocol URL with encoded host");
|
|
5527
5812
|
return;
|
|
5528
5813
|
}
|
|
5529
|
-
const isAllowed = host === "auth" && pathname === "/callback" || host === "auth" && pathname === "";
|
|
5814
|
+
const isAllowed = host === "auth" && pathname === "/callback" || host === "auth" && pathname === "" || host === "payment" && pathname === "/callback";
|
|
5530
5815
|
if (!isAllowed) {
|
|
5531
5816
|
console.warn(`[Main] Ignoring protocol URL with unexpected path: ${host}${pathname}`);
|
|
5532
5817
|
return;
|
|
@@ -5541,7 +5826,23 @@ function handleProtocolUrl(url) {
|
|
|
5541
5826
|
}
|
|
5542
5827
|
mainWindow.focus();
|
|
5543
5828
|
}
|
|
5544
|
-
|
|
5829
|
+
if (host === "auth") {
|
|
5830
|
+
authManager.checkDeviceTokenStatus();
|
|
5831
|
+
return;
|
|
5832
|
+
}
|
|
5833
|
+
if (host === "payment" && pathname === "/callback") {
|
|
5834
|
+
const payload = {
|
|
5835
|
+
url,
|
|
5836
|
+
status: parsed.searchParams.get("status"),
|
|
5837
|
+
sessionId: parsed.searchParams.get("session_id"),
|
|
5838
|
+
amountUsd: toNullableNumber(parsed.searchParams.get("amount_usd")),
|
|
5839
|
+
creditsToAdd: toNullableNumber(parsed.searchParams.get("credits_to_add")),
|
|
5840
|
+
query: Object.fromEntries(parsed.searchParams.entries()),
|
|
5841
|
+
receivedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5842
|
+
};
|
|
5843
|
+
console.log("[Main] Payment callback received:", payload.status || "unknown");
|
|
5844
|
+
dispatchPaymentCallback(payload);
|
|
5845
|
+
}
|
|
5545
5846
|
}
|
|
5546
5847
|
app.on("open-url", (event, url) => {
|
|
5547
5848
|
event.preventDefault();
|
|
@@ -5688,6 +5989,10 @@ function createWindow() {
|
|
|
5688
5989
|
mainWindow = null;
|
|
5689
5990
|
windowManager.setMainWindow(null);
|
|
5690
5991
|
});
|
|
5992
|
+
if (pendingPaymentCallback) {
|
|
5993
|
+
dispatchPaymentCallback(pendingPaymentCallback);
|
|
5994
|
+
pendingPaymentCallback = null;
|
|
5995
|
+
}
|
|
5691
5996
|
}
|
|
5692
5997
|
app.whenReady().then(async () => {
|
|
5693
5998
|
try {
|
package/dist/preload/index.js
CHANGED
|
@@ -68,8 +68,12 @@ electron.contextBridge.exposeInMainWorld("api", {
|
|
|
68
68
|
getTaskResult: (id) => electron.ipcRenderer.invoke("cloud:getTaskResult", id),
|
|
69
69
|
downloadPdf: (id) => electron.ipcRenderer.invoke("cloud:downloadPdf", id),
|
|
70
70
|
getPageImage: (params) => electron.ipcRenderer.invoke("cloud:getPageImage", params),
|
|
71
|
+
createCheckout: (params) => electron.ipcRenderer.invoke("cloud:createCheckout", params),
|
|
72
|
+
getCheckoutStatus: (params) => electron.ipcRenderer.invoke("cloud:getCheckoutStatus", params),
|
|
73
|
+
reconcileCheckout: (params) => electron.ipcRenderer.invoke("cloud:reconcileCheckout", params),
|
|
71
74
|
getCredits: () => electron.ipcRenderer.invoke("cloud:getCredits"),
|
|
72
75
|
getCreditHistory: (params) => electron.ipcRenderer.invoke("cloud:getCreditHistory", params),
|
|
76
|
+
getPaymentHistory: (params) => electron.ipcRenderer.invoke("cloud:getPaymentHistory", params),
|
|
73
77
|
sseConnect: () => electron.ipcRenderer.invoke("cloud:sseConnect"),
|
|
74
78
|
sseDisconnect: () => electron.ipcRenderer.invoke("cloud:sseDisconnect"),
|
|
75
79
|
sseResetAndDisconnect: () => electron.ipcRenderer.invoke("cloud:sseResetAndDisconnect")
|
|
@@ -150,6 +154,18 @@ electron.contextBridge.exposeInMainWorld("api", {
|
|
|
150
154
|
return () => {
|
|
151
155
|
electron.ipcRenderer.removeListener("cloud:taskEvent", handler);
|
|
152
156
|
};
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* 监听支付回跳事件
|
|
160
|
+
* @param callback 事件回调函数
|
|
161
|
+
* @returns 清理函数
|
|
162
|
+
*/
|
|
163
|
+
onPaymentCallback: (callback) => {
|
|
164
|
+
const handler = (_event, data) => callback(data);
|
|
165
|
+
electron.ipcRenderer.on("payment:callback", handler);
|
|
166
|
+
return () => {
|
|
167
|
+
electron.ipcRenderer.removeListener("payment:callback", handler);
|
|
168
|
+
};
|
|
153
169
|
}
|
|
154
170
|
},
|
|
155
171
|
// ==================== Platform APIs ====================
|