Migrating from Alpha
This guide is for teams that tested Coco during the coco-cashu-* alpha phase and now want to move to the current @cashu/* release line.
The biggest migration is the namespace change, but this release line is also a clean API cut. It is not a package-name-only upgrade: several alpha-era compatibility aliases were intentionally removed.
In most codebases, the move is:
- Replace old package names in
package.json - Rewrite imports to the new
@cashu/*names - Reinstall dependencies and regenerate your lockfile
- Update any code that still uses removed alpha-era APIs
Package rename map
| Alpha package | Current package |
|---|---|
coco-cashu-core | @cashu/coco-core |
coco-cashu-indexeddb | @cashu/coco-indexeddb |
coco-cashu-expo-sqlite | @cashu/coco-expo-sqlite |
coco-cashu-sqlite3 | @cashu/coco-sqlite |
coco-cashu-sqlite-bun | @cashu/coco-sqlite-bun |
coco-cashu-react | @cashu/coco-react |
coco-cashu-adapter-tests | @cashu/coco-adapter-tests |
Update your dependencies
Replace the old alpha package names in your app:
{
"dependencies": {
"@cashu/coco-core": "<current @cashu version>",
"@cashu/coco-indexeddb": "<current @cashu version>"
}
}Then reinstall:
npm installIf you use Bun:
bun installRewrite imports
Update import paths everywhere the old package names appear.
// before
import { initializeCoco } from 'coco-cashu-core';
import { IndexedDbRepositories } from 'coco-cashu-indexeddb';
// after
import { initializeCoco } from '@cashu/coco-core';
import { IndexedDbRepositories } from '@cashu/coco-indexeddb';React projects follow the same pattern:
// before
import { CocoCashuProvider } from 'coco-cashu-react';
// after
import { CocoCashuProvider } from '@cashu/coco-react';Node users: move from sqlite3 to better-sqlite3
The old coco-cashu-sqlite3 package has been replaced by @cashu/coco-sqlite, and the adapter now uses better-sqlite3.
npm remove coco-cashu-sqlite3 sqlite3
npm install @cashu/coco-sqlite better-sqlite3// before
import { SqliteRepositories } from 'coco-cashu-sqlite3';
import { Database } from 'sqlite3';
// after
import { SqliteRepositories } from '@cashu/coco-sqlite';
import Database from 'better-sqlite3';If you are on Bun, prefer @cashu/coco-sqlite-bun instead.
Required API updates
Much of the old wallet flow API was rewritten around a saga-based operation model. The current surface for send, receive, mint, and melt lifecycles now lives under OpsApi, exposed on the manager as manager.ops.*.
The @cashu/* release line intentionally removes several deprecated alpha compatibility surfaces. If your app still used those wrappers, you must update that code as part of the migration.
Removed manager aliases:
manager.send->manager.ops.sendmanager.receive->manager.ops.receivemanager.quotes-> usemanager.ops.mintandmanager.ops.meltmanager.recoverPendingSendOperations()->manager.ops.send.recovery.run()manager.recoverPendingReceiveOperations()->manager.ops.receive.recovery.run()manager.recoverPendingMeltOperations()->manager.ops.melt.recovery.run()
Removed WalletApi compatibility wrappers:
wallet.send()->manager.ops.send.prepare()andmanager.ops.send.execute()wallet.processPaymentRequest()->manager.paymentRequests.parse()wallet.preparePaymentRequestTransaction()->manager.paymentRequests.prepare()wallet.handle*PaymentRequest()->manager.paymentRequests.execute()
Receive compatibility note:
wallet.receive()is still available as a one-shot convenience wrapper- New receive flows should prefer
manager.ops.receive.prepare()andmanager.ops.receive.execute()so your code can inspect and manage the persisted operation directly - Event listeners that migrate to the operation API should subscribe to
receive-op:prepared,receive-op:finalized, andreceive-op:rolled-back receive:createdhas been removed; completion listeners should usereceive-op:finalized
Removed public service surface:
TransactionServiceis no longer exported from@cashu/coco-core- The plugin
ServiceMapno longer includestransactionService - Plugin and integration code that depended on
transactionServiceshould migrate to the operation services that now own those flows:sendOperationService,receiveOperationService,mintOperationService,meltOperationService, andpaymentRequestService
Breaking WalletApi balance changes:
- Alpha exposed only scalar balance totals; v1 removes them in favor of a single structured balance surface that distinguishes
spendable,reserved, andtotal - Use these entrypoints:
wallet.balances.byMint(scope?)andwallet.balances.total(scope?) - All scalar and breakdown helpers are removed, including
wallet.getBalance(),wallet.getBalances(),wallet.getTrustedBalances(),wallet.getSpendableBalance(),wallet.getSpendableBalances(),wallet.getTrustedSpendableBalances(),wallet.getBalanceBreakdown(),wallet.getBalancesBreakdown(),wallet.getTrustedBalancesBreakdown(),wallet.getBalancesByMint(), andwallet.getBalanceTotal()
Use these forms after migrating:
// preferred
await manager.ops.send.prepare({ mintUrl, amount: 100 });
await manager.ops.receive.prepare({ token });
await manager.ops.mint.prepare({ mintUrl, amount: 100, method: 'bolt11' });
await manager.ops.melt.prepare({
mintUrl,
method: 'bolt11',
methodData: { invoice },
});
const balancesByMint = await manager.wallet.balances.byMint();
const trustedBalancesByMint = await manager.wallet.balances.byMint({ trustedOnly: true });
const total = await manager.wallet.balances.total();Notes:
- Treat
manager.opsas the supported replacement for the older one-shot wallet flow helpers - Use
manager.paymentRequests.parse(),prepare(), andexecute()for payment-request handling
React hook breaking changes
The React package changed more than just import paths. The old flow hooks were removed and replaced with operation-oriented hooks:
useSend()was removed. UseuseSendOperation().useReceive()was removed. UseuseReceiveOperation().useMintOperation()anduseMeltOperation()are new first-class hooks for the quote-backed flows that previously required dropping down to the manager.
The new hooks intentionally mirror manager.ops.*, which means the React calling convention also changed:
- The old callback-style action options were removed. Methods now return promises and expose hook-managed
status,error,isLoading, andisErrorstate. - Each hook binds to one operation after
prepare(...),importQuote(...), or initial mount-time hydration fromuseXOperation(operationId). - Follow-up methods such as
execute(),refresh(),cancel(),reclaim(),finalize(), andcheckPayment()act on the currently bound operation, so you do not pass the operation id to those methods anymore. - Hook state is now split between
currentOperationfor the persisted operation record andexecuteResultfor execute-specific return data. - The optional hook argument is initial-only. If a mounted component needs to switch to a different operation later, remount the hook or component with a new React
key.
The derived balance surfaces also changed:
- Alpha balance hooks exposed flat numeric balances only
useBalances()anduseTrustedBalance()now return a structured result withbalances.byMint[mintUrl]andbalances.total- Each per-mint value is now a balance snapshot with
{ spendable, reserved, total } useBalanceContext()follows the same structuredbalancesshape- This is a real return-shape break:
const { balance } = useTrustedBalance()becomesconst { balances, refresh } = useTrustedBalance() - Code that previously read
balance[mintUrl]orbalance.totalmust now readbalances.byMint[mintUrl]?.totalandbalances.total.total
Example balance-hook migration:
// before
const { balance } = useTrustedBalance();
const mintBalance = balance[mintUrl] ?? 0;
const total = balance.total;
// after
const { balances, refresh } = useTrustedBalance();
const mintBalance = balances.byMint[mintUrl]?.total ?? 0;
const spendable = balances.byMint[mintUrl]?.spendable ?? 0;
const total = balances.total.total;Example balance-context migration:
// before
const { balance } = useBalanceContext();
const total = balance.total;
// after
const { balances } = useBalanceContext();
const total = balances.total.total;Example send migration:
// before
const { prepareSend, executePreparedSend, rollback, status, error } = useSend();
const prepared = await prepareSend(mintUrl, amount, {
onSuccess: (op) => setPrepared(op),
});
const result = await executePreparedSend(prepared.id);
await rollback(prepared.id);
// after
const { prepare, execute, cancel, currentOperation, executeResult, status, error } =
useSendOperation();
await prepare({ mintUrl, amount });
if (userCanceled) {
await cancel();
} else {
await execute();
}Example receive migration:
// before
const { receive, status, error } = useReceive();
await receive(token);
// after
const { prepare, execute, currentOperation, status, error } = useReceiveOperation();
await prepare({ token });
await execute();Existing wallet data and migrations
For the maintained adapters, keep using the same repository/database location and initialize Coco normally.
const repo = new IndexedDbRepositories({ name: 'coco' });
const manager = await initializeCoco({ repo, seedGetter });On startup:
- repository initialization runs schema setup or migrations through the adapter
initializeCoco()reconciles legacy mint quote rows into mint operations before watchers, processors, or mint recovery start
That means alpha users should generally migrate by opening the same persisted data with the new package names rather than exporting and re-importing wallet state manually.
CI, scripts, and workspace filters
If your scripts referenced the old package names, update them too.
# before
bun run --filter='coco-cashu-core' build
# after
bun run --filter='@cashu/coco-core' buildDo the same for any:
- Bun workspace filters
- test scripts
- release scripts
- docs snippets
- monorepo automation
Release history and versions
The old alpha release history was archived under the repository's history/ directory. The @cashu/* packages start a new release line, so do not assume that the latest alpha version number directly maps to the current namespaced version number.
Upgrade by package name and API surface, not by comparing the old and new version strings.
Migration checklist
- Replace all
coco-cashu-*dependencies with@cashu/* - Rewrite imports to the new namespace
- For Node, switch from
sqlite3tobetter-sqlite3 - Reinstall dependencies and regenerate the lockfile
- Replace removed alpha-era manager and
WalletApiwrappers withmanager.ops.*andmanager.paymentRequests.* - Update Bun workspace filters and CI scripts
- Start the app against your existing persisted data and verify balances, pending operations, and mint subscriptions