From 3ee2d5376633e3bb0e2faf4d23dc38d42ab3f7bf Mon Sep 17 00:00:00 2001 From: Harvey Zuccon Date: Mon, 15 Jun 2026 20:04:51 +1000 Subject: [PATCH] Formatting and reduce explicit typing --- src/utils/resolve-invitation-data.ts | 163 +++++++------------- tests/utils/resolve-invitation-data.test.ts | 24 +-- 2 files changed, 71 insertions(+), 116 deletions(-) diff --git a/src/utils/resolve-invitation-data.ts b/src/utils/resolve-invitation-data.ts index 949fd4d..b3d0232 100644 --- a/src/utils/resolve-invitation-data.ts +++ b/src/utils/resolve-invitation-data.ts @@ -22,24 +22,6 @@ import type { XOTemplateVariable, } from "@xo-cash/types"; -/** - * View metadata copied from a template definition onto a resolved invitation item. - */ -export interface TemplateViewMetadata { - name?: string; - description?: string; - icon?: string; -} - -/** - * Role-specific view metadata from a template output definition. - */ -export interface ResolvedInvitationOutputRoleMetadata { - name?: string; - description?: string; - icon?: string; -} - /** * A variable from invitation commits enriched with its template definition. */ @@ -74,7 +56,10 @@ export type ResolvedInvitationOutput = XOInvitationOutput & { name?: string; description?: string; icon?: string; - roles?: Record; + roles?: Record< + string, + { name?: string; description?: string; icon?: string } + >; lockingScript?: string; }; @@ -91,24 +76,13 @@ export interface ResolvedInvitationData { } /** - * Template display metadata layered onto a committed output. + * Picks human-readable view fields from a template definition. */ -export interface TemplateOutputMetadata { +export const pickTemplateViewMetadata = (definition?: { name?: string; description?: string; icon?: string; - roles?: Record; - lockingScript?: string; - valueSatoshis?: bigint | string; - token?: XOTemplateOutput["token"]; -} - -/** - * Picks human-readable view fields from a template definition. - */ -export const pickTemplateViewMetadata = ( - definition: TemplateViewMetadata | undefined, -): TemplateViewMetadata => { +}) => { if (!definition) return {}; return { @@ -124,8 +98,8 @@ export const pickTemplateViewMetadata = ( * Picks variable metadata from a template variable definition. */ export const pickTemplateVariableMetadata = ( - definition: XOTemplateVariable | undefined, -): Pick => { + definition?: XOTemplateVariable, +) => { if (!definition) return {}; return { @@ -138,12 +112,7 @@ export const pickTemplateVariableMetadata = ( /** * Picks input metadata from a template input definition. */ -export const pickTemplateInputMetadata = ( - definition: XOTemplateInput | undefined, -): Pick< - ResolvedInvitationInput, - "name" | "description" | "icon" | "unlockingScript" | "omitChangeAmounts" -> => { +export const pickTemplateInputMetadata = (definition?: XOTemplateInput) => { if (!definition) return {}; return { @@ -164,9 +133,7 @@ export const pickTemplateInputMetadata = ( * defaults; display-oriented fields like name, description, and template * valueSatoshis expressions are layered on for UI rendering. */ -export const pickTemplateOutputMetadata = ( - definition: XOTemplateOutput | undefined, -): TemplateOutputMetadata => { +export const pickTemplateOutputMetadata = (definition?: XOTemplateOutput) => { if (!definition) return {}; const roles = definition.roles @@ -198,19 +165,17 @@ export const resolveVariable = ( variable: XOInvitationVariable, entityIdentifier: string, template: XOTemplate, -): ResolvedInvitationVariable => { - const definition = template.variables?.[variable.variableIdentifier]; - - return { - entityIdentifier, - variableIdentifier: variable.variableIdentifier, - ...(variable.roleIdentifier !== undefined && { - roleIdentifier: variable.roleIdentifier, - }), - value: variable.value, - ...pickTemplateVariableMetadata(definition), - }; -}; +): ResolvedInvitationVariable => ({ + entityIdentifier, + variableIdentifier: variable.variableIdentifier, + ...(variable.roleIdentifier !== undefined && { + roleIdentifier: variable.roleIdentifier, + }), + value: variable.value, + ...pickTemplateVariableMetadata( + template.variables?.[variable.variableIdentifier], + ), +}); /** * Enriches a committed input with its template definition when an identifier is present. @@ -219,17 +184,15 @@ export const resolveInput = ( input: XOInvitationInput, entityIdentifier: string, template: XOTemplate, -): ResolvedInvitationInput => { - const definition = input.inputIdentifier - ? template.inputs?.[input.inputIdentifier] - : undefined; - - return { - entityIdentifier, - ...input, - ...pickTemplateInputMetadata(definition), - }; -}; +): ResolvedInvitationInput => ({ + entityIdentifier, + ...input, + ...pickTemplateInputMetadata( + input.inputIdentifier + ? template.inputs?.[input.inputIdentifier] + : undefined, + ), +}); /** * Enriches a committed output with its template definition when an identifier is present. @@ -238,25 +201,21 @@ export const resolveOutput = ( output: XOInvitationOutput, entityIdentifier: string, template: XOTemplate, -): ResolvedInvitationOutput => { - const definition = output.outputIdentifier - ? template.outputs?.[output.outputIdentifier] - : undefined; - const templateMetadata = pickTemplateOutputMetadata(definition); - - return { +): ResolvedInvitationOutput => + ({ entityIdentifier, ...output, - ...templateMetadata, - } as ResolvedInvitationOutput; -}; + ...pickTemplateOutputMetadata( + output.outputIdentifier + ? template.outputs?.[output.outputIdentifier] + : undefined, + ), + }) as ResolvedInvitationOutput; /** * Converts hex or binary invitation bytecode fields to hex strings for display. */ -export const hexOrBinToHex = ( - value: string | Uint8Array | undefined, -): string | undefined => { +export const hexOrBinToHex = (value?: string | Uint8Array) => { if (value === undefined) { return undefined; } @@ -267,10 +226,8 @@ export const hexOrBinToHex = ( /** * Normalizes a merged input row for UI display (hex strings, no encoding placeholders). */ -export const normalizeMergedInputForDisplay = ( - input: XOInvitationInput, -): XOInvitationInput => { - const normalized: XOInvitationInput = { ...input }; +export const normalizeMergedInputForDisplay = (input: XOInvitationInput) => { + const normalized = { ...input }; if (input.outpointTransactionHash !== undefined) { normalized.outpointTransactionHash = hexOrBinToHex( @@ -302,10 +259,8 @@ export const normalizeMergedInputForDisplay = ( /** * Normalizes a merged output row for UI display (hex strings). */ -export const normalizeMergedOutputForDisplay = ( - output: XOInvitationOutput, -): XOInvitationOutput => { - const normalized: XOInvitationOutput = { ...output }; +export const normalizeMergedOutputForDisplay = (output: XOInvitationOutput) => { + const normalized = { ...output }; if (output.lockingBytecode !== undefined) { normalized.lockingBytecode = hexOrBinToHex( @@ -323,7 +278,7 @@ export const normalizeMergedOutputForDisplay = ( export const findOutputIdentifierForMergedOutput = ( commit: XOInvitationCommit | undefined, mergedOutput: XOInvitationOutput, -): string | undefined => { +) => { const outputs = commit?.data?.outputs ?? []; const mergedBytecodeHex = hexOrBinToHex(mergedOutput.lockingBytecode); @@ -348,8 +303,7 @@ export const findOutputIdentifierForMergedOutput = ( ); if (outputsWithIdentifier.length === 1) { - const soleIdentifiedOutput = outputsWithIdentifier[0]; - return soleIdentifiedOutput?.outputIdentifier; + return outputsWithIdentifier[0]?.outputIdentifier; } return undefined; @@ -361,12 +315,9 @@ export const findOutputIdentifierForMergedOutput = ( export const matchesInvitationVariable = ( left: XOInvitationVariable, right: XOInvitationVariable, -): boolean => { - return ( - left.variableIdentifier === right.variableIdentifier && - left.roleIdentifier === right.roleIdentifier - ); -}; +) => + left.variableIdentifier === right.variableIdentifier && + left.roleIdentifier === right.roleIdentifier; /** * Finds the entity that authored a merged variable by scanning invitation commits. @@ -376,7 +327,7 @@ export const matchesInvitationVariable = ( export const findVariableEntityIdentifier = ( variable: XOInvitationVariable, commits: XOInvitationCommit[], -): string => { +) => { let entityIdentifier = ""; for (const commit of commits) { @@ -397,10 +348,6 @@ export const findVariableEntityIdentifier = ( * extensions and transaction indices are resolved. Variables come from the merged * result and are enriched with template metadata. Commit ordering is delegated to * the engine merger. - * - * @param invitation - The raw invitation in standard XO format. - * @param template - The template referenced by the invitation. - * @returns Resolved invitation data ready for display. */ export const resolveCommitReferences = ( invitation: XOInvitation, @@ -436,8 +383,9 @@ export const resolveCommitReferences = ( ); const inputs = merged.inputs.map((mergedInput) => { - const commit = commitsMap.get(mergedInput.sourceCommitIdentifier); - const entityIdentifier = commit?.entityIdentifier ?? ""; + const entityIdentifier = + commitsMap.get(mergedInput.sourceCommitIdentifier)?.entityIdentifier ?? + ""; const { sourceCommitIdentifier: _sourceCommitIdentifier, mergesWith: _mergesWith, @@ -459,7 +407,10 @@ export const resolveCommitReferences = ( mergesWith: _mergesWith, ...output } = mergedOutput; - const outputIdentifier = findOutputIdentifierForMergedOutput(commit, output); + const outputIdentifier = findOutputIdentifierForMergedOutput( + commit, + output, + ); const outputForDisplay = normalizeMergedOutputForDisplay( outputIdentifier !== undefined ? { ...output, outputIdentifier } : output, ); diff --git a/tests/utils/resolve-invitation-data.test.ts b/tests/utils/resolve-invitation-data.test.ts index bffecba..030a734 100644 --- a/tests/utils/resolve-invitation-data.test.ts +++ b/tests/utils/resolve-invitation-data.test.ts @@ -24,7 +24,8 @@ const originalInvitation: XOInvitation = { previousCommitIdentifier: undefined, entityIdentifier: MERCHANT_ENTITY, data: {}, - signature: "5f487c045657f3939ecfeaaacf239a7cfd44b485c2be591f5280bf0cc3a6e5fe304e8ea23311d82b2afa4f0ad7e0a6d07ec1e0b1aaee9c44097613694390966b", + signature: + "5f487c045657f3939ecfeaaacf239a7cfd44b485c2be591f5280bf0cc3a6e5fe304e8ea23311d82b2afa4f0ad7e0a6d07ec1e0b1aaee9c44097613694390966b", expiresAtTimestamp: 1779506689379, }, { @@ -61,7 +62,8 @@ const originalInvitation: XOInvitation = { }, ], }, - signature: "7cfc53860ec81403a79a03521a7674ee8d2a11365ee031e4f7f2e36a045bd6e2999510264b29045582a74e1190f0176950a855361f02bc67ff7877fabcf794f4", + signature: + "7cfc53860ec81403a79a03521a7674ee8d2a11365ee031e4f7f2e36a045bd6e2999510264b29045582a74e1190f0176950a855361f02bc67ff7877fabcf794f4", expiresAtTimestamp: 1779506689390, }, { @@ -77,7 +79,8 @@ const originalInvitation: XOInvitation = { }, ], }, - signature: "d9bdd3b24fef6afd13f12da92e832672c6c1b83fb372506faeb7fa4ea0e39e3a32ad74493fbe7a393aed58bc18226431dabae09948ce371ad3f77b0219cb3831", + signature: + "d9bdd3b24fef6afd13f12da92e832672c6c1b83fb372506faeb7fa4ea0e39e3a32ad74493fbe7a393aed58bc18226431dabae09948ce371ad3f77b0219cb3831", expiresAtTimestamp: 1779506689412, }, { @@ -85,7 +88,8 @@ const originalInvitation: XOInvitation = { previousCommitIdentifier: "583208aa304c0aa9841d1400efe6b6aa", entityIdentifier: CUSTOMER_ENTITY, data: {}, - signature: "63be8af81622da4fccc7eb6b81c6174879fe6aa113b8dae794bd42d4d5c87ae550a18be1e6cb5edf231e774bdc7883eb5a78bd02188579dce58da0d449c43865", + signature: + "63be8af81622da4fccc7eb6b81c6174879fe6aa113b8dae794bd42d4d5c87ae550a18be1e6cb5edf231e774bdc7883eb5a78bd02188579dce58da0d449c43865", expiresAtTimestamp: 1779506979194, }, { @@ -101,7 +105,8 @@ const originalInvitation: XOInvitation = { }, ], }, - signature: "e36942eb5f147e620659d20b7059630da871944e74fe5ffb3c4ff0298a5aedb101bc7468b19750114cbcfa56b99bd4a080453a31084f18173adcd9442fca4303", + signature: + "e36942eb5f147e620659d20b7059630da871944e74fe5ffb3c4ff0298a5aedb101bc7468b19750114cbcfa56b99bd4a080453a31084f18173adcd9442fca4303", expiresAtTimestamp: 1779507006272, }, { @@ -117,7 +122,8 @@ const originalInvitation: XOInvitation = { }, ], }, - signature: "2c1d1ed1259a2e4b1bc7187b93029e99e590a4e92ff9c39031319766b7fbcdabab9c3dc20b3d27d05eee198cbc717b9aedfbef92bd3e519c62c60e4731bd936a", + signature: + "2c1d1ed1259a2e4b1bc7187b93029e99e590a4e92ff9c39031319766b7fbcdabab9c3dc20b3d27d05eee198cbc717b9aedfbef92bd3e519c62c60e4731bd936a", expiresAtTimestamp: 1779507008169, }, ], @@ -226,8 +232,7 @@ describe("resolveCommitReferences", () => { { entityIdentifier: MERCHANT_ENTITY, outputIdentifier: "purchaseOutput", - lockingBytecode: - "76a9146a4715fe1cc1ce228336502f1711b06045ef361088ac", + lockingBytecode: "76a9146a4715fe1cc1ce228336502f1711b06045ef361088ac", name: "Purchase Payment", description: "$() sats to $()", icon: "request", @@ -250,8 +255,7 @@ describe("resolveCommitReferences", () => { { entityIdentifier: CUSTOMER_ENTITY, valueSatoshis: 74881n, - lockingBytecode: - "76a9141730ca066d4b9c8d542f8c9bdce645f77697d46088ac", + lockingBytecode: "76a9141730ca066d4b9c8d542f8c9bdce645f77697d46088ac", }, ], });