diff --git a/package-lock.json b/package-lock.json index 3be7ca18..30ad5e68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,14 +15,14 @@ "@dfinity/ic-management": "^6.1.1", "@dfinity/identity": "^2.3.0", "@dfinity/principal": "^2.3.0", - "@junobuild/admin": "^0.5.0-next-2025-05-31.3", - "@junobuild/cdn": "^0.1.0-next-2025-05-31.3", - "@junobuild/cli-tools": "^0.2.0-next-2025-05-31.3", + "@junobuild/admin": "^0.5.0-next-2025-06-01", + "@junobuild/cdn": "^0.1.0-next-2025-06-01", + "@junobuild/cli-tools": "^0.2.0-next-2025-06-01", "@junobuild/config": "^0.1.8", "@junobuild/config-loader": "^0.2.1", - "@junobuild/core": "^0.1.15-next-2025-05-31.3", + "@junobuild/core": "^0.1.15-next-2025-06-01", "@junobuild/did-tools": "^0.2.1", - "@junobuild/storage": "^0.2.0-next-2025-05-31.3", + "@junobuild/storage": "^0.2.0-next-2025-06-01", "@junobuild/utils": "^0.1.3", "chokidar": "^4.0.3", "conf": "^13.1.0", @@ -1464,9 +1464,9 @@ } }, "node_modules/@junobuild/admin": { - "version": "0.5.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/admin/-/admin-0.5.0-next-2025-05-31.3.tgz", - "integrity": "sha512-OwEm/DDFdHpZN3eCQkBvTx1o8RoodvezfG2XzpDYgpPbJaxN0CSsPaLBXIrObS0x+EvPdrA1j3/rd1TBqU+s8Q==", + "version": "0.5.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/admin/-/admin-0.5.0-next-2025-06-01.tgz", + "integrity": "sha512-94Wu/9z6DB4E++oLClu8I6Je6hnszqwz3WNjqDpCBCrTXAd9K2o8LZ/DC5fruCbx24whE6Jisltwk2f/LtS82g==", "license": "MIT", "peerDependencies": { "@dfinity/agent": "*", @@ -1481,9 +1481,9 @@ } }, "node_modules/@junobuild/cdn": { - "version": "0.1.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/cdn/-/cdn-0.1.0-next-2025-05-31.3.tgz", - "integrity": "sha512-88RxfdQcxA4PVQLVdTOtp3MVUQ+os9slJZiIoe7FLBUo1qCpALFX1yOLnl1AvzgDbhWIg32Bai13BQAMeQNoIg==", + "version": "0.1.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/cdn/-/cdn-0.1.0-next-2025-06-01.tgz", + "integrity": "sha512-QbXh9pR2RDmYB8D8z8tFcMulIax6w82k9Rf8eJ32QO9Rp1QL1+mqX7wrmSv+WftXXz0njgk9MrtRHeaJUHkV6A==", "license": "MIT", "peerDependencies": { "@dfinity/agent": "*", @@ -1497,9 +1497,9 @@ } }, "node_modules/@junobuild/cli-tools": { - "version": "0.2.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/cli-tools/-/cli-tools-0.2.0-next-2025-05-31.3.tgz", - "integrity": "sha512-/kUuYfORcb//ttXr6YUjloc85fkfKLqk4269QhjWq08tac29TjJ9tBzVaBse7cpuBD/RxFddBckUp4P8H8Uqgw==", + "version": "0.2.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/cli-tools/-/cli-tools-0.2.0-next-2025-06-01.tgz", + "integrity": "sha512-KUnrAr+6PKA5KxlcMebS8Pn8GcPl6QOR4mHgrPf5/ZRpB9N9K5yC/LetGu/Xgz30zJMPkVLreRH+1XSMc+zAbg==", "license": "MIT", "dependencies": { "file-type": "^21.0.0", @@ -1536,9 +1536,9 @@ } }, "node_modules/@junobuild/core": { - "version": "0.1.15-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/core/-/core-0.1.15-next-2025-05-31.3.tgz", - "integrity": "sha512-ZZBDgz9aDWtJId9oJgWAuAx11740D7HE3wUrpzr5wBbAspeVkhw12XlrpapYPC3A/IYVPh0yrIm9EsUzLJDkfw==", + "version": "0.1.15-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/core/-/core-0.1.15-next-2025-06-01.tgz", + "integrity": "sha512-4/UhZdrzNnCEDow0elZ5Tm0rpukaa7ACg2ZtwRgGiFB0mmgf/OyZIYwHLXF/w/r3BsEUv7MGoWy9CBo1dm1ckA==", "license": "MIT", "dependencies": { "@junobuild/errors": "*", @@ -1591,9 +1591,9 @@ } }, "node_modules/@junobuild/storage": { - "version": "0.2.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/storage/-/storage-0.2.0-next-2025-05-31.3.tgz", - "integrity": "sha512-43DNxC6etbEuXkT5G1sVUYJzNCWqVao0L5CLuv7JDFHpDeKrOt1TigtFNL5h8cEWLWMJ9SD2lNol609xTmXtTQ==", + "version": "0.2.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/storage/-/storage-0.2.0-next-2025-06-01.tgz", + "integrity": "sha512-wNuiAlk8xKJJMA/nw7JAk+Uc0ErK/Qdi2UP6LCLbrjyw1Umn7d/RCHAWekt9BA2H/G808Sp/rzdypLiDhHEnNg==", "license": "MIT", "peerDependencies": { "@dfinity/agent": "*", @@ -8011,21 +8011,21 @@ } }, "@junobuild/admin": { - "version": "0.5.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/admin/-/admin-0.5.0-next-2025-05-31.3.tgz", - "integrity": "sha512-OwEm/DDFdHpZN3eCQkBvTx1o8RoodvezfG2XzpDYgpPbJaxN0CSsPaLBXIrObS0x+EvPdrA1j3/rd1TBqU+s8Q==", + "version": "0.5.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/admin/-/admin-0.5.0-next-2025-06-01.tgz", + "integrity": "sha512-94Wu/9z6DB4E++oLClu8I6Je6hnszqwz3WNjqDpCBCrTXAd9K2o8LZ/DC5fruCbx24whE6Jisltwk2f/LtS82g==", "requires": {} }, "@junobuild/cdn": { - "version": "0.1.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/cdn/-/cdn-0.1.0-next-2025-05-31.3.tgz", - "integrity": "sha512-88RxfdQcxA4PVQLVdTOtp3MVUQ+os9slJZiIoe7FLBUo1qCpALFX1yOLnl1AvzgDbhWIg32Bai13BQAMeQNoIg==", + "version": "0.1.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/cdn/-/cdn-0.1.0-next-2025-06-01.tgz", + "integrity": "sha512-QbXh9pR2RDmYB8D8z8tFcMulIax6w82k9Rf8eJ32QO9Rp1QL1+mqX7wrmSv+WftXXz0njgk9MrtRHeaJUHkV6A==", "requires": {} }, "@junobuild/cli-tools": { - "version": "0.2.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/cli-tools/-/cli-tools-0.2.0-next-2025-05-31.3.tgz", - "integrity": "sha512-/kUuYfORcb//ttXr6YUjloc85fkfKLqk4269QhjWq08tac29TjJ9tBzVaBse7cpuBD/RxFddBckUp4P8H8Uqgw==", + "version": "0.2.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/cli-tools/-/cli-tools-0.2.0-next-2025-06-01.tgz", + "integrity": "sha512-KUnrAr+6PKA5KxlcMebS8Pn8GcPl6QOR4mHgrPf5/ZRpB9N9K5yC/LetGu/Xgz30zJMPkVLreRH+1XSMc+zAbg==", "requires": { "file-type": "^21.0.0", "listr": "^0.14.3", @@ -8046,9 +8046,9 @@ "requires": {} }, "@junobuild/core": { - "version": "0.1.15-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/core/-/core-0.1.15-next-2025-05-31.3.tgz", - "integrity": "sha512-ZZBDgz9aDWtJId9oJgWAuAx11740D7HE3wUrpzr5wBbAspeVkhw12XlrpapYPC3A/IYVPh0yrIm9EsUzLJDkfw==", + "version": "0.1.15-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/core/-/core-0.1.15-next-2025-06-01.tgz", + "integrity": "sha512-4/UhZdrzNnCEDow0elZ5Tm0rpukaa7ACg2ZtwRgGiFB0mmgf/OyZIYwHLXF/w/r3BsEUv7MGoWy9CBo1dm1ckA==", "requires": { "@junobuild/errors": "*", "@junobuild/storage": "*", @@ -8074,9 +8074,9 @@ "requires": {} }, "@junobuild/storage": { - "version": "0.2.0-next-2025-05-31.3", - "resolved": "https://registry.npmjs.org/@junobuild/storage/-/storage-0.2.0-next-2025-05-31.3.tgz", - "integrity": "sha512-43DNxC6etbEuXkT5G1sVUYJzNCWqVao0L5CLuv7JDFHpDeKrOt1TigtFNL5h8cEWLWMJ9SD2lNol609xTmXtTQ==", + "version": "0.2.0-next-2025-06-01", + "resolved": "https://registry.npmjs.org/@junobuild/storage/-/storage-0.2.0-next-2025-06-01.tgz", + "integrity": "sha512-wNuiAlk8xKJJMA/nw7JAk+Uc0ErK/Qdi2UP6LCLbrjyw1Umn7d/RCHAWekt9BA2H/G808Sp/rzdypLiDhHEnNg==", "requires": {} }, "@junobuild/utils": { diff --git a/package.json b/package.json index ec826242..2c32a0a3 100644 --- a/package.json +++ b/package.json @@ -30,14 +30,14 @@ "@dfinity/ic-management": "^6.1.1", "@dfinity/identity": "^2.3.0", "@dfinity/principal": "^2.3.0", - "@junobuild/admin": "^0.5.0-next-2025-05-31.3", - "@junobuild/cdn": "^0.1.0-next-2025-05-31.3", - "@junobuild/cli-tools": "^0.2.0-next-2025-05-31.3", + "@junobuild/admin": "^0.5.0-next-2025-06-01", + "@junobuild/cdn": "^0.1.0-next-2025-06-01", + "@junobuild/cli-tools": "^0.2.0-next-2025-06-01", "@junobuild/config": "^0.1.8", "@junobuild/config-loader": "^0.2.1", - "@junobuild/core": "^0.1.15-next-2025-05-31.3", + "@junobuild/core": "^0.1.15-next-2025-06-01", "@junobuild/did-tools": "^0.2.1", - "@junobuild/storage": "^0.2.0-next-2025-05-31.3", + "@junobuild/storage": "^0.2.0-next-2025-06-01", "@junobuild/utils": "^0.1.3", "chokidar": "^4.0.3", "conf": "^13.1.0", diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index fb547555..adb2798d 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -9,6 +9,7 @@ import { } from '@junobuild/cli-tools'; import {uploadBlob} from '@junobuild/core'; import {junoConfigExist} from '../configs/juno.config'; +import {clearProposalStagedAssets} from '../services/changes/changes.clear.services'; import {clear} from '../services/clear.services'; import { type DeployFnParams, @@ -87,16 +88,23 @@ const deployWithProposal = async ({args, clearOption}: {args?: string[]; clearOp }); }; - const {result} = await executeDeployWithProposal({ + const result = await executeDeployWithProposal({ args, deployFn, uploadFileFn }); - if (result !== 'deployed') { + if (result.result !== 'deployed') { return; } + const {proposalId} = result; + + await clearProposalStagedAssets({ + args, + proposalId + }); + await links(args); }; diff --git a/src/help/changes.apply.help.ts b/src/help/changes.apply.help.ts index d79c0bde..5ec09bd2 100644 --- a/src/help/changes.apply.help.ts +++ b/src/help/changes.apply.help.ts @@ -8,6 +8,7 @@ const usage = `Usage: ${green('juno')} ${cyan('changes')} ${magenta('apply')} ${ Options: ${yellow('-i, --id')} The ID of the change to apply. ${yellow('-s, --hash')} The expected hash of all included changes (for verification). + ${yellow('-k, --keep-staged')} Keep staged assets in memory after applying the change. ${yellow('-h, --help')} Output usage information.`; const doc = `${CHANGES_APPLY_DESCRIPTION} diff --git a/src/help/changes.reject.help.ts b/src/help/changes.reject.help.ts index f7ca41c4..de596bef 100644 --- a/src/help/changes.reject.help.ts +++ b/src/help/changes.reject.help.ts @@ -8,6 +8,7 @@ const usage = `Usage: ${green('juno')} ${cyan('changes')} ${magenta('reject')} $ Options: ${yellow('-i, --id')} The ID of the change to reject. ${yellow('-s, --hash')} The expected hash of all included changes (for verification). + ${yellow('-k, --keep-staged')} Keep staged assets in memory after applying the change. ${yellow('-h, --help')} Output usage information.`; const doc = `${CHANGES_REJECT_DESCRIPTION} diff --git a/src/help/deploy.help.ts b/src/help/deploy.help.ts index f8ae3070..ac17f38d 100644 --- a/src/help/deploy.help.ts +++ b/src/help/deploy.help.ts @@ -8,9 +8,14 @@ const usage = `Usage: ${green('juno')} ${cyan('deploy')} ${yellow('[options]')} Options: ${yellow('-c, --clear')} Clear existing app files before proceeding with deployment. ${yellow('-n, --no-apply')} Submit the deployment as a change but do not apply it yet. + ${yellow('-k, --keep-staged')} Keep staged assets in memory after applying the change. ${yellow('-i, --immediate')} Deploy files instantly (bypasses the change workflow). ${helpMode} - ${yellow('-h, --help')} Output usage information.`; + ${yellow('-h, --help')} Output usage information. + +Notes: + +- The option ${yellow('--keep-staged')} only applies when ${yellow('--no-apply')} is NOT used (i.e. the change is applied immediately).`; const doc = `${DEPLOY_DESCRIPTION} diff --git a/src/services/changes/changes.apply.services.ts b/src/services/changes/changes.apply.services.ts index e4c92912..029e83aa 100644 --- a/src/services/changes/changes.apply.services.ts +++ b/src/services/changes/changes.apply.services.ts @@ -1,14 +1,33 @@ import {hexStringToUint8Array} from '@dfinity/utils'; import {commitProposal} from '@junobuild/cdn'; import ora from 'ora'; +import type {SatelliteParametersWithId} from '../../types/satellite'; import {readChangesIdAndHash} from '../../utils/changes.utils'; import {assertConfigAndLoadSatelliteContext} from '../../utils/satellite.utils'; +import {clearProposalStagedAssets} from './changes.clear.services'; export const applyChanges = async (args?: string[]) => { const {satellite} = await assertConfigAndLoadSatelliteContext(args); const {proposalId, hash} = readChangesIdAndHash(args); + await executeApplyChanges({satellite, proposalId, hash}); + + await clearProposalStagedAssets({ + args, + proposalId + }); +}; + +const executeApplyChanges = async ({ + satellite, + proposalId, + hash +}: { + proposalId: bigint; + hash: string; + satellite: SatelliteParametersWithId; +}) => { const spinner = ora('Applying...').start(); try { @@ -22,8 +41,12 @@ export const applyChanges = async (args?: string[]) => { } }); + spinner.stop(); + console.log(`\n🎯 Change ID ${proposalId} applied.`); - } finally { + } catch (err: unknown) { spinner.stop(); + + throw err; } }; diff --git a/src/services/changes/changes.clear.services.ts b/src/services/changes/changes.clear.services.ts new file mode 100644 index 00000000..5de1b171 --- /dev/null +++ b/src/services/changes/changes.clear.services.ts @@ -0,0 +1,40 @@ +import {deleteProposalAssets} from '@junobuild/cdn'; +import {hasArgs} from '@junobuild/cli-tools'; +import {green} from 'kleur'; +import ora from 'ora'; +import {assertConfigAndLoadSatelliteContext} from '../../utils/satellite.utils'; + +export const clearProposalStagedAssets = async ({ + args, + proposalId +}: { + args?: string[]; + proposalId: bigint; +}) => { + const keepAssets = hasArgs({args, options: ['-k', '--keep-staged']}); + + if (keepAssets) { + return; + } + + console.log(''); + + const spinner = ora('Deleting staged assets...').start(); + + try { + const {satellite} = await assertConfigAndLoadSatelliteContext(args); + + await deleteProposalAssets({ + cdn: {satellite}, + proposalIds: [proposalId] + }); + + spinner.stop(); + + console.log(`${green('✔')} Staged assets deleted.`); + } catch (err: unknown) { + spinner.stop(); + + throw err; + } +}; diff --git a/src/services/changes/changes.reject.services.ts b/src/services/changes/changes.reject.services.ts index d63b40c7..4eb9d07b 100644 --- a/src/services/changes/changes.reject.services.ts +++ b/src/services/changes/changes.reject.services.ts @@ -1,14 +1,33 @@ import {hexStringToUint8Array} from '@dfinity/utils'; import {rejectProposal} from '@junobuild/cdn'; import ora from 'ora'; +import type {SatelliteParametersWithId} from '../../types/satellite'; import {readChangesIdAndHash} from '../../utils/changes.utils'; import {assertConfigAndLoadSatelliteContext} from '../../utils/satellite.utils'; +import {clearProposalStagedAssets} from './changes.clear.services'; export const rejectChanges = async (args?: string[]) => { const {satellite} = await assertConfigAndLoadSatelliteContext(args); const {proposalId, hash} = readChangesIdAndHash(args); + await executeRejectChanges({satellite, proposalId, hash}); + + await clearProposalStagedAssets({ + args, + proposalId + }); +}; + +const executeRejectChanges = async ({ + satellite, + proposalId, + hash +}: { + proposalId: bigint; + hash: string; + satellite: SatelliteParametersWithId; +}) => { const spinner = ora('Rejecting...').start(); try { @@ -22,8 +41,12 @@ export const rejectChanges = async (args?: string[]) => { } }); + spinner.stop(); + console.log(`\n🚫 Change ID ${proposalId} rejected.`); - } finally { + } catch (err: unknown) { spinner.stop(); + + throw err; } };