mtok-bridge 0.3.2 → 0.3.3
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/package.json +1 -1
- package/src/bridge.mjs +2 -1
- package/src/serve-core.mjs +24 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mtok-bridge",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Serve any model as an OpenAI-compatible API with a key. No payment, no market, runs anywhere node runs. The transport core behind mtok.market's seller relay.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/bridge.mjs
CHANGED
|
@@ -55,7 +55,7 @@ export async function serveChat({ body, authHeader, apiKey, models, upstream })
|
|
|
55
55
|
// `baseUrl` is the API root (e.g. https://api.openai.com/v1 or a local model server); `key` is
|
|
56
56
|
// its bearer token (optional for a keyless local server). This is what makes the bridge portable:
|
|
57
57
|
// point it at a provider, or at ollama / LM Studio / vLLM on localhost.
|
|
58
|
-
export function httpUpstream({ baseUrl, key }) {
|
|
58
|
+
export function httpUpstream({ baseUrl, key, timeoutMs }) {
|
|
59
59
|
const url = String(baseUrl || '').replace(/\/$/, '') + '/chat/completions';
|
|
60
60
|
return async (payload) => {
|
|
61
61
|
const res = await fetch(url, {
|
|
@@ -65,6 +65,7 @@ export function httpUpstream({ baseUrl, key }) {
|
|
|
65
65
|
...(key ? { authorization: `Bearer ${key}` } : {}),
|
|
66
66
|
},
|
|
67
67
|
body: JSON.stringify(payload),
|
|
68
|
+
...(timeoutMs == null ? {} : { signal: AbortSignal.timeout(timeoutMs) }),
|
|
68
69
|
});
|
|
69
70
|
const text = await res.text();
|
|
70
71
|
let json;
|
package/src/serve-core.mjs
CHANGED
|
@@ -282,6 +282,24 @@ export function createServeCore({
|
|
|
282
282
|
return { status: 402, body: { error: 'contract_mode_required', detail: 'this relay only serves contract-mode draws; the platform is not reporting a dripContractAddress' } };
|
|
283
283
|
}
|
|
284
284
|
if (!drawPaidTxHash) return { status: 402, body: { error: 'draw_payment_required', detail: 'contract mode requires drawPaidTxHash before upstream delivery' } };
|
|
285
|
+
let storedKey = cacheKey;
|
|
286
|
+
// The redemption interface may be sync (fs store) or async (a Workers KV
|
|
287
|
+
// store): await normalizes both, and identity-awaits cost nothing under the
|
|
288
|
+
// host's per-booking lock.
|
|
289
|
+
let redemptionState = await redemption.state(storedKey);
|
|
290
|
+
// Preserve an upgrade's pre-scheme redemption log; missing this alias
|
|
291
|
+
// would let a legacy paid draw run upstream again after relay upgrade.
|
|
292
|
+
if (!redemptionState && oldLegacyKey) {
|
|
293
|
+
const oldLegacyState = await redemption.state(oldLegacyKey);
|
|
294
|
+
if (oldLegacyState) {
|
|
295
|
+
storedKey = oldLegacyKey;
|
|
296
|
+
redemptionState = oldLegacyState;
|
|
297
|
+
} else {
|
|
298
|
+
// Checking the legacy marker may have refreshed a prefixed record
|
|
299
|
+
// appended by another upgraded process.
|
|
300
|
+
redemptionState = await redemption.state(cacheKey);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
285
303
|
let paid;
|
|
286
304
|
try {
|
|
287
305
|
paid = await verifier.verifyDrawPaid(drawPaidTxHash, {
|
|
@@ -295,16 +313,15 @@ export function createServeCore({
|
|
|
295
313
|
requestHash,
|
|
296
314
|
sellerWallet,
|
|
297
315
|
feeRecipient: currentFeeRecipient,
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
// skip-on-unreadable-block residual is named in redemption.mjs). An
|
|
302
|
-
// honest retry is seconds-to-minutes old, never days.
|
|
303
|
-
maxPaidAgeMs: redemption.retentionMs,
|
|
316
|
+
// A known completion spends no new inference. New claims need a verified
|
|
317
|
+
// age because both payload and claim markers expire after retention.
|
|
318
|
+
maxPaidAgeMs: redemptionState === 'complete' ? undefined : redemption.retentionMs,
|
|
304
319
|
});
|
|
305
320
|
} catch (e) {
|
|
321
|
+
if (e.name === 'TimeoutError') return { status: 503, body: { error: 'relay_timeout', _bookingId: bookingId } };
|
|
306
322
|
return { status: 402, body: { error: 'payment_unverified', detail: e.message } };
|
|
307
323
|
}
|
|
324
|
+
if (paid?.reason === 'payment_age_unavailable') return { status: 503, body: { error: 'payment_age_unavailable', detail: 'payment age could not be verified; retry this same paid draw', _bookingId: bookingId } };
|
|
308
325
|
if (!paid?.ok) return { status: 402, body: { error: 'payment_unverified', detail: paid?.reason || 'unknown' } };
|
|
309
326
|
const expectedFee = configuredFeeAtomic({
|
|
310
327
|
sellerUsdAtomic: paid.event.sellerUsdAtomic,
|
|
@@ -328,24 +345,6 @@ export function createServeCore({
|
|
|
328
345
|
return { status: 403, body: { error: 'payer_denied', detail: 'payer screening failed: ' + e.message } };
|
|
329
346
|
}
|
|
330
347
|
}
|
|
331
|
-
let storedKey = cacheKey;
|
|
332
|
-
// The redemption interface may be sync (fs store) or async (a Workers KV
|
|
333
|
-
// store): await normalizes both, and identity-awaits cost nothing under the
|
|
334
|
-
// host's per-booking lock.
|
|
335
|
-
let redemptionState = await redemption.state(storedKey);
|
|
336
|
-
// Preserve an upgrade's pre-scheme redemption log; missing this alias
|
|
337
|
-
// would let a legacy paid draw run upstream again after relay upgrade.
|
|
338
|
-
if (!redemptionState && oldLegacyKey) {
|
|
339
|
-
const oldLegacyState = await redemption.state(oldLegacyKey);
|
|
340
|
-
if (oldLegacyState) {
|
|
341
|
-
storedKey = oldLegacyKey;
|
|
342
|
-
redemptionState = oldLegacyState;
|
|
343
|
-
} else {
|
|
344
|
-
// Checking the legacy marker may have refreshed a prefixed record
|
|
345
|
-
// appended by another upgraded process.
|
|
346
|
-
redemptionState = await redemption.state(cacheKey);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
348
|
if (redemptionState === 'complete') return { status: 200, body: await redemption.get(storedKey) };
|
|
350
349
|
if (redemptionState === 'pending') {
|
|
351
350
|
return { status: 409, body: { error: 'draw_pending', detail: 'this paid draw was already claimed; refusing to run upstream again', _bookingId: bookingId } };
|
|
@@ -388,6 +387,7 @@ export function createServeCore({
|
|
|
388
387
|
try {
|
|
389
388
|
completion = await upstream(safeRequest);
|
|
390
389
|
} catch (e) {
|
|
390
|
+
if (e.name === 'TimeoutError') return { status: 503, body: { error: 'relay_timeout', _bookingId: bookingId } };
|
|
391
391
|
return { status: 502, body: { error: 'upstream_error', detail: e.message } };
|
|
392
392
|
}
|
|
393
393
|
|