@paytaca/opencode-plugin 0.1.13 → 0.1.15
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/README.md +1 -1
- package/dist/bundled/proxy.d.ts +1 -1
- package/dist/bundled/proxy.d.ts.map +1 -1
- package/dist/bundled/proxy.js +184 -101
- package/dist/bundled/proxy.js.map +1 -1
- package/dist/bundled/wrapper.d.ts +1 -1
- package/dist/bundled/wrapper.d.ts.map +1 -1
- package/dist/bundled/wrapper.js +7 -2
- package/dist/bundled/wrapper.js.map +1 -1
- package/dist/config.d.ts +0 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -26
- package/dist/config.js.map +1 -1
- package/dist/proxy.d.ts +0 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +112 -106
- package/dist/proxy.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/bundled/proxy.js
CHANGED
|
@@ -45,37 +45,6 @@ function log(message) {
|
|
|
45
45
|
logStream.write(timestamp + ' [Proxy] ' + message + '\\n');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// Heartbeat monitoring - proxy exits if heartbeat is stale
|
|
49
|
-
const HEARTBEAT_FILE = path.join(LOG_DIR, 'heartbeat');
|
|
50
|
-
const HEARTBEAT_TIMEOUT = 300000; // 5 minutes
|
|
51
|
-
|
|
52
|
-
function checkHeartbeat() {
|
|
53
|
-
try {
|
|
54
|
-
if (!fs.existsSync(HEARTBEAT_FILE)) {
|
|
55
|
-
// No heartbeat file yet, wait a bit
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
const heartbeat = parseInt(fs.readFileSync(HEARTBEAT_FILE, 'utf8'));
|
|
59
|
-
if (heartbeat === 0) {
|
|
60
|
-
// Special value: plugin is stopping
|
|
61
|
-
log('Heartbeat = 0, shutting down...');
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
const elapsed = Date.now() - heartbeat;
|
|
65
|
-
if (elapsed > HEARTBEAT_TIMEOUT) {
|
|
66
|
-
log('Heartbeat stale (' + elapsed + 'ms), shutting down...');
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
return true;
|
|
70
|
-
} catch (err) {
|
|
71
|
-
// If we can't read heartbeat, keep running (graceful degradation)
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Heartbeat checker reference (will be started after server creation)
|
|
77
|
-
let heartbeatChecker = null;
|
|
78
|
-
|
|
79
48
|
// Store pending payment requests per wallet hash
|
|
80
49
|
// Each entry: { body, modelId, displayName, durationMinutes, tiers[], step }
|
|
81
50
|
// step: 'tier_select' (user must pick a tier) or 'approval' (yes/no)
|
|
@@ -172,22 +141,19 @@ function sseDone(res) {
|
|
|
172
141
|
res.write('data: [DONE]\\n\\n');
|
|
173
142
|
}
|
|
174
143
|
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
model: modelName,
|
|
189
|
-
choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }],
|
|
190
|
-
});
|
|
144
|
+
// Stream the tier-selection prompt body (SSE lines) into an in-progress response.
|
|
145
|
+
// When includeRole is false the leading role delta is skipped, so the body can be
|
|
146
|
+
// appended to a stream that already emitted content (e.g. after a payment failure).
|
|
147
|
+
async function streamTierSelectionBody(res, walletHash, modelName, tiers, includeRole) {
|
|
148
|
+
if (includeRole !== false) {
|
|
149
|
+
sseLine(res, {
|
|
150
|
+
id: 'tier-1',
|
|
151
|
+
object: 'chat.completion.chunk',
|
|
152
|
+
created: Math.floor(Date.now() / 1000),
|
|
153
|
+
model: modelName,
|
|
154
|
+
choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
191
157
|
|
|
192
158
|
// Loading sequence
|
|
193
159
|
sseLine(res, {
|
|
@@ -275,7 +241,19 @@ async function streamTierSelectionPrompt(res, walletHash, modelName, tiers) {
|
|
|
275
241
|
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
|
|
276
242
|
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
277
243
|
});
|
|
244
|
+
}
|
|
278
245
|
|
|
246
|
+
// Build and stream a full tier-selection prompt (headers + body + [DONE]) to the client.
|
|
247
|
+
async function streamTierSelectionPrompt(res, walletHash, modelName, tiers) {
|
|
248
|
+
if (!res.headersSent) {
|
|
249
|
+
res.writeHead(200, {
|
|
250
|
+
'Content-Type': 'text/event-stream',
|
|
251
|
+
'Cache-Control': 'no-cache',
|
|
252
|
+
'X-Payment-Required': 'true',
|
|
253
|
+
'Connection': 'keep-alive',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
await streamTierSelectionBody(res, walletHash, modelName, tiers, true);
|
|
279
257
|
sseDone(res);
|
|
280
258
|
res.end();
|
|
281
259
|
}
|
|
@@ -567,8 +545,15 @@ function forceNonStreaming(body) {
|
|
|
567
545
|
}
|
|
568
546
|
|
|
569
547
|
// Convert a chat.completion JSON object to SSE format
|
|
570
|
-
function jsonToSse(res, chatCompletion) {
|
|
571
|
-
|
|
548
|
+
function jsonToSse(res, chatCompletion, opts) {
|
|
549
|
+
opts = opts || {};
|
|
550
|
+
if (res.destroyed || res.writableEnded) {
|
|
551
|
+
log('jsonToSse: response already destroyed/ended, cannot send SSE');
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const message = chatCompletion.choices?.[0]?.message || {};
|
|
555
|
+
const content = message.content || '';
|
|
556
|
+
const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : null;
|
|
572
557
|
const model = chatCompletion.model || chatCompletion.model_id || 'deepseek/deepseek-v4-flash';
|
|
573
558
|
const created = chatCompletion.created || Math.floor(Date.now() / 1000);
|
|
574
559
|
|
|
@@ -580,6 +565,7 @@ function jsonToSse(res, chatCompletion) {
|
|
|
580
565
|
'Connection': 'keep-alive',
|
|
581
566
|
});
|
|
582
567
|
} catch (e) {
|
|
568
|
+
log('jsonToSse writeHead failed: ' + e.message);
|
|
583
569
|
return;
|
|
584
570
|
}
|
|
585
571
|
}
|
|
@@ -593,45 +579,115 @@ function jsonToSse(res, chatCompletion) {
|
|
|
593
579
|
choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }],
|
|
594
580
|
});
|
|
595
581
|
} catch (e) {
|
|
582
|
+
log('jsonToSse: failed to write role delta: ' + e.message);
|
|
596
583
|
}
|
|
597
584
|
|
|
585
|
+
const allContent = (opts.prependContent || '') + content;
|
|
598
586
|
const chunkSize = 20;
|
|
599
587
|
let chunksWritten = 0;
|
|
600
|
-
for (let i = 0; i <
|
|
588
|
+
for (let i = 0; i < allContent.length; i += chunkSize) {
|
|
601
589
|
try {
|
|
602
590
|
sseLine(res, {
|
|
603
591
|
id: 'chatcmpl-' + (i + 2),
|
|
604
592
|
object: 'chat.completion.chunk',
|
|
605
593
|
created,
|
|
606
594
|
model,
|
|
607
|
-
choices: [{ index: 0, delta: { content:
|
|
595
|
+
choices: [{ index: 0, delta: { content: allContent.slice(i, i + chunkSize) }, finish_reason: null }],
|
|
608
596
|
});
|
|
609
597
|
chunksWritten++;
|
|
610
598
|
} catch (e) {
|
|
599
|
+
log('jsonToSse: failed to write content chunk ' + (i / chunkSize) + ': ' + e.message);
|
|
611
600
|
break;
|
|
612
601
|
}
|
|
613
602
|
}
|
|
614
603
|
|
|
604
|
+
let finishReason = 'stop';
|
|
605
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
606
|
+
const toolCallDeltas = [];
|
|
607
|
+
for (let i = 0; i < toolCalls.length; i++) {
|
|
608
|
+
const tc = toolCalls[i] || {};
|
|
609
|
+
const fn = tc.function || {};
|
|
610
|
+
let args = fn.arguments;
|
|
611
|
+
if (args !== undefined && typeof args !== 'string') {
|
|
612
|
+
try { args = JSON.stringify(args); } catch (e) { args = String(args); }
|
|
613
|
+
}
|
|
614
|
+
toolCallDeltas.push({
|
|
615
|
+
index: i,
|
|
616
|
+
id: tc.id || ('call_' + i),
|
|
617
|
+
type: 'function',
|
|
618
|
+
function: {
|
|
619
|
+
name: fn.name || '',
|
|
620
|
+
arguments: args === undefined || args === null ? '' : String(args),
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
sseLine(res, {
|
|
626
|
+
id: 'chatcmpl-tools',
|
|
627
|
+
object: 'chat.completion.chunk',
|
|
628
|
+
created,
|
|
629
|
+
model,
|
|
630
|
+
choices: [{ index: 0, delta: { tool_calls: toolCallDeltas }, finish_reason: null }],
|
|
631
|
+
});
|
|
632
|
+
} catch (e) {
|
|
633
|
+
log('jsonToSse: failed to write tool_calls: ' + e.message);
|
|
634
|
+
}
|
|
635
|
+
finishReason = 'tool_calls';
|
|
636
|
+
}
|
|
637
|
+
|
|
615
638
|
try {
|
|
616
639
|
sseLine(res, {
|
|
617
640
|
id: 'chatcmpl-done',
|
|
618
641
|
object: 'chat.completion.chunk',
|
|
619
642
|
created,
|
|
620
643
|
model,
|
|
621
|
-
choices: [{ index: 0, delta: {}, finish_reason:
|
|
644
|
+
choices: [{ index: 0, delta: {}, finish_reason: finishReason }],
|
|
622
645
|
usage: chatCompletion.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
623
646
|
});
|
|
624
647
|
} catch (e) {
|
|
648
|
+
log('jsonToSse: failed to write final delta: ' + e.message);
|
|
625
649
|
}
|
|
626
650
|
|
|
627
651
|
try {
|
|
628
652
|
sseDone(res);
|
|
629
653
|
} catch (e) {
|
|
654
|
+
log('jsonToSse: failed to write [DONE]: ' + e.message);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
try {
|
|
658
|
+
res.end();
|
|
659
|
+
} catch (e) {
|
|
660
|
+
log('jsonToSse: res.end() failed: ' + e.message);
|
|
630
661
|
}
|
|
662
|
+
}
|
|
631
663
|
|
|
664
|
+
// Stream a payment-failure message, then re-show the tier-selection prompt so the
|
|
665
|
+
// user can retry the same or a different plan without sending another message.
|
|
666
|
+
// The pending payment is restored to the tier-select step so the next tier pick is
|
|
667
|
+
// handled by the proxy instead of being forwarded fresh to Django.
|
|
668
|
+
async function streamPaymentFailureAndRetry(res, walletHash, pendingPayload, message) {
|
|
669
|
+
try {
|
|
670
|
+
sseLine(res, {
|
|
671
|
+
id: 'pay-err',
|
|
672
|
+
object: 'chat.completion.chunk',
|
|
673
|
+
created: Math.floor(Date.now() / 1000),
|
|
674
|
+
model: 'deepseek/deepseek-v4-flash',
|
|
675
|
+
choices: [{ index: 0, delta: { content: message }, finish_reason: 'stop' }],
|
|
676
|
+
});
|
|
677
|
+
} catch (e) {
|
|
678
|
+
}
|
|
679
|
+
pendingPayload.step = 'tier_select';
|
|
680
|
+
pendingPayload.durationMinutes = null;
|
|
681
|
+
pendingPayments.set(walletHash, pendingPayload);
|
|
632
682
|
try {
|
|
683
|
+
const tiers = Array.isArray(pendingPayload.tiers) ? pendingPayload.tiers : [];
|
|
684
|
+
if (tiers.length > 0) {
|
|
685
|
+
await streamTierSelectionBody(res, walletHash, pendingPayload.displayName || pendingPayload.modelId || 'AI Model', tiers, false);
|
|
686
|
+
}
|
|
687
|
+
sseDone(res);
|
|
633
688
|
res.end();
|
|
634
689
|
} catch (e) {
|
|
690
|
+
try { res.end(); } catch (e2) {}
|
|
635
691
|
}
|
|
636
692
|
}
|
|
637
693
|
|
|
@@ -696,7 +752,17 @@ function runPaytacaPay(djangoUrl, body, walletHash, extraHeaders, callback) {
|
|
|
696
752
|
callback(new Error('Could not parse paytaca pay response: ' + err.message));
|
|
697
753
|
}
|
|
698
754
|
} else {
|
|
699
|
-
|
|
755
|
+
// Try to extract error from stdout (wrapper writes JSON errors to stdout, not stderr)
|
|
756
|
+
let wrapperErr = stderr.trim();
|
|
757
|
+
if (!wrapperErr) {
|
|
758
|
+
try {
|
|
759
|
+
const parsed = JSON.parse(stdout.trim());
|
|
760
|
+
wrapperErr = parsed.error || 'Unknown error';
|
|
761
|
+
} catch {
|
|
762
|
+
wrapperErr = stdout.trim() || 'paytaca pay wrapper exited with code ' + code;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
callback(new Error(wrapperErr));
|
|
700
766
|
}
|
|
701
767
|
});
|
|
702
768
|
|
|
@@ -1062,42 +1128,49 @@ const server = http.createServer(async (req, res) => {
|
|
|
1062
1128
|
res.write(': keepalive\\n\\n');
|
|
1063
1129
|
}, 2000);
|
|
1064
1130
|
|
|
1065
|
-
runPaytacaPay(BACKEND_URL + '/v1', pendingPayload.body, walletHash, extraHeaders, (err, responseJson) => {
|
|
1131
|
+
runPaytacaPay(BACKEND_URL + '/v1', pendingPayload.body, walletHash, extraHeaders, async (err, responseJson) => {
|
|
1066
1132
|
pendingPayments.delete(walletHash);
|
|
1067
1133
|
clearInterval(keepalive);
|
|
1068
1134
|
|
|
1069
1135
|
if (err) {
|
|
1070
1136
|
log('paytaca pay failed: ' + err.message);
|
|
1071
|
-
if (res.headersSent) {
|
|
1137
|
+
if (res.headersSent && !res.destroyed && !res.writableEnded) {
|
|
1138
|
+
await streamPaymentFailureAndRetry(res, walletHash, pendingPayload, '\\n\\n❌ Payment failed: ' + err.message + '\\n\\n');
|
|
1139
|
+
} else if (!res.headersSent) {
|
|
1072
1140
|
try {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
res.end();
|
|
1077
|
-
} catch (e) {}
|
|
1141
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1142
|
+
res.end(JSON.stringify({ error: 'Payment failed', message: err.message, details: 'Please check your wallet balance and try again.' }));
|
|
1143
|
+
} catch (e) { log('Failed to send payment error response: ' + e.message); }
|
|
1078
1144
|
} else {
|
|
1079
|
-
|
|
1080
|
-
res.end(JSON.stringify({ error: 'Payment failed', message: err.message, details: 'Please check your wallet balance and try again.' }));
|
|
1145
|
+
log('Cannot send payment failure — response already ended or destroyed');
|
|
1081
1146
|
}
|
|
1082
1147
|
return;
|
|
1083
1148
|
}
|
|
1084
1149
|
|
|
1085
1150
|
if (!responseJson.success) {
|
|
1086
1151
|
const isTimeout = responseJson.timeout;
|
|
1087
|
-
const sseContent = isTimeout ? '\\n\\n⏱️ Response timed out. Your payment was processed \\u2014 check credits with \\'credits\\' and try again' : '\\n\\n❌ Payment failed: ' + (responseJson.error || 'Unknown error');
|
|
1152
|
+
const sseContent = isTimeout ? '\\n\\n⏱️ Response timed out. Your payment was processed \\u2014 check credits with \\'credits\\' and try again' : '\\n\\n❌ Payment failed: ' + (responseJson.error || 'Unknown error') + '\\n\\n';
|
|
1088
1153
|
const errLabel = isTimeout ? 'Response timeout' : 'Payment failed';
|
|
1089
1154
|
const errMsg = isTimeout ? 'Response timed out. Payment was processed.' : responseJson.error;
|
|
1090
1155
|
const errDetails = isTimeout ? 'Try again or check credits with \\'credits\\'.' : 'Please check your balance and try again.';
|
|
1091
|
-
if (res.headersSent) {
|
|
1156
|
+
if (res.headersSent && !res.destroyed && !res.writableEnded) {
|
|
1157
|
+
if (isTimeout) {
|
|
1158
|
+
try {
|
|
1159
|
+
sseLine(res, { id: 'pay-err', object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000), model: 'deepseek/deepseek-v4-flash', choices: [{ index: 0, delta: { content: sseContent }, finish_reason: 'stop' }] });
|
|
1160
|
+
sseLine(res, { id: 'pay-err-done', object: 'chat.completion.chunk', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] });
|
|
1161
|
+
sseDone(res);
|
|
1162
|
+
res.end();
|
|
1163
|
+
} catch (e) { log('Failed to send timeout error via SSE: ' + e.message); }
|
|
1164
|
+
} else {
|
|
1165
|
+
await streamPaymentFailureAndRetry(res, walletHash, pendingPayload, sseContent);
|
|
1166
|
+
}
|
|
1167
|
+
} else if (!res.headersSent) {
|
|
1092
1168
|
try {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
res.end();
|
|
1097
|
-
} catch (e) {}
|
|
1169
|
+
res.writeHead(responseJson.status || 500, { 'Content-Type': 'application/json' });
|
|
1170
|
+
res.end(JSON.stringify({ error: errLabel, message: errMsg, details: errDetails }));
|
|
1171
|
+
} catch (e) { log('Failed to send payment error JSON: ' + e.message); }
|
|
1098
1172
|
} else {
|
|
1099
|
-
|
|
1100
|
-
res.end(JSON.stringify({ error: errLabel, message: errMsg, details: errDetails }));
|
|
1173
|
+
log('Cannot send payment error — response already ended or destroyed');
|
|
1101
1174
|
}
|
|
1102
1175
|
return;
|
|
1103
1176
|
}
|
|
@@ -1111,15 +1184,22 @@ const server = http.createServer(async (req, res) => {
|
|
|
1111
1184
|
|
|
1112
1185
|
log('paytaca pay succeeded. Returning chat response.');
|
|
1113
1186
|
|
|
1187
|
+
if (res.destroyed || res.writableEnded) {
|
|
1188
|
+
log('Payment succeeded but response connection is gone — cannot deliver chat response');
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1114
1192
|
if (wasStreaming) {
|
|
1115
1193
|
try {
|
|
1116
|
-
jsonToSse(res, chatCompletion);
|
|
1117
|
-
} catch (e) {}
|
|
1194
|
+
jsonToSse(res, chatCompletion, { prependContent: '\\n💳 Payment successful — generating your response...\\n\\n' });
|
|
1195
|
+
} catch (e) { log('jsonToSse threw: ' + e.message); }
|
|
1118
1196
|
} else {
|
|
1119
1197
|
try {
|
|
1120
|
-
res.
|
|
1198
|
+
if (!res.headersSent) {
|
|
1199
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1200
|
+
}
|
|
1121
1201
|
res.end(JSON.stringify(chatCompletion));
|
|
1122
|
-
} catch (e) {}
|
|
1202
|
+
} catch (e) { log('Failed to send non-streaming response: ' + e.message); }
|
|
1123
1203
|
}
|
|
1124
1204
|
});
|
|
1125
1205
|
return;
|
|
@@ -1161,16 +1241,20 @@ const server = http.createServer(async (req, res) => {
|
|
|
1161
1241
|
clearInterval(keepalive);
|
|
1162
1242
|
if (err) {
|
|
1163
1243
|
log('paytaca pay failed: ' + err.message);
|
|
1164
|
-
if (res.headersSent) {
|
|
1244
|
+
if (res.headersSent && !res.destroyed && !res.writableEnded) {
|
|
1165
1245
|
try {
|
|
1166
1246
|
sseLine(res, { id: 'pay-err', object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000), model: 'deepseek/deepseek-v4-flash', choices: [{ index: 0, delta: { content: '\\n\\n❌ Payment failed: ' + err.message }, finish_reason: 'stop' }] });
|
|
1167
1247
|
sseLine(res, { id: 'pay-err-done', object: 'chat.completion.chunk', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] });
|
|
1168
1248
|
sseDone(res);
|
|
1169
1249
|
res.end();
|
|
1170
|
-
} catch (e) {}
|
|
1250
|
+
} catch (e) { log('Failed to send payment error via SSE: ' + e.message); }
|
|
1251
|
+
} else if (!res.headersSent) {
|
|
1252
|
+
try {
|
|
1253
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1254
|
+
res.end(JSON.stringify({ error: 'Payment failed', message: err.message, details: 'Please check your wallet balance and try again.' }));
|
|
1255
|
+
} catch (e) { log('Failed to send payment error JSON: ' + e.message); }
|
|
1171
1256
|
} else {
|
|
1172
|
-
|
|
1173
|
-
res.end(JSON.stringify({ error: 'Payment failed', message: err.message, details: 'Please check your wallet balance and try again.' }));
|
|
1257
|
+
log('Cannot send payment failure — response already ended or destroyed');
|
|
1174
1258
|
}
|
|
1175
1259
|
return;
|
|
1176
1260
|
}
|
|
@@ -1181,16 +1265,20 @@ const server = http.createServer(async (req, res) => {
|
|
|
1181
1265
|
const errLabel = isTimeout ? 'Response timeout' : 'Payment failed';
|
|
1182
1266
|
const errMsg = isTimeout ? 'Response timed out. Payment was processed.' : responseJson.error;
|
|
1183
1267
|
const errDetails = isTimeout ? 'Try again or check credits with \\'credits\\'.' : 'Please check your balance and try again.';
|
|
1184
|
-
if (res.headersSent) {
|
|
1268
|
+
if (res.headersSent && !res.destroyed && !res.writableEnded) {
|
|
1185
1269
|
try {
|
|
1186
1270
|
sseLine(res, { id: 'pay-err', object: 'chat.completion.chunk', created: Math.floor(Date.now() / 1000), model: 'deepseek/deepseek-v4-flash', choices: [{ index: 0, delta: { content: sseContent }, finish_reason: 'stop' }] });
|
|
1187
1271
|
sseLine(res, { id: 'pay-err-done', object: 'chat.completion.chunk', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] });
|
|
1188
1272
|
sseDone(res);
|
|
1189
1273
|
res.end();
|
|
1190
|
-
} catch (e) {}
|
|
1274
|
+
} catch (e) { log('Failed to send error via SSE: ' + e.message); }
|
|
1275
|
+
} else if (!res.headersSent) {
|
|
1276
|
+
try {
|
|
1277
|
+
res.writeHead(responseJson.status || 500, { 'Content-Type': 'application/json' });
|
|
1278
|
+
res.end(JSON.stringify({ error: errLabel, message: errMsg, details: errDetails }));
|
|
1279
|
+
} catch (e) { log('Failed to send error JSON: ' + e.message); }
|
|
1191
1280
|
} else {
|
|
1192
|
-
|
|
1193
|
-
res.end(JSON.stringify({ error: errLabel, message: errMsg, details: errDetails }));
|
|
1281
|
+
log('Cannot send payment error — response already ended or destroyed');
|
|
1194
1282
|
}
|
|
1195
1283
|
return;
|
|
1196
1284
|
}
|
|
@@ -1203,16 +1291,23 @@ const server = http.createServer(async (req, res) => {
|
|
|
1203
1291
|
} catch {}
|
|
1204
1292
|
|
|
1205
1293
|
log('paytaca pay succeeded. Returning chat response.');
|
|
1294
|
+
|
|
1295
|
+
if (res.destroyed || res.writableEnded) {
|
|
1296
|
+
log('Payment succeeded but response connection is gone — cannot deliver chat response');
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1206
1299
|
|
|
1207
1300
|
if (wasStreaming) {
|
|
1208
1301
|
try {
|
|
1209
|
-
jsonToSse(res, chatCompletion);
|
|
1210
|
-
} catch (e) {}
|
|
1302
|
+
jsonToSse(res, chatCompletion, { prependContent: '\\n💳 Payment successful — generating your response...\\n\\n' });
|
|
1303
|
+
} catch (e) { log('jsonToSse threw: ' + e.message); }
|
|
1211
1304
|
} else {
|
|
1212
1305
|
try {
|
|
1213
|
-
res.
|
|
1306
|
+
if (!res.headersSent) {
|
|
1307
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1308
|
+
}
|
|
1214
1309
|
res.end(JSON.stringify(chatCompletion));
|
|
1215
|
-
} catch (e) {}
|
|
1310
|
+
} catch (e) { log('Failed to send non-streaming response: ' + e.message); }
|
|
1216
1311
|
}
|
|
1217
1312
|
});
|
|
1218
1313
|
return;
|
|
@@ -1311,6 +1406,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1311
1406
|
pendingPayments.set(walletHash, {
|
|
1312
1407
|
body: body,
|
|
1313
1408
|
modelId: modelId,
|
|
1409
|
+
displayName: displayName,
|
|
1314
1410
|
durationMinutes: null,
|
|
1315
1411
|
tiers: tiers,
|
|
1316
1412
|
step: tiers ? 'tier_select' : 'approval'
|
|
@@ -1425,24 +1521,11 @@ server.on('error', (err) => {
|
|
|
1425
1521
|
|
|
1426
1522
|
server.listen(PROXY_PORT, () => {
|
|
1427
1523
|
log('Paytaca AI Proxy running on http://localhost:' + PROXY_PORT);
|
|
1428
|
-
log('Forwarding to
|
|
1524
|
+
log('Forwarding to ' + BACKEND_URL);
|
|
1429
1525
|
log('Discovery: http://localhost:' + PROXY_PORT + '/v1/config');
|
|
1430
1526
|
log('Managed by OpenCode plugin');
|
|
1431
1527
|
});
|
|
1432
1528
|
|
|
1433
|
-
// Start heartbeat checker after server is created
|
|
1434
|
-
heartbeatChecker = setInterval(() => {
|
|
1435
|
-
if (!checkHeartbeat()) {
|
|
1436
|
-
clearInterval(heartbeatChecker);
|
|
1437
|
-
log('Closing server due to missing heartbeat');
|
|
1438
|
-
server.close(() => {
|
|
1439
|
-
process.exit(0);
|
|
1440
|
-
});
|
|
1441
|
-
// Force exit after 2 seconds if graceful shutdown fails
|
|
1442
|
-
setTimeout(() => process.exit(0), 2000);
|
|
1443
|
-
}
|
|
1444
|
-
}, 5000);
|
|
1445
|
-
|
|
1446
1529
|
// Graceful shutdown
|
|
1447
1530
|
process.on('SIGTERM', () => {
|
|
1448
1531
|
log('Shutting down proxy...');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/bundled/proxy.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,6DAA6D;;;AAEhD,QAAA,oBAAoB,GAAG
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/bundled/proxy.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,6DAA6D;;;AAEhD,QAAA,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6/CnC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const WRAPPER_SCRIPT_CONTENT = "#!/usr/bin/env node\n/**\n * Paytaca Pay Wrapper \u2014 handles large request bodies by reading from a file.\n * Imports paytaca-cli modules directly (avoids CLI argument size limits).\n */\n\nimport { readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// Find paytaca-cli installation\nfunction findPaytacaCliPath() {\n const possiblePaths = [];\n \n // Try to get global npm root\n try {\n const globalPath = execSync('npm root -g', { encoding: 'utf8' }).trim();\n possiblePaths.push(\n join(globalPath, 'paytaca-cli'),\n join(globalPath, 'opencode-plugin', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Common global locations\n possiblePaths.push(\n '/usr/lib/node_modules/paytaca-cli',\n '/usr/local/lib/node_modules/paytaca-cli',\n '/opt/homebrew/lib/node_modules/paytaca-cli',\n );\n \n // Try current file's node_modules (for bundled installs)\n try {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n possiblePaths.push(\n join(currentDir, '..', 'node_modules', 'paytaca-cli'),\n join(currentDir, '..', '..', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Find first valid path\n for (const basePath of possiblePaths) {\n try {\n const walletPath = join(basePath, 'dist', 'wallet', 'index.js');\n readFileSync(walletPath);\n return basePath;\n } catch {}\n }\n \n throw new Error('paytaca-cli not found. Try reinstalling opencode-plugin: npm install @paytaca/opencode-plugin');\n}\n\n// Load paytaca-cli modules\nlet loadMnemonic, loadWallet, LibauthHDWallet, X402Payer, parsePaymentRequiredJson, selectBchPaymentRequirements, BCH_DERIVATION_PATH;\n\ntry {\n const basePath = findPaytacaCliPath();\n \n ({ loadMnemonic, loadWallet } = await import(join(basePath, 'dist', 'wallet', 'index.js')));\n ({ LibauthHDWallet } = await import(join(basePath, 'dist', 'wallet', 'keys.js')));\n ({ X402Payer } = await import(join(basePath, 'dist', 'wallet', 'x402.js')));\n ({ parsePaymentRequiredJson, selectBchPaymentRequirements } = await import(join(basePath, 'dist', 'utils', 'x402.js')));\n ({ BCH_DERIVATION_PATH } = await import(join(basePath, 'dist', 'utils', 'network.js')));\n} catch (err) {\n console.log(JSON.stringify({ success: false, error: 'Failed to load paytaca-cli: ' + err.message }));\n process.exit(1);\n}\n\nasync function main() {\n const configPath = process.argv[2];\n if (!configPath) {\n console.log(JSON.stringify({ success: false, error: 'Usage: node paytaca-pay-wrapper.mjs <config.json>' }));\n process.exit(1);\n }\n\n const config = JSON.parse(readFileSync(configPath, 'utf8'));\n const { url, method, headers, bodyFile, chipnet, confirmed } = config;\n\n const body = readFileSync(bodyFile, 'utf8');\n\n const data = loadMnemonic();\n if (!data) {\n console.log(JSON.stringify({ success: false, error: 'No wallet found. Run paytaca wallet create first.' }));\n process.exit(1);\n }\n\n const wallet = loadWallet();\n const isChipnet = Boolean(chipnet);\n const bchWallet = wallet.forNetwork(isChipnet);\n const hdWallet = new LibauthHDWallet(data.mnemonic, BCH_DERIVATION_PATH, isChipnet ? 'chipnet' : 'mainnet');\n const x402Payer = new X402Payer({ hdWallet, addressIndex: 0 });\n\n try {\n const result = await executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed);\n console.log(JSON.stringify(result, null, 2));\n } catch (err) {\n console.log(JSON.stringify({ success: false, error: err.message || String(err) }, null, 2));\n process.exit(1);\n }\n}\n\nasync function executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed) {\n const response = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(
|
|
1
|
+
export declare const WRAPPER_SCRIPT_CONTENT = "#!/usr/bin/env node\n/**\n * Paytaca Pay Wrapper \u2014 handles large request bodies by reading from a file.\n * Imports paytaca-cli modules directly (avoids CLI argument size limits).\n */\n\nimport { readFileSync } from 'fs';\nimport { execSync } from 'child_process';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// How long to wait for the server to respond before treating the payment as timed out.\n// Default 240s so heavy non-streaming generations (large context / long output) can\n// complete; override with PAYTACA_PAY_TIMEOUT_MS.\nconst PAY_TIMEOUT_MS = Number(process.env.PAYTACA_PAY_TIMEOUT_MS || 240000);\n\n// Find paytaca-cli installation\nfunction findPaytacaCliPath() {\n const possiblePaths = [];\n \n // Try to get global npm root\n try {\n const globalPath = execSync('npm root -g', { encoding: 'utf8' }).trim();\n possiblePaths.push(\n join(globalPath, 'paytaca-cli'),\n join(globalPath, 'opencode-plugin', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Common global locations\n possiblePaths.push(\n '/usr/lib/node_modules/paytaca-cli',\n '/usr/local/lib/node_modules/paytaca-cli',\n '/opt/homebrew/lib/node_modules/paytaca-cli',\n );\n \n // Try current file's node_modules (for bundled installs)\n try {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n possiblePaths.push(\n join(currentDir, '..', 'node_modules', 'paytaca-cli'),\n join(currentDir, '..', '..', 'node_modules', 'paytaca-cli'),\n );\n } catch {}\n \n // Find first valid path\n for (const basePath of possiblePaths) {\n try {\n const walletPath = join(basePath, 'dist', 'wallet', 'index.js');\n readFileSync(walletPath);\n return basePath;\n } catch {}\n }\n \n throw new Error('paytaca-cli not found. Try reinstalling opencode-plugin: npm install @paytaca/opencode-plugin');\n}\n\n// Load paytaca-cli modules\nlet loadMnemonic, loadWallet, LibauthHDWallet, X402Payer, parsePaymentRequiredJson, selectBchPaymentRequirements, BCH_DERIVATION_PATH;\n\ntry {\n const basePath = findPaytacaCliPath();\n \n ({ loadMnemonic, loadWallet } = await import(join(basePath, 'dist', 'wallet', 'index.js')));\n ({ LibauthHDWallet } = await import(join(basePath, 'dist', 'wallet', 'keys.js')));\n ({ X402Payer } = await import(join(basePath, 'dist', 'wallet', 'x402.js')));\n ({ parsePaymentRequiredJson, selectBchPaymentRequirements } = await import(join(basePath, 'dist', 'utils', 'x402.js')));\n ({ BCH_DERIVATION_PATH } = await import(join(basePath, 'dist', 'utils', 'network.js')));\n} catch (err) {\n console.log(JSON.stringify({ success: false, error: 'Failed to load paytaca-cli: ' + err.message }));\n process.exit(1);\n}\n\nasync function main() {\n const configPath = process.argv[2];\n if (!configPath) {\n console.log(JSON.stringify({ success: false, error: 'Usage: node paytaca-pay-wrapper.mjs <config.json>' }));\n process.exit(1);\n }\n\n const config = JSON.parse(readFileSync(configPath, 'utf8'));\n const { url, method, headers, bodyFile, chipnet, confirmed } = config;\n\n const body = readFileSync(bodyFile, 'utf8');\n\n const data = loadMnemonic();\n if (!data) {\n console.log(JSON.stringify({ success: false, error: 'No wallet found. Run paytaca wallet create first.' }));\n process.exit(1);\n }\n\n const wallet = loadWallet();\n const isChipnet = Boolean(chipnet);\n const bchWallet = wallet.forNetwork(isChipnet);\n const hdWallet = new LibauthHDWallet(data.mnemonic, BCH_DERIVATION_PATH, isChipnet ? 'chipnet' : 'mainnet');\n const x402Payer = new X402Payer({ hdWallet, addressIndex: 0 });\n\n try {\n const result = await executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed);\n console.log(JSON.stringify(result, null, 2));\n } catch (err) {\n console.log(JSON.stringify({ success: false, error: err.message || String(err) }, null, 2));\n process.exit(1);\n }\n}\n\nasync function executePay(url, method, headers, body, bchWallet, x402Payer, isChipnet, confirmed) {\n const response = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n\n const responseHeaders = {};\n response.headers.forEach((value, key) => { responseHeaders[key] = value; });\n const responseText = await response.text();\n let responseData;\n try { responseData = JSON.parse(responseText); } catch { responseData = responseText; }\n\n if (response.status === 402) {\n const paymentRequired = parsePaymentRequiredJson(responseData);\n if (!paymentRequired) {\n return { success: false, status: 402, error: 'Could not parse PaymentRequired from 402 response body' };\n }\n const requirements = selectBchPaymentRequirements(paymentRequired, isChipnet ? 'chipnet' : 'mainnet');\n if (!requirements) {\n return {\n success: false, status: 402, error: 'Server does not accept BCH payment',\n data: { acceptedSchemes: paymentRequired.accepts.map(a => ({ scheme: a.scheme, network: a.network })) },\n };\n }\n\n const payerAddress = x402Payer.getPayerAddress();\n const address = requirements.payTo;\n const amountBch = Number(requirements.amount) / 1e8;\n const changeAddressSet = bchWallet.getAddressSetAt(0);\n const changeAddress = changeAddressSet.change;\n\n if (!confirmed) {\n return {\n success: false, status: 402, error: 'Payment not confirmed.',\n payment: { required: true, amount: requirements.amount, payTo: address },\n };\n }\n\n const sendResult = await bchWallet.sendBch(amountBch, address, changeAddress);\n if (!sendResult.success) {\n return { success: false, status: 402, payment: { required: true, error: sendResult.error }, error: sendResult.error };\n }\n\n const txid = sendResult.txid;\n const paymentPayload = await x402Payer.createPaymentPayload(requirements, paymentRequired.resource.url, txid, 0, requirements.amount);\n headers['PAYMENT-SIGNATURE'] = JSON.stringify(paymentPayload);\n\n let retryResponse;\n try {\n retryResponse = await fetch(url, {\n method,\n headers,\n body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,\n signal: AbortSignal.timeout(PAY_TIMEOUT_MS),\n });\n } catch (e) {\n if (e.name === 'AbortError') {\n return { success: false, timeout: true, error: 'Response timed out from server.' };\n }\n throw e;\n }\n const retryResponseHeaders = {};\n retryResponse.headers.forEach((value, key) => { retryResponseHeaders[key] = value; });\n const retryResponseText = await retryResponse.text();\n let retryResponseData;\n try { retryResponseData = JSON.parse(retryResponseText); } catch { retryResponseData = retryResponseText; }\n\n return {\n success: retryResponse.ok,\n status: retryResponse.status,\n statusText: retryResponse.statusText,\n headers: retryResponseHeaders,\n data: retryResponseData,\n payment: { required: true, txid, recipientAddress: address },\n };\n }\n\n return {\n success: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n data: responseData,\n payment: { required: false },\n };\n}\n\nmain();\n";
|
|
2
2
|
//# sourceMappingURL=wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,ozOAqMlC,CAAC"}
|
package/dist/bundled/wrapper.js
CHANGED
|
@@ -15,6 +15,11 @@ import { execSync } from 'child_process';
|
|
|
15
15
|
import { fileURLToPath } from 'url';
|
|
16
16
|
import { dirname, join } from 'path';
|
|
17
17
|
|
|
18
|
+
// How long to wait for the server to respond before treating the payment as timed out.
|
|
19
|
+
// Default 240s so heavy non-streaming generations (large context / long output) can
|
|
20
|
+
// complete; override with PAYTACA_PAY_TIMEOUT_MS.
|
|
21
|
+
const PAY_TIMEOUT_MS = Number(process.env.PAYTACA_PAY_TIMEOUT_MS || 240000);
|
|
22
|
+
|
|
18
23
|
// Find paytaca-cli installation
|
|
19
24
|
function findPaytacaCliPath() {
|
|
20
25
|
const possiblePaths = [];
|
|
@@ -111,7 +116,7 @@ async function executePay(url, method, headers, body, bchWallet, x402Payer, isCh
|
|
|
111
116
|
method,
|
|
112
117
|
headers,
|
|
113
118
|
body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,
|
|
114
|
-
signal: AbortSignal.timeout(
|
|
119
|
+
signal: AbortSignal.timeout(PAY_TIMEOUT_MS),
|
|
115
120
|
});
|
|
116
121
|
|
|
117
122
|
const responseHeaders = {};
|
|
@@ -161,7 +166,7 @@ async function executePay(url, method, headers, body, bchWallet, x402Payer, isCh
|
|
|
161
166
|
method,
|
|
162
167
|
headers,
|
|
163
168
|
body: ['POST', 'PUT', 'PATCH'].includes(method) ? body : undefined,
|
|
164
|
-
signal: AbortSignal.timeout(
|
|
169
|
+
signal: AbortSignal.timeout(PAY_TIMEOUT_MS),
|
|
165
170
|
});
|
|
166
171
|
} catch (e) {
|
|
167
172
|
if (e.name === 'AbortError') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,4EAA4E;AAC5E,mFAAmF;;;AAEtE,QAAA,sBAAsB,GAAG
|
|
1
|
+
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/bundled/wrapper.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,4EAA4E;AAC5E,mFAAmF;;;AAEtE,QAAA,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMrC,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -10,7 +10,4 @@ export declare function getPidFile(configDir: string): string;
|
|
|
10
10
|
export declare function getProxyScript(configDir: string): string;
|
|
11
11
|
export declare function getLogFile(configDir: string): string;
|
|
12
12
|
export declare function getWrapperScript(configDir: string): string;
|
|
13
|
-
export declare function getHeartbeatFile(configDir: string): string;
|
|
14
|
-
export declare function updateHeartbeat(configDir: string): void;
|
|
15
|
-
export declare function startHeartbeat(configDir: string): NodeJS.Timeout;
|
|
16
13
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkCpD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D"}
|
package/dist/config.js
CHANGED
|
@@ -43,9 +43,6 @@ exports.getPidFile = getPidFile;
|
|
|
43
43
|
exports.getProxyScript = getProxyScript;
|
|
44
44
|
exports.getLogFile = getLogFile;
|
|
45
45
|
exports.getWrapperScript = getWrapperScript;
|
|
46
|
-
exports.getHeartbeatFile = getHeartbeatFile;
|
|
47
|
-
exports.updateHeartbeat = updateHeartbeat;
|
|
48
|
-
exports.startHeartbeat = startHeartbeat;
|
|
49
46
|
const fs = __importStar(require("fs"));
|
|
50
47
|
const path = __importStar(require("path"));
|
|
51
48
|
// Default production backend
|
|
@@ -84,6 +81,7 @@ function loadConfig(configDir) {
|
|
|
84
81
|
proxyPort: parsed.proxyPort || exports.DEFAULT_PROXY_PORT,
|
|
85
82
|
walletHash: parsed.walletHash,
|
|
86
83
|
proxyPid: parsed.proxyPid,
|
|
84
|
+
proxyScriptHash: parsed.proxyScriptHash,
|
|
87
85
|
};
|
|
88
86
|
}
|
|
89
87
|
catch (err) {
|
|
@@ -113,27 +111,4 @@ function getLogFile(configDir) {
|
|
|
113
111
|
function getWrapperScript(configDir) {
|
|
114
112
|
return path.join(configDir, 'paytaca-pay-wrapper.mjs');
|
|
115
113
|
}
|
|
116
|
-
function getHeartbeatFile(configDir) {
|
|
117
|
-
return path.join(configDir, 'heartbeat');
|
|
118
|
-
}
|
|
119
|
-
// Touch the heartbeat file to signal the proxy we're still alive
|
|
120
|
-
function updateHeartbeat(configDir) {
|
|
121
|
-
const heartbeatFile = getHeartbeatFile(configDir);
|
|
122
|
-
try {
|
|
123
|
-
// Write current timestamp
|
|
124
|
-
fs.writeFileSync(heartbeatFile, Date.now().toString());
|
|
125
|
-
}
|
|
126
|
-
catch (err) {
|
|
127
|
-
// Ignore errors
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
// Start heartbeat interval that updates every 5 seconds
|
|
131
|
-
function startHeartbeat(configDir) {
|
|
132
|
-
// Update immediately
|
|
133
|
-
updateHeartbeat(configDir);
|
|
134
|
-
// Then every 5 seconds
|
|
135
|
-
return setInterval(() => {
|
|
136
|
-
updateHeartbeat(configDir);
|
|
137
|
-
}, 5000);
|
|
138
|
-
}
|
|
139
114
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,oCAGC;AAED,0CAIC;AAED,sCAEC;AAED,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ export declare function getProxyStatus(configDir: string): Promise<{
|
|
|
8
8
|
pid?: number;
|
|
9
9
|
}>;
|
|
10
10
|
export declare function startProxy(configDir: string, config: Config): Promise<ProxyInfo>;
|
|
11
|
-
export declare function stopProxy(configDir: string): Promise<void>;
|
|
12
11
|
export declare function getProxyConfig(configDir: string): Promise<{
|
|
13
12
|
backendUrl: string;
|
|
14
13
|
port: number;
|