mtok-bridge 0.3.3 → 0.3.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/serve-core.mjs +15 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtok-bridge",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
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": {
@@ -243,11 +243,6 @@ export function createServeCore({
243
243
  maxOutputTokens,
244
244
  }) {
245
245
  const serve = async (body) => {
246
- // #651: feeBps/feeRecipient may be getters so a long-running relay tracks a
247
- // platform fee change instead of pinning the boot rate (a fee DECREASE with a
248
- // stale higher rate would refuse an already-paid draw as fee_amount_too_low).
249
- // Resolve once per serve and use the resolved values everywhere below.
250
- const currentFeeBps = typeof feeBps === 'function' ? feeBps() : feeBps;
251
246
  const currentFeeRecipient = typeof feeRecipient === 'function' ? feeRecipient() : feeRecipient;
252
247
  const { bookingId, n, buyerId, request, requestNonce, drawPaidTxHash } = body;
253
248
  const hasRequestNonce = Object.hasOwn(body, 'requestNonce');
@@ -313,9 +308,9 @@ export function createServeCore({
313
308
  requestHash,
314
309
  sellerWallet,
315
310
  feeRecipient: currentFeeRecipient,
316
- // A known completion spends no new inference. New claims need a verified
311
+ // A known claim spends no new inference. New claims need a verified
317
312
  // age because both payload and claim markers expire after retention.
318
- maxPaidAgeMs: redemptionState === 'complete' ? undefined : redemption.retentionMs,
313
+ maxPaidAgeMs: redemptionState === 'complete' || redemptionState === 'pending' ? undefined : redemption.retentionMs,
319
314
  });
320
315
  } catch (e) {
321
316
  if (e.name === 'TimeoutError') return { status: 503, body: { error: 'relay_timeout', _bookingId: bookingId } };
@@ -323,14 +318,6 @@ export function createServeCore({
323
318
  }
324
319
  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 } };
325
320
  if (!paid?.ok) return { status: 402, body: { error: 'payment_unverified', detail: paid?.reason || 'unknown' } };
326
- const expectedFee = configuredFeeAtomic({
327
- sellerUsdAtomic: paid.event.sellerUsdAtomic,
328
- feeAddress: currentFeeRecipient,
329
- feeBps: currentFeeBps,
330
- });
331
- if (BigInt(paid.event.feeUsdAtomic || 0) < expectedFee) {
332
- return { status: 402, body: { error: 'payment_unverified', detail: 'fee_amount_too_low' } };
333
- }
334
321
  // Screen the verified payer before spending upstream capacity. The
335
322
  // payment already settled on-chain (that money is the buyer's loss);
336
323
  // this refuses the SERVICE, which is the only refusal an edge can
@@ -349,6 +336,19 @@ export function createServeCore({
349
336
  if (redemptionState === 'pending') {
350
337
  return { status: 409, body: { error: 'draw_pending', detail: 'this paid draw was already claimed; refusing to run upstream again', _bookingId: bookingId } };
351
338
  }
339
+ // Completed/pending claims already crossed the fee gate and cannot spend
340
+ // again. New claims use the policy at the verified payment time.
341
+ let currentFeeBps;
342
+ try {
343
+ currentFeeBps = typeof feeBps === 'function' ? await feeBps(paid) : feeBps ?? 0;
344
+ if (!Number.isSafeInteger(currentFeeBps) || currentFeeBps < 0 || currentFeeBps > 10_000) throw new TypeError('invalid fee rate');
345
+ } catch {
346
+ return { status: 503, body: { error: 'fee_policy_unavailable', detail: 'fee policy could not be verified; retry this same paid draw', _bookingId: bookingId } };
347
+ }
348
+ const expectedFee = configuredFeeAtomic({ sellerUsdAtomic: paid.event.sellerUsdAtomic, feeAddress: currentFeeRecipient, feeBps: currentFeeBps });
349
+ if (BigInt(paid.event.feeUsdAtomic || 0) < expectedFee) {
350
+ return { status: 402, body: { error: 'payment_unverified', detail: 'fee_amount_too_low' } };
351
+ }
352
352
  const paidEvent = paid.event;
353
353
  const remainingUsd = Number(paid.event.sellerUsdAtomic || 0) / 1e6;
354
354
  if (remainingUsd < BALANCE_EPSILON) {