Migration guide
Step-by-step guides for migrating MarzbanSDK across its breaking releases — v3.0.0's async webhook API, and v4.0.0's WebSocket reconnect lifecycle and destroy() contract.
v3.0.0 → v4.0.0
Shipped in marzban-sdk@4.0.0, bundling three issues that all forced the same major:
#84 (a terminal destroy() lifecycle contract),
#88 (a WebSocket reconnect state machine
replacing sdk.logs's "request that either succeeds or fails" model), and
#89 (the resulting public surface — lifecycle
callbacks, replay dedup, reconnect options, header auth). See
ADR-0015,
ADR-0016,
and ADR-0017
for the full design rationale.
Breaking changes:
- A failed first
connect*()now rejects instead of resolving. Previously it always resolved with a close handle, even to a socket that never opened. connect*()resolves only once the socket is genuinelyopen, not merely constructed.onErrorreceives a, never a raw DOM event.err.urlis redacted; it never carries the access token.replay: 'dedup'is the new default, suppressing log lines the panel re-delivers after a reconnect. If you relied on seeing every replayed line, opt intoreplay: 'all'.LogsStreamOptions.maxRetriesis gone. WS reconnects use their own internal time budget instead ofconfig.retries; there's no equivalent option to set.- Any SDK operation called after
destroy()now rejects withinstead of silently succeeding or (for WS) silently reconnecting:authorize(),getAuthToken(),logs.connect*(), andwebhook.parseWebhook()/handleWebhook()/dispatch().webhook.on()/once()/off()are unaffected — unsubscribing after shutdown still works.
See the Changelog for full release notes.
1. Handle a rejected first connect
import { isWsError } from 'marzban-sdk'
// v3 — always resolved, even on a failed handshake
const stream = await sdk.logs.connectByCore({ onMessage: handler })
// v4 — a failed first connect now rejects; handle it
try {
const stream = await sdk.logs.connectByCore({ onMessage: handler })
} catch (err) {
if (isWsError(err)) console.error('Failed to connect:', err.code, err.message)
}2. Update onError handlers to expect a WsError
// v3 — a raw DOM event, potentially carrying the token in event.target.url
onError: (event) => console.error(event.message)
// v4 — a typed, redacted error
onError: (error: WsError) => console.error(error.code, error.message)3. Opt back into every replayed line, if you relied on it
// v4 default is 'dedup' — add this to restore v3's behavior
await sdk.logs.connectByCore({ onMessage: handler, replay: 'all' })4. Drop maxRetries, use the reconnect option if you need custom timing
// v3
await sdk.logs.connectByCore({ onMessage: handler, maxRetries: 5 })
// v4 — reconnects are budget-based, not attempt-based; shouldReconnect gives full control
await sdk.logs.connectByCore({
onMessage: handler,
reconnect: { shouldReconnect: ({ attempt }) => attempt <= 5 },
})5. Catch SdkDestroyedError for calls that might race a shutdown
import { isSdkDestroyedError } from 'marzban-sdk'
await sdk.destroy()
// v3 — this would silently succeed or hang
// v4 — rejects with SdkDestroyedError
try {
await sdk.authorize()
} catch (err) {
if (isSdkDestroyedError(err)) {
/* expected post-shutdown */
}
}v2 → v3.0.0
Shipped in marzban-sdk@3.0.0 by a single commit (fix!: make webhook crypto cross-runtime and keep node:crypto out of browser bundles) — the only breaking-change commit in the 3.x line. Every release from v3.0.1 through v3.3.0 is additive. v4.0.0, however, is another breaking release — see the guide above if you're upgrading past it.
Breaking changes:
- Webhook verification is now async.
parseWebhookandverifyWebhookSignaturereturnPromiseinstead of being synchronous. Update all call sites toawait. - Webhook verification is server-side only. Calling
handleWebhookorparseWebhookwith a secret configured in a browser context now throws(code:WEBHOOK_ENVIRONMENT_ERROR).
See the Changelog for full release notes across every version.
1. Await parseWebhook
// v2
const events = sdk.webhook.parseWebhook(rawBody, sig)
// v3
const events = await sdk.webhook.parseWebhook(rawBody, sig)2. Await handleWebhook
// v2
sdk.webhook.handleWebhook(rawBody, sig)
// v3
await sdk.webhook.handleWebhook(rawBody, sig)3. Await verifyWebhookSignature (if called directly)
import { verifyWebhookSignature } from 'marzban-sdk'
// v2
const ok = verifyWebhookSignature(sig, secret, bytes)
// v3
const ok = await verifyWebhookSignature(sig, secret, bytes)4. Catch WebhookEnvironmentError in browser code
If you were calling signature verification from the browser (not recommended), you'll now receive . Move webhook handling to a server route.
Changelog
MarzbanSDK and marzban-mcp release history — generated directly from each package's CHANGELOG.md, so it can't drift from what's on npm or GitHub Releases.
FAQ
Answers to common MarzbanSDK questions — Marzban version support, runtime compatibility, authentication, retries, error handling, and webhooks.