@@ -7,31 +7,93 @@ import { getAppInfo } from '../delegatee/get-app-info';
77 * Registers a new app version. On-chain app versions are immutable, so any time you modify
88 * abilities or policies, you must register a new version of your app using the new ipfs CIDs
99 *
10+ * This function will check if the latest app version already has the same abilities and policies.
11+ * If they match, it will return the existing appVersion without registering a new one.
12+ *
1013 * @param abilityIpfsCids - Array of ability IPFS CIDs to register
11- * @param abilityPolicies - Array of policy IPFS CIDs for each ability
14+ * @param abilityPolicies - Array of policy IPFS CIDs for each ability (must be parallel to abilityIpfsCids)
15+ * @param registerNewVersionOverride - Whether to register a new version even if the latest version already has the same abilities and policies
16+ *
17+ * @remarks
18+ * Assumptions:
19+ * - `abilityIpfsCids` and `abilityPolicies` are parallel arrays where `abilityPolicies[i]` contains
20+ * the policy CIDs for the ability at `abilityIpfsCids[i]`
21+ * - The comparison is order-independent for both abilities and policies within each ability
22+ * - Two app versions are considered equivalent if they have the same set of abilities (regardless of order)
23+ * and each ability has the same set of policies (regardless of order)
1224 */
1325export async function registerNewAppVersion ( {
1426 abilityIpfsCids,
1527 abilityPolicies,
28+ registerNewVersionOverride = false ,
1629} : {
1730 abilityIpfsCids : string [ ] ;
1831 abilityPolicies : string [ ] [ ] ;
32+ registerNewVersionOverride ?: boolean ;
1933} ) {
2034 const app = await getAppInfo ( ) ;
2135
2236 if ( ! app ) {
2337 throw new Error ( 'App was expected, but not found. Please register a new app first.' ) ;
2438 }
2539
26- const { appId } = app ;
40+ const { appId, appVersion : latestVersion } = app ;
2741
2842 const {
2943 wallets : { appManager } ,
3044 } = await getChainHelpers ( ) ;
3145
32- const { txHash, newAppVersion } = await getClient ( {
33- signer : appManager ,
34- } ) . registerNextVersion ( {
46+ const client = getClient ( { signer : appManager } ) ;
47+
48+ if ( ! registerNewVersionOverride ) {
49+ // Get the existing app version to compare
50+ const existingAppVersion = await client . getAppVersion ( {
51+ appId,
52+ version : latestVersion ,
53+ } ) ;
54+
55+ if ( existingAppVersion ) {
56+ // Create a map from ability CID to its policies for easy lookup
57+ const existingAbilityMap = new Map < string , string [ ] > ( ) ;
58+ existingAppVersion . appVersion . abilities . forEach ( ( ability ) => {
59+ existingAbilityMap . set ( ability . abilityIpfsCid , ability . policyIpfsCids ) ;
60+ } ) ;
61+
62+ // Check if we have the same number of abilities and compare them
63+ if ( existingAbilityMap . size === abilityIpfsCids . length ) {
64+ // For each ability in the new version, check if it exists with the same policies
65+ const allMatch = abilityIpfsCids . every ( ( abilityId , index ) => {
66+ const existingPolicies = existingAbilityMap . get ( abilityId ) ;
67+ if ( existingPolicies === undefined ) return false ; // Ability doesn't exist in current version
68+
69+ const newPolicies = abilityPolicies [ index ] ;
70+ if ( newPolicies === undefined ) {
71+ throw new Error (
72+ `Parallel arrays are not in sync: abilityPolicies[${ index } ] is undefined for ability '${ abilityId } '.` ,
73+ ) ;
74+ }
75+
76+ // Compare policy arrays (order-independent)
77+ if ( existingPolicies . length !== newPolicies . length ) return false ;
78+
79+ const sortedExisting = [ ...existingPolicies ] . sort ( ) ;
80+ const sortedNew = [ ...newPolicies ] . sort ( ) ;
81+
82+ return sortedExisting . every ( ( policy , i ) => policy === sortedNew [ i ] ) ;
83+ } ) ;
84+
85+ if ( allMatch ) {
86+ console . log (
87+ `App version ${ latestVersion } already has the same abilities and policies. Skipping registration.` ,
88+ ) ;
89+ return { appId, appVersion : latestVersion } ;
90+ }
91+ }
92+ }
93+ }
94+
95+ // Register new version if abilities or policies have changed
96+ const { txHash, newAppVersion } = await client . registerNextVersion ( {
3597 appId,
3698 versionAbilities : {
3799 abilityIpfsCids : abilityIpfsCids ,
0 commit comments