Commit Graph
125 Commits
Author SHA1 Message Date
9qeklajcandGitHub 3c1b6d5f17 Merge pull request #578 from Routstr/token-error-code
fix: specific, sanitized errors for failed Cashu token redemption
2026-07-07 15:59:49 +02:00
9qeklajc 46bbba7027 resolve reivews 2026-07-07 14:29:39 +02:00
9qeklajc e2aa02307b explicit code for error report & update doc 2026-07-05 23:05:53 +02:00
9qeklajc 12c4c1f030 make cache prices configurable 2026-07-04 21:49:05 +02:00
Jeroen UbbinkandClaude Opus 4.8 434283c58d refactor(upstream): resolve a provider's own row by primary key
A live upstream provider re-finds its own database row in two places —
PPQ.AI's insufficient-balance self-disable and the base
refresh_models_cache — with WHERE base_url == self.base_url AND
api_key == self.api_key. That uses a rotatable secret as a self-handle:
if the row's key rotates under a live object, it can no longer find
itself.

Carry the row's primary key on the instance as db_id, stamped centrally
by from_db_row via a _build_from_row construction hook that subclasses
override, and look the row up with session.get(UpstreamProviderRow,
db_id). This also closes a latent gap where providers built outside the
init path (auto-topup) never received db_id.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 12:53:31 +02:00
9qeklajcandGitHub 38d7075652 Merge pull request #567 from Routstr/feat-prune-dead-api-keys
feat: prune dead zero-balance API keys with background janitor
2026-06-25 14:21:20 +02:00
9qeklajc 7b56dcb902 resolve review comments 2026-06-24 22:54:07 +02:00
9qeklajcandGitHub 2131cfc7f9 Merge pull request #566 from Routstr/fix-reservation-overrun-charge
fix: always charge balance on reservation overrun even after stale sweep
2026-06-24 22:38:28 +02:00
9qeklajcandGitHub cbd97e8e3a Merge pull request #549 from jeroenubbink/fix/swap-fee-retry
fix: retry foreign mint swaps with observed fees instead of trusting fee_reserve
2026-06-23 22:42:26 +02:00
9qeklajc 1e50afbd82 feat: prune dead zero-balance API keys with background janitor 2026-06-21 15:04:16 +02:00
9qeklajc 4d6e2cdf59 fix: always charge balance on reservation overrun even after stale sweep 2026-06-21 15:03:50 +02:00
9qeklajc 861fda21b7 resolve review comments 2026-06-12 20:20:38 +02:00
Jeroen UbbinkandClaude Fable 5 7870db9af1 fix: retry foreign mint swaps with observed fees instead of trusting fee_reserve
A foreign mint's melt fee_reserve is a non-binding estimate (NUT-05): the
mint may demand more on the real quote or reject the melt outright (e.g.
mint.cubabitcoin.org charging input fees beyond its quote). Instead of
padding the estimate with a safety buffer that strands funds at the
foreign mint on every swap, retry the mint-quote/melt-quote/melt cycle
(max 3 attempts) with the amount recomputed from the fees the mint
actually demands.

Melt failures are classified by the NUT-00 error code (11005 registered
TransactionUnbalanced as sent by cdk, 11000 nutshell's generic
TransactionError): fee-related rejections retry, others (e.g. 20004
Lightning payment failed) surface immediately. Nutshell's Provided/needed
amounts refine the retry step when present; otherwise shrink by 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:08:38 +02:00
Jeroen UbbinkandClaude Sonnet 4.6 28c4008892 fix: enforce balance_limit atomically on child key requests
The Python pre-check on balance_limit provided no concurrency guarantee —
two concurrent requests could both pass the check on stale in-memory state
and both proceed to reserve, exceeding the limit.

Add the balance_limit guard to the child key UPDATE's WHERE clause so the
enforcement is atomic. The HTTP 402 is raised without an explicit rollback:
since session.commit() was never called, the uncommitted billing key update
is discarded when the session context manager closes on exception exit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 11:37:39 +02:00
9qeklajcandGitHub a16bc1220c Merge pull request #546 from Routstr/fix-parent-key-leak-to-child-key
do not leak parent key to child key
2026-06-07 15:27:32 +02:00
9qeklajc 68a7cd1dfb do not leak parent key to child key 2026-06-07 15:25:13 +02:00
9qeklajc d96dc20e86 secure endpoint 2026-06-07 15:18:49 +02:00
9qeklajc 9e9c2bde57 fix: buffer-based SSE parser for all supported providers
Replace the fragile `re.split(b"data: ")` streaming parser with a
buffered, event-delimited parser in both the chat-completion and
Responses-API streamers. Events are accumulated until the SSE blank-line
delimiter, so parsing is independent of network chunk boundaries.

Fixes:
- OpenRouter `: OPENROUTER PROCESSING` keepalive comments no longer leak
  to clients as `data: : ...` (the `Unexpected token ':'` client crash).
- JSON payloads split across TCP reads are reassembled before parsing.
- CRLF framing (Gemini native alt=sse) handled.
- Combined content+usage chunks (Gemini thinking models over the
  OpenAI-compat endpoint) forward content once and still report usage in
  the cost trailer, instead of dropping the assistant message.
- Multi-line non-JSON `data` blocks are re-prefixed per line so they stay
  valid SSE framing for the client.

Adds tests/unit/test_streaming_sse_providers.py driving the real
generator against per-provider on-the-wire framing, and switches the
integration token-mint fallback to secrets.token_hex to kill a
PRNG/clock collision flake.
2026-06-07 12:58:54 +02:00
9qeklajcandGitHub 8f89171db1 Merge pull request #541 from jeroenubbink/fix/lightning-invoice-key-constraints
fix: persist and propagate key constraints from Lightning invoices
2026-06-07 10:51:29 +02:00
Jeroen UbbinkandClaude Sonnet 4.6 feb76bc89d fix: persist and propagate key constraints from Lightning invoices
LightningInvoice had no columns for balance_limit, balance_limit_reset,
or validity_date. SQLModel silently dropped these constructor kwargs, so
create_api_key_from_invoice always produced an unconstrained key.

Add the three columns to LightningInvoice with a migration, and wire them
through to the ApiKey in create_api_key_from_invoice, matching the pattern
already used in the child key creation path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 14:58:40 +02:00
Jeroen UbbinkandClaude Sonnet 4.6 3b7f96560b fix: make child key balance deduction atomic
The previous in-memory deduction (key.balance -= cost) was a read-modify-
write on stale state, allowing two concurrent create_child_key() calls to
both pass the balance check and both succeed, effectively charging the
parent only once for two child keys.

Replace with an atomic UPDATE ... WHERE balance - reserved_balance >= cost
and check rowcount, matching the pattern already used in pay_for_request.
Also adds a concurrent integration test that reproduces the race and
confirms the fix holds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 12:02:12 +02:00
9qeklajcandGitHub d7bf1d6582 Merge pull request #536 from Routstr/add-created-date-to-api-key
add api key creation date
2026-06-02 00:20:57 +02:00
9qeklajc 379c319e0d fix test 2026-06-01 23:30:20 +02:00
9qeklajc aaa80d47bc add api key creation date 2026-06-01 23:27:26 +02:00
9qeklajcandGitHub 29cfeaed9a Merge pull request #523 from Routstr/rip-08-lightning-invoice
add rop-08 lightning invoice support
2026-05-21 00:28:41 +02:00
9qeklajc 632244e54f add rop-08 lightning invoice support 2026-05-20 23:24:24 +02:00
9qeklajc 3251664513 use correct var to report balance info 2026-05-20 23:00:03 +02:00
9qeklajc 3c13be20cb no key creation when refund 2026-05-13 22:34:24 +02:00
9qeklajc a2db3e2d57 fmt 2026-04-26 22:19:30 +02:00
9qeklajc 1f2ff8a99c added admin token 2026-04-25 11:18:58 +02:00
9qeklajc aa682bf8ec fix test 2026-04-22 23:43:11 +02:00
9qeklajc afd81aeca2 reduce retries 2026-04-22 23:14:45 +02:00
9qeklajc fa7d2804bb add test 2026-04-22 23:00:04 +02:00
9qeklajc 05115c3387 add api-key history and fix race condition while topup 2026-04-22 21:50:22 +02:00
9qeklajc a637acd8f4 use db fixture 2026-04-09 23:08:01 +02:00
9qeklajc 58be0c7976 clean u 2026-04-09 20:42:36 +02:00
9qeklajc 74b58e5fa3 add some tests and improve payment handling 2026-04-09 20:25:43 +02:00
9qeklajc a1018776e9 make sure no negative balance can happen 2026-04-08 00:16:55 +02:00
9qeklajc 7267bb87b9 fix tests 2026-03-13 23:04:17 +01:00
9qeklajc 173f5fbcbd make sure the models with lowest prices are forwarded 2026-03-13 22:59:09 +01:00
9qeklajcandGitHub 8b3fdaa545 Merge pull request #403 from Routstr/fix-admin-routstr-balance-timeout
Handle Routstr admin balance timeouts
2026-03-13 21:13:19 +01:00
Shroominic 9560050946 test: type routstr topup async client mock 2026-03-13 19:08:45 +08:00
Shroominic dd88e9b172 test: annotate admin balance integration session 2026-03-13 18:51:30 +08:00
Shroominic 59f8d31719 Handle Routstr admin balance timeouts 2026-03-13 18:45:18 +08:00
Shroominic 0198569a9a fix: retry transient Routstr top-up invoice failures 2026-03-13 18:17:19 +08:00
9qeklajc 66975ee271 Merge branch 'v0.4.0' into add-routstr-provider 2026-03-06 23:08:30 +01:00
9qeklajc 9fb6f54d12 fix negative reserve balance 2026-03-03 15:29:07 +01:00
9qeklajc 350714f23a default child key price to zero 2026-02-18 23:45:37 +01:00
9qeklajc 21f421b212 fmt 2026-02-15 17:09:46 +01:00
9qeklajc 1d95379328 add child keys details to view 2026-02-15 17:06:01 +01:00