-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathremove-piece.ts
More file actions
159 lines (132 loc) · 5.24 KB
/
Copy pathremove-piece.ts
File metadata and controls
159 lines (132 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* CLI entrypoint for removing a piece from a Data Set.
*
* Responsibilities:
* - Validate required CLI arguments (piece CID, dataSet)
* - Initialize Synapse with CLI auth/env configuration
* - Wire up progress events to spinner output
* - Return transaction hash and confirmation status (or throw on failure)
*/
import pc from 'picocolors'
import pino from 'pino'
import { setIncompleteExitCode } from '../common/cli-errors.js'
import { type RemovePieceProgressEvents, removePiece } from '../core/piece/index.js'
import { initializeSynapse } from '../core/synapse/index.js'
import { parseCLIAuth } from '../utils/cli-auth.js'
import { cancel, createSpinner, intro, outro } from '../utils/cli-helpers.js'
import { log } from '../utils/cli-logger.js'
import type { RmPieceOptions, RmPieceResult } from './types.js'
/**
* Run the remove piece process.
*
* @param options - CLI options including piece CID and dataSet id
* @returns Transaction hash, confirmation status, and identifiers used
*
* Behavior:
* - Requires both `piece` and `dataSet`; throws if missing/invalid
* - Uses CLI auth env/flags via parseCLIAuth
* - Streams progress to spinner and exits with cancel on failure
* - Always calls cleanupSynapseService to close providers
*/
export async function runRmPiece(options: RmPieceOptions): Promise<RmPieceResult> {
intro(pc.bold('Filecoin Pin Remove'))
const spinner = createSpinner()
// Initialize logger (silent for CLI output)
const logger = pino({
level: process.env.LOG_LEVEL || 'silent',
})
const { piece: pieceCid, dataSet } = options
// Validate inputs
if (!pieceCid || !dataSet) {
spinner.stop(`${pc.red('✗')} Piece CID and DataSet ID are required`)
cancel('Remove cancelled')
throw new Error('Piece CID and DataSet ID are required')
}
const dataSetId = Number(dataSet)
if (!Number.isInteger(dataSetId) || dataSetId <= 0) {
spinner.stop(`${pc.red('✗')} DataSet ID must be a positive integer`)
cancel('Remove cancelled')
throw new Error('DataSet ID must be a positive integer')
}
try {
spinner.start('Initializing Synapse SDK...')
const authConfig = await parseCLIAuth(options)
const synapse = await initializeSynapse(authConfig, logger)
const network = synapse.chain.name
spinner.stop(`${pc.green('✓')} Connected to ${pc.bold(network)}`)
log.spinnerSection('Remove Configuration', [
pc.gray(`Piece CID: ${pieceCid}`),
pc.gray(`Data Set ID: ${dataSetId}`),
])
// Track transaction details
let txHash = ''
let isConfirmed = false
// Remove piece with progress tracking
const onProgress = (event: RemovePieceProgressEvents): void => {
switch (event.type) {
case 'removePiece:submitting':
spinner.message('Submitting remove transaction...')
break
case 'removePiece:submitted':
spinner.message(`Transaction submitted: ${event.data.txHash}`)
txHash = event.data.txHash
break
case 'removePiece:confirming':
spinner.message('Waiting for transaction confirmation...')
break
case 'removePiece:confirmationFailed':
spinner.message(`${pc.yellow('⚠')} Confirmation wait timed out: ${event.data.message}`)
break
case 'removePiece:complete':
isConfirmed = event.data.confirmed
txHash = event.data.txHash
// Main flow will handle stopping the spinner
break
}
}
spinner.start('Creating storage context...')
const storage = await synapse.storage.createContext({ dataSetId: BigInt(dataSetId) })
spinner.stop(`${pc.green('✓')} Storage context created`)
spinner.start('Removing piece...')
txHash = await removePiece(pieceCid, storage, {
synapse,
logger,
onProgress,
waitForConfirmation: options.waitForConfirmation ?? false,
})
// Time-out waiting for requested confirmation, leaving the removal
// unconfirmed. Signal that distinctly so scripts can tell it apart from
// both success (0) and a caught error (1).
const confirmationPending = options.waitForConfirmation === true && !isConfirmed
if (confirmationPending) {
setIncompleteExitCode()
}
// Ensure spinner is stopped before displaying results
spinner.stop(`${pc.green('✓')} Piece removed${isConfirmed ? ' and confirmed' : ' (confirmation pending)'}`)
// Display results
log.spinnerSection('Results', [
pc.gray(`Transaction Hash: ${txHash}`),
pc.gray(`Status: ${isConfirmed ? 'Confirmed' : 'Pending confirmation'}`),
pc.gray(`Network: ${network}`),
])
const result: RmPieceResult = {
pieceCid,
dataSetId,
transactionHash: txHash,
confirmed: isConfirmed,
}
// Clean up WebSocket providers to allow process termination
// Synapse instances don't require explicit cleanup
if (confirmationPending) {
outro('Remove submitted; confirmation still pending')
} else {
outro('Remove completed successfully')
}
return result
} catch (error) {
spinner.stop(`${pc.red('✗')} Remove failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
logger.error({ event: 'rm.failed', error }, 'Remove failed')
cancel('Remove failed')
throw error
}
}