Changelog
Did you upgrade and something broke? Here's how to fix it!
We try not to needlessly add breaking changes, but sometimes it can happen! To find out how to migrate between versions, follow this guide.
“Love doesn't just sit there, like a stone, it has to be made, like bread; remade all the time, made new.” - Ursula Le Guin, the Lathe of Heaven
8.0 -> 9.0
BREAKING CHANGE: @learncard/core package split
Breaking Changes
initLearnCardis no longer exported by@learncard/core, as it is now the responsibility of@learncard/init
// Old
import { initLearnCard } from '@learncard/core';
// New
import { initLearnCard } from '@learncard/init';The didkit wasm binary is no longer exported by
@learncard/core, as it is now the responsibility of@learncard/init
// Old
import didkit from '@learncard/core/dist/didkit/didkit_wasm_bg.wasm';
// New
import didkit from '@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm';@learncard/network-pluginand@learncard/did-web-pluginno longer export their own version ofinitLearnCard, and are instead now proper instantiation targets from@learncard/init
// Old
import { initNetworkLearnCard } from '@learncard/network-plugin';
import { initDidWebLearnCard } from '@learncard/did-web-plugin';
const networkLearnCard = await initNetworkLearnCard({ seed: 'a'.repeat(64) });
const didWebLearnCard = await initDidWebLearnCard({ seed: 'a'.repeat(64), didWeb: 'did:web:test' });
// New
import { initLearnCard } from '@learncard/init';
const networkLearnCard = await initLearnCard({ seed: 'a'.repeat(64), network: true });
const didWebLearnCard = await initLearnCard({ seed: 'a'.repeat(64), didWeb: 'did:web:test' });Migration Steps
For the most part, you can just rename @learncard/core to @learncard/init, and everything should just work, with the exceptions listed above! In the rare case that doesn't immediately work, you may need to import something directly from the plugin itself, such as the case with the didkit wasm binary.
Notes
With this change, @learncard/core becomes version 9.0, however it also becomes much less public facing compared to the newly released @learncard/init (version 1.0). This documentation will continue to use the @learncard/core versioning.
7.0 -> 8.0
BREAKING CHANGE: Control Planes Overhaul
Breaking Changes
Universal Wallets are now returned directly by
initLearnCard, rather than a wrapped object.This means you can now call
addPlugindirectly on the return value ofinitLearnCard:
const learnCard = await initLearnCard();
const bespokeLearnCard = await learnCard.addPlugin(plugin);Universal Wallets now implement Control Planes as well as just methods - These are top-level objects with standardized functions that allow plugins/consumers access to a unified interface for common operations. When it makes sense, a specific plugin implementing a plane can also be chosen, such as choosing where to store a credential when uploading. - There are currently five planes, with more planned for the future:
Read, which implements
getgetsimply resolves a URI to a VC
Store, which implements
uploadand (optionally)uploadManyuploadstores a VC and returns a URI that can be resolveduploadManystores an array of VCs, returning an array of URIs that can be resolved
Index, which implements
get,add,update, andremovegetreturns a list of the holder's credential objects (currently namedIDXCredentials)These objects contain (at a minimum) an
idand aurithat can be resolved to a VC
addadds a credential to the holder's listupdateupdates an object in the holder's listremoveremoves an object from the holder's list
Cache, which implements
getIndex,setIndex,flushIndex,getVc,setVc, andflushVcgetIndexreturns the hodler's credential list as it exists in the cachesetIndexsets the holder's credential list in the cacheflushIndexemptys the holder's credential list cachegetVcreturns a VC for a URI if it exists in the cachesetVcsets a VC for a URI in the cacheflushVcemptys all VCs from the cache
ID, which implements
didandkeypairdidis identical to the previouswallet.didmethod, returning a did for a given methodkeypairis identical to the previouswallet.keypairmethod, returning a JWK for a given cryptographic algorithm
Plugins implement planes via the second generic parameter to the
PlugintypeFor example, a plugin implementing the Read and Store planes would be typed like this:
Plugin<'Test', 'read' | 'store'>
Plugins may continue to expose methods the same way they have, instead using the third generic parameter instead of the second:
For example, a plugin implementing the
getSubjectDidmethod would be typed like this:Plugin<'Test', any, { getSubjectDid: (did?: string) => string }>
Plugins may depend on wallets that implement planes/methods in the same way
For example, a wallet implementing the id plane and the
getSubjectDidmethod may be typed like this:Wallet<any, 'id', { getSubjectDid: (did?: string) => string }>
The
pluginMethodskey has been renamed tomethodswhen creating a plugin, andinvokewhen calling them from a walletThe old
LearnCardtype has been removedThe
Wallettype has been renamed toLearnCardgenerateWallethas been renamed togenerateLearnCardThis function should now be considered private. If you'd like to construct a fully custom LearnCard, please use
initLearnCard({ custom: true })instead
The
didmethod now has had its type loosened to juststringThe
verifyCredentialmethod now returns aVerificationCheckdirectly, unless you explicitly ask for the prettified version via a flagI.e.
wallet.verifyCredential(vc)is nowc(vc, {}, true)
The
namefield is now required for plugins, and they may optionally specify adisplayNameanddescriptionwalletFromKeyhas been renamed tolearnCardFromSeedwalletFromApiUrlhas been renamed tolearnCardFromApiUrlemptyWallethas been renamed toemptyLearnCard
Migration Steps
Migration StepsFor the most part, you can simply rename calls and everything will just work
wallet.didis nowwallet.id.didwallet.keypairis nowwallet.id.keypairwallet.newCredentialis nowwallet.invoke.newCredentialwallet.newPresentationis nowwallet.invoke.newPresentationwallet.verifyCredentialis nowwallet.invoke.verifyCredentialAs per above, if you'd like to retain the same output format, you will need to pass true as the third argument
I.e.
wallet.verifyCredential(vc)is nowwallet.invoke.verifyCredential(vc, {}, true)
wallet.issueCredentialis nowwallet.invoke.issueCredentialwallet.issuePresentationis nowwallet.invoke.issuePresentationwallet.verifyPresentationis nowwallet.invoke.verifyPresentationwallet.getCredentialis a bit more complex, as it was actually wrapping two operations:Getting a credential with a given id
Resolving that credential
This can now be replaced with the following code:
// Old
const vc = await lc.getCredential('test');
// New
const record = (await lc.index.all.get()).find(record => record.id === 'test');
const vc = await lc.read.get(record.uri);If this proves to be too cumbersome, we may add back in the getCredential method as helper in invoke
wallet.getCredentialshas the same issue aswallet.getCredential, it can be replaced with the following code:
const vcs = await lc.getCredentials();
// New
const uris = (await lc.index.all.get()).map(record => record.uri);
const vcs = await Promise.all(uris.map(async uri => lc.read.get(uri)));wallet.getCredentialsListis nowwallet.index.all.getwallet.publishCredentialis nowwallet.store.Ceramic.uploadwallet.addCredentialis nowwallet.index.IDX.addwallet.removeCredentialis nowwallet.index.IDX.removewallet.resolveDidis nowwallet.invoke.resolveDidwallet.readFromCeramicis nowwallet.invoke.readContentFromCeramicwallet.resolveCredentialis nowwallet.read.getwallet.getTestVcis nowwallet.invoke.getTestVcwallet.getTestVpis nowwallet.invoke.getTestVpwallet.getEthereumAddressis nowwallet.invoke.getEthereumAddresswallet.getBalanceis nowwallet.invoke.getBalancewallet.getBalanceForAddressis nowwallet.invoke.getBalanceForAddresswallet.transferTokensis nowwallet.invoke.transferTokenswallet.getCurrentNetworkis nowwallet.invoke.getCurrentNetworkwallet.changeNetworkis nowwallet.invoke.changeNetworkwallet.addInfuraProjectIdis nowwallet.invoke.addInfuraProjectIdwallet.vpFromQrCodeis nowwallet.invoke.vpFromQrCodewallet.vpToQrCodeis nowwallet.invoke.vpToQrCodewallet.installChapiHandleris nowwallet.invoke.installChapiHandlerwallet.activateChapiHandleris nowwallet.invoke.activateChapiHandlerwallet.receiveChapiEventis nowwallet.invoke.receiveChapiEventwallet.storePresentationViaChapiis nowwallet.invoke.storePresentationViaChapiwallet.storeCredentialViaChapiDidAuthis nowwallet.invoke.storeCredentialViaChapiDidAuth
Because the LearnCard and Wallet types have changed, if you were using either, you will need to update your code:
let test: LearnCard | undefined = undefined; // Old
let test: LearnCardFromSeed['returnValue'] | undefined = undefined; // New
let test: LearnCard<any> | undefined = undefined; // Also valid if you don't know which instantiation function will be used
let test: Wallet<any, { getSubjectDid: (did?: string) => string }>; // Old
let test: LearnCard<any, any, { getSubjectDid: (did?: string) => string }>; // NewNotes
We are moving away from the term "wallet", preferring instead to use the term LearnCard in its place. You may notice that in updated documentation and examples, variables named wallet have been replaced with the name learnCard.
Last updated
Was this helpful?