Document methods in resolveInvitationData

This commit is contained in:
2026-06-15 20:07:31 +10:00
parent 3ee2d53766
commit cfcba02bb3

View File

@@ -85,6 +85,8 @@ export const pickTemplateViewMetadata = (definition?: {
}) => { }) => {
if (!definition) return {}; if (!definition) return {};
// Only copy fields that are present so absent template metadata does not
// overwrite committed values when this object is spread onto a commit row.
return { return {
...(definition.name !== undefined && { name: definition.name }), ...(definition.name !== undefined && { name: definition.name }),
...(definition.description !== undefined && { ...(definition.description !== undefined && {
@@ -151,6 +153,8 @@ export const pickTemplateOutputMetadata = (definition?: XOTemplateOutput) => {
...(definition.lockingScript !== undefined && { ...(definition.lockingScript !== undefined && {
lockingScript: definition.lockingScript, lockingScript: definition.lockingScript,
}), }),
// Keep CashAssembly expressions (e.g. "$(<totalSatoshis>)") for UI compilation;
// committed bigint values on the output row take precedence when spread later.
...(definition.valueSatoshis !== undefined && { ...(definition.valueSatoshis !== undefined && {
valueSatoshis: definition.valueSatoshis, valueSatoshis: definition.valueSatoshis,
}), }),
@@ -196,6 +200,10 @@ export const resolveInput = (
/** /**
* Enriches a committed output with its template definition when an identifier is present. * Enriches a committed output with its template definition when an identifier is present.
*
* Template metadata is spread after commit fields so display expressions (e.g.
* `valueSatoshis: "$(<totalSatoshis>)"`) layer on for the UI even when the merger
* already resolved a bigint for transaction encoding.
*/ */
export const resolveOutput = ( export const resolveOutput = (
output: XOInvitationOutput, output: XOInvitationOutput,
@@ -210,6 +218,8 @@ export const resolveOutput = (
? template.outputs?.[output.outputIdentifier] ? template.outputs?.[output.outputIdentifier]
: undefined, : undefined,
), ),
// Template valueSatoshis may be a CashAssembly string while XOInvitationOutput
// expects bigint — the read model intentionally allows both for display.
}) as ResolvedInvitationOutput; }) as ResolvedInvitationOutput;
/** /**
@@ -225,6 +235,9 @@ export const hexOrBinToHex = (value?: string | Uint8Array) => {
/** /**
* Normalizes a merged input row for UI display (hex strings, no encoding placeholders). * Normalizes a merged input row for UI display (hex strings, no encoding placeholders).
*
* The engine merger returns libauth-ready binary fields and fills in encoding
* defaults (empty unlocking bytecode, sequence 0) that are not useful in the TUI.
*/ */
export const normalizeMergedInputForDisplay = (input: XOInvitationInput) => { export const normalizeMergedInputForDisplay = (input: XOInvitationInput) => {
const normalized = { ...input }; const normalized = { ...input };
@@ -236,6 +249,7 @@ export const normalizeMergedInputForDisplay = (input: XOInvitationInput) => {
} }
if (input.unlockingBytecode !== undefined) { if (input.unlockingBytecode !== undefined) {
// Engine uses an empty Uint8Array as a placeholder until the input is signed.
const isPlaceholder = const isPlaceholder =
input.unlockingBytecode instanceof Uint8Array && input.unlockingBytecode instanceof Uint8Array &&
input.unlockingBytecode.length === 0; input.unlockingBytecode.length === 0;
@@ -249,6 +263,7 @@ export const normalizeMergedInputForDisplay = (input: XOInvitationInput) => {
} }
} }
// Default sequence from the merger is not meaningful for display.
if (normalized.sequenceNumber === 0) { if (normalized.sequenceNumber === 0) {
delete normalized.sequenceNumber; delete normalized.sequenceNumber;
} }
@@ -289,6 +304,7 @@ export const findOutputIdentifierForMergedOutput = (
const commitBytecodeHex = hexOrBinToHex(commitOutput.lockingBytecode); const commitBytecodeHex = hexOrBinToHex(commitOutput.lockingBytecode);
// Match merged binary bytecode back to the committed row that carried the identifier.
if ( if (
mergedBytecodeHex !== undefined && mergedBytecodeHex !== undefined &&
commitBytecodeHex !== undefined && commitBytecodeHex !== undefined &&
@@ -298,6 +314,7 @@ export const findOutputIdentifierForMergedOutput = (
} }
} }
// Fall back when the commit has a single identified output (common case).
const outputsWithIdentifier = outputs.filter( const outputsWithIdentifier = outputs.filter(
(commitOutput) => commitOutput.outputIdentifier !== undefined, (commitOutput) => commitOutput.outputIdentifier !== undefined,
); );
@@ -330,6 +347,8 @@ export const findVariableEntityIdentifier = (
) => { ) => {
let entityIdentifier = ""; let entityIdentifier = "";
// Merged variables do not carry sourceCommitIdentifier today; walk commits and
// let the last array match win (ordering deferred to the engine merger).
for (const commit of commits) { for (const commit of commits) {
for (const commitVariable of commit.data?.variables ?? []) { for (const commitVariable of commit.data?.variables ?? []) {
if (matchesInvitationVariable(commitVariable, variable)) { if (matchesInvitationVariable(commitVariable, variable)) {
@@ -358,6 +377,8 @@ export const resolveCommitReferences = (
commits.map((commit) => [commit.commitIdentifier, commit]), commits.map((commit) => [commit.commitIdentifier, commit]),
); );
// Merge rather than flatten so mergesWith input extensions and transactionIndex
// ordering are handled by the engine (see signing flow in engine.append/sign).
const merged = mergeInvitationCommits( const merged = mergeInvitationCommits(
invitation as Parameters<typeof mergeInvitationCommits>[0], invitation as Parameters<typeof mergeInvitationCommits>[0],
template, template,
@@ -386,6 +407,7 @@ export const resolveCommitReferences = (
const entityIdentifier = const entityIdentifier =
commitsMap.get(mergedInput.sourceCommitIdentifier)?.entityIdentifier ?? commitsMap.get(mergedInput.sourceCommitIdentifier)?.entityIdentifier ??
""; "";
// Strip merger-only fields before normalization and template enrichment.
const { const {
sourceCommitIdentifier: _sourceCommitIdentifier, sourceCommitIdentifier: _sourceCommitIdentifier,
mergesWith: _mergesWith, mergesWith: _mergesWith,
@@ -411,6 +433,7 @@ export const resolveCommitReferences = (
commit, commit,
output, output,
); );
// Re-attach outputIdentifier so pickTemplateOutputMetadata can resolve names/roles.
const outputForDisplay = normalizeMergedOutputForDisplay( const outputForDisplay = normalizeMergedOutputForDisplay(
outputIdentifier !== undefined ? { ...output, outputIdentifier } : output, outputIdentifier !== undefined ? { ...output, outputIdentifier } : output,
); );