Major Changes
-
#1157
64d52ebThanks @codama-releases! - Release Codama v2, supporting IDLs of the v2 standard. Upgrade v1 IDLs with thecodama upgradecommand or the@codama/upgradepackage. -
#1248
7f8bedaThanks @lorisleiva! - Validate Codama v2 IDLs with new rules covering identifier collisions, contextual values, paths, interpolated intents, numeric attributes, value labels and cyclic defined types.BREAKING CHANGES
Identifier-based messages. Items refer to identifiers instead of names, e.g.
Account has no identifier.instead ofAccount has no name., and theProgram has no origin.info item is removed along withprogramNode.origin. The bump check now readsData field "…" cannot default to the bump of the "…" account as it may be a signer.Identifier collisions. Duplicated identifiers and distinct identifiers sharing a camelCase form are reported as errors, against the offending entry, among programs, each collection of a program, struct fields, enum variants, variable PDA seeds, and the accounts, remaining accounts, provided values and sub-instructions of an instruction. This replaces the former duplicated struct field, instruction account and instruction argument checks.
New error-level rules.
- Account links pointing to a missing account.
- Contextual values within instructions:
dataValueNodepaths must resolve within the instruction data,accountValueNode,accountBumpValueNodeandaccountDataValueNodeaccounts must be accounts of the instruction, andaccountDataValueNodes need an account link and a path resolving within the linked account's data. Paths may cross account links through a.datasegment (e.g.mint.data.decimals). - Injected values consumed by an instruction that are neither provided nor have a fallback.
- Field discriminator paths must resolve to a struct field of their account, event or instruction data, and must not cross an account link.
- Interpolated intents of instruction displays must have valid placeholders, and their
${data.…}and${accounts.…}placeholders are checked like the contextual values they stand for. fixedPointTypeNodescales must be positive integers, andticksPerSecondofdateTimeTypeNodes anddurationTypeNodes must be positive integers.- Value labels on struct fields must be concrete values matching the field's type, not injected or constant values.
- Defined types in a cycle without any finite value, such as
loop = struct { next: link(loop) }, are reported on every type of the cycle, carrying theCODAMA_ERROR__DEFINED_TYPE_HAS_NO_FINITE_VALUEerror their codecs would throw ascause. Types outside a program are not checked.
New info-level rule. A
textNodewithout plugins suggests using a plain string instead. -
#1261
bb09077Thanks @lorisleiva! - Carry node paths in the remaining error contexts. Contexts that still held nodes or account names now hold node paths instead, e.g. thecycleof a circular dependency lists the path of each account and data field it goes through. Production-encoded contexts encode lists of node paths as lists of node selectors.getInstructionDataFieldsnow returns thefieldPathof each field, andmapVisitorgives the visited node to its map function.BREAKING CHANGES
Nodes and account names replaced by node paths in error contexts. The following contexts changed, completing the move to node paths.
if (isCodamaError(e, CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY)) { - const { chain } = e.context; // "a -> b -> a" + const { cycle, formattedCycle, path } = e.context; // formattedCycle: "a -> b -> a" + const account = cycle[0].at(-1); // instructionAccountNode a } if (isCodamaError(e, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE)) { - const { accountName } = e.context; + const account = e.context.path.at(-1); // e.g. instructionAccountNode }Code Removed Added VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES(1200002)cycleholds the path of each account and data field instead of the nodes themselvesVISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY(1200004)dependencyuse dependencyKindanddependencyNameVISITORS__INVALID_NUMBER_WRAPPER(1200006)pathof the number to wrap (empty when the wrapper is invalid on its own)VISITORS__FAILED_TO_VALIDATE_NODE(1200008)pathof the validated nodeDYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND(2500000)pathof the programDYNAMIC_CLIENT__PDA_NOT_FOUND(2500001)pathof the programDYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE(2500005)accountNamepathof the account, remaining accounts, PDA or data field, and theindexof the remaining account at faultDYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY(2500008)chainpathof the instruction,cycle,formattedCycletoAddressOrThrowtakes a node path. The second argument oftoAddressOrThrowfrom@codama/dynamic-address-resolutionis now the path of the node the value should be the address of, rather than an account name.- toAddressOrThrow(value, 'mint'); + toAddressOrThrow(value, [root, program, instruction, mint]);
It also takes an optional
indexfor values given in a list, e.g.toAddressOrThrow(value, [root, program, instruction, signers], 1), which the error carries in its context (it is not rendered in the message).Messages changed accordingly. The messages of these errors now render their
path, e.g.Circular dependency detected: [a -> b -> a].becomesCircular dependency detected when resolving the accounts and data of instruction [programNode]token.[instructionNode]transfer. Got the following dependency cycle [a -> b -> a].. -
#1260
3ad402aThanks @lorisleiva! - Require Node.js 22.12.0 or later.BREAKING CHANGES
Node.js 20 is no longer supported. Every package now declares
"engines": { "node": ">=22.12.0" }, the first Node.js 22 release that supportsrequire(esm)by default. Node.js 20 reached its end of life in April 2026, and some dependencies (e.g.commander) already require Node.js 22.12.0. -
#1248
7f8bedaThanks @lorisleiva! - Drop thenodeattribute of validation items in favour of theirpath, and keep theCodamaErrora validation item stems from as itscause.BREAKING CHANGES
ValidationItem.noderemoved. The node an item is about is now the last node of itspath, whichValidationItem<TNode>can type. Items about identifier collisions and instruction accounts without identifiers now lead to the offending entry rather than its parent.- const node = item.node; + const node = getLastNodeFromPath(item.path);
ValidationItem.causeadded. Items matching aCodamaError, whether thrown while validating (e.g. a cyclic dependency between instruction inputs) or the error a codec would throw (e.g. a defined type without a finite value), keep it as theircause, so consumers can match its code and context rather than its message.const cycles = items.filter(item => isCodamaError( item.cause, CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, ), );
validationItemsignature changed. Thenodeparameter is removed and an optionalcauseis appended. Passing an empty path, or aNodeStackwhose path is empty, throwsCODAMA_ERROR__UNEXPECTED_NODE_KIND, since an item must be about a node.- validationItem('warn', 'Program has no version.', program, stack); + validationItem('warn', 'Program has no version.', stack); + validationItem('error', error.message, stack, error);
Minor Changes
- #1254
eb01f83Thanks @lorisleiva! - Report instructions whose identifier collides with another instruction or sub-instruction of their program, at any nesting level, whether as an exact duplicate or once converted to camelCase, since instruction links would otherwise resolve to the wrong instruction and renderers would write flattened instructions to the same file. Collisions within the same set of sibling instructions are still only reported once, by the existing identifier collision check.
Patch Changes
- Updated dependencies [
7f8beda,1f0fb88,3f76a7f,e1cce0d,64d52eb,e92df74,7f8beda,909960f,3f76a7f,bb09077,bb09077,277eae1,277eae1,3ad402a,7f8beda,7f8beda,277eae1,7f8beda,7f8beda,b869cef,7f8beda,7f8beda,08d72e7]:- @codama/visitors-core@2.0.0-rc.0
- @codama/errors@2.0.0-rc.0
- @codama/fragments@2.0.0-rc.0
- @codama/nodes@2.0.0-rc.0