@filoz/repair-cli 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/cli.js +2 -0
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/commands/datasets.d.ts +1 -0
  5. package/dist/src/commands/datasets.d.ts.map +1 -1
  6. package/dist/src/commands/datasets.js +14 -3
  7. package/dist/src/commands/datasets.js.map +1 -1
  8. package/dist/src/commands/providers.d.ts +1 -0
  9. package/dist/src/commands/providers.d.ts.map +1 -1
  10. package/dist/src/commands/providers.js.map +1 -1
  11. package/dist/src/commands/repair.d.ts +1 -0
  12. package/dist/src/commands/repair.d.ts.map +1 -1
  13. package/dist/src/commands/repair.js +7 -8
  14. package/dist/src/commands/repair.js.map +1 -1
  15. package/dist/src/commands/replicate.d.ts +24 -0
  16. package/dist/src/commands/replicate.d.ts.map +1 -0
  17. package/dist/src/commands/replicate.js +171 -0
  18. package/dist/src/commands/replicate.js.map +1 -0
  19. package/dist/src/commands/setup.d.ts +0 -1
  20. package/dist/src/commands/setup.d.ts.map +1 -1
  21. package/dist/src/commands/setup.js +17 -4
  22. package/dist/src/commands/setup.js.map +1 -1
  23. package/dist/src/commands/wallet.d.ts +1 -0
  24. package/dist/src/commands/wallet.d.ts.map +1 -1
  25. package/dist/src/db/dedupe-cids.d.ts +22 -0
  26. package/dist/src/db/dedupe-cids.d.ts.map +1 -0
  27. package/dist/src/db/dedupe-cids.js +28 -0
  28. package/dist/src/db/dedupe-cids.js.map +1 -0
  29. package/dist/src/db/find-providers-by-cid.d.ts +9 -0
  30. package/dist/src/db/find-providers-by-cid.d.ts.map +1 -0
  31. package/dist/src/db/{get-providers-by-cid.js → find-providers-by-cid.js} +4 -6
  32. package/dist/src/db/find-providers-by-cid.js.map +1 -0
  33. package/dist/src/db/find-repair-dataset.d.ts +10 -0
  34. package/dist/src/db/find-repair-dataset.d.ts.map +1 -0
  35. package/dist/src/db/{get-repair-dataset.js → find-repair-dataset.js} +3 -4
  36. package/dist/src/db/find-repair-dataset.js.map +1 -0
  37. package/dist/src/db/get-pieces.d.ts +16 -0
  38. package/dist/src/db/get-pieces.d.ts.map +1 -1
  39. package/dist/src/db/get-pieces.js +44 -3
  40. package/dist/src/db/get-pieces.js.map +1 -1
  41. package/dist/src/db/repair-create.d.ts.map +1 -1
  42. package/dist/src/db/repair-create.js +1 -0
  43. package/dist/src/db/repair-create.js.map +1 -1
  44. package/dist/src/db/repair-delete.d.ts.map +1 -1
  45. package/dist/src/db/repair-delete.js +0 -5
  46. package/dist/src/db/repair-delete.js.map +1 -1
  47. package/dist/src/db/replicate-create.d.ts +7 -0
  48. package/dist/src/db/replicate-create.d.ts.map +1 -0
  49. package/dist/src/db/replicate-create.js +78 -0
  50. package/dist/src/db/replicate-create.js.map +1 -0
  51. package/dist/src/db/upsert-operations.js +1 -1
  52. package/dist/src/db/upsert-operations.js.map +1 -1
  53. package/dist/src/local-schema.d.ts +19 -0
  54. package/dist/src/local-schema.d.ts.map +1 -1
  55. package/dist/src/local-schema.js +1 -0
  56. package/dist/src/local-schema.js.map +1 -1
  57. package/dist/src/middleware.d.ts +2 -0
  58. package/dist/src/middleware.d.ts.map +1 -1
  59. package/dist/src/middleware.js +4 -2
  60. package/dist/src/middleware.js.map +1 -1
  61. package/dist/src/pipeline/add-pieces.d.ts +12 -0
  62. package/dist/src/pipeline/add-pieces.d.ts.map +1 -0
  63. package/dist/src/pipeline/add-pieces.js +143 -0
  64. package/dist/src/pipeline/add-pieces.js.map +1 -0
  65. package/dist/src/pipeline/create-datasets.d.ts +3 -1
  66. package/dist/src/pipeline/create-datasets.d.ts.map +1 -1
  67. package/dist/src/pipeline/create-datasets.js +57 -5
  68. package/dist/src/pipeline/create-datasets.js.map +1 -1
  69. package/dist/src/utils.d.ts +32 -2
  70. package/dist/src/utils.d.ts.map +1 -1
  71. package/dist/src/utils.js +40 -7
  72. package/dist/src/utils.js.map +1 -1
  73. package/package.json +1 -1
  74. package/readme.md +110 -7
  75. package/src/cli.ts +2 -0
  76. package/src/commands/datasets.ts +15 -4
  77. package/src/commands/providers.ts +0 -1
  78. package/src/commands/repair.ts +12 -8
  79. package/src/commands/replicate.ts +183 -0
  80. package/src/commands/setup.ts +18 -4
  81. package/src/db/dedupe-cids.ts +49 -0
  82. package/src/db/{get-providers-by-cid.ts → find-providers-by-cid.ts} +5 -10
  83. package/src/db/{get-repair-dataset.ts → find-repair-dataset.ts} +6 -5
  84. package/src/db/get-pieces.ts +105 -3
  85. package/src/db/get-target-dataset.ts +1 -1
  86. package/src/db/repair-create.ts +1 -0
  87. package/src/db/repair-delete.ts +0 -5
  88. package/src/db/replicate-create.ts +106 -0
  89. package/src/db/upsert-operations.ts +1 -1
  90. package/src/local-schema.ts +1 -0
  91. package/src/middleware.ts +4 -2
  92. package/src/pipeline/add-pieces.ts +215 -0
  93. package/src/pipeline/create-datasets.ts +71 -5
  94. package/src/utils.ts +49 -10
  95. package/dist/src/db/get-providers-by-cid.d.ts +0 -10
  96. package/dist/src/db/get-providers-by-cid.d.ts.map +0 -1
  97. package/dist/src/db/get-providers-by-cid.js.map +0 -1
  98. package/dist/src/db/get-repair-dataset.d.ts +0 -9
  99. package/dist/src/db/get-repair-dataset.d.ts.map +0 -1
  100. package/dist/src/db/get-repair-dataset.js.map +0 -1
  101. package/dist/src/db/sync-pieces-onchain.d.ts +0 -10
  102. package/dist/src/db/sync-pieces-onchain.d.ts.map +0 -1
  103. package/dist/src/db/sync-pieces-onchain.js +0 -35
  104. package/dist/src/db/sync-pieces-onchain.js.map +0 -1
  105. package/dist/src/pipeline/pull.d.ts +0 -30
  106. package/dist/src/pipeline/pull.d.ts.map +0 -1
  107. package/dist/src/pipeline/pull.js +0 -169
  108. package/dist/src/pipeline/pull.js.map +0 -1
  109. package/src/db/sync-pieces-onchain.ts +0 -53
  110. package/src/pipeline/pull.ts +0 -255
@@ -1,255 +0,0 @@
1
- import { taskLog } from '@clack/prompts'
2
- import * as Piece from '@filoz/synapse-core/piece'
3
- import { createPieceUrlPDP } from '@filoz/synapse-core/piece'
4
- import * as SP from '@filoz/synapse-core/sp'
5
- import { and, asc, eq, gt, inArray } from 'drizzle-orm'
6
- import PQueue from 'p-queue'
7
- import { getTargetDataset } from '../db/get-target-dataset.ts'
8
- import { syncPiecesOnchain } from '../db/sync-pieces-onchain.ts'
9
- import { updateOperation } from '../db/update-operation.ts'
10
- import { upsertOperations } from '../db/upsert-operations.ts'
11
- import type { OperationSelect, RepairSelect } from '../local-schema.ts'
12
- import type { IndexerDatabase, LocalDatabase, WalletClient } from '../types.ts'
13
- import { hashLink } from '../utils.ts'
14
-
15
- /** Pending `add_piece` operations batched for a single pull job. */
16
- export type PullPiecesBatch = {
17
- operations: OperationSelect[]
18
- }
19
-
20
- export type RunPullPiecesPhaseOptions = {
21
- localDb: LocalDatabase
22
- indexerDb: IndexerDatabase
23
- repair: RepairSelect
24
- concurrency: number
25
- batchSize: number
26
- client: WalletClient
27
- reset: boolean
28
- }
29
-
30
- /** Mock pull worker: logs each batch and its piece CIDs. */
31
- export function createPullPiecesWorker({
32
- localDb,
33
- indexerDb,
34
- repair,
35
- client,
36
- state,
37
- log,
38
- }: {
39
- localDb: LocalDatabase
40
- indexerDb: IndexerDatabase
41
- repair: RepairSelect
42
- client: WalletClient
43
- state: {
44
- totalBatches: number
45
- totalOperations: number
46
- completedOperations: number
47
- failedOperations: number
48
- }
49
- log: ReturnType<typeof taskLog>
50
- }) {
51
- return async (batch: PullPiecesBatch, batchNumber: number) => {
52
- let completedCids = 0
53
- let failedCids = 0
54
- const cidToOperation = new Map<string, OperationSelect>()
55
-
56
- const spin = log.group(`Batch ${batchNumber}/${state.totalBatches}`)
57
- spin.message(`Pull 0 completed, 0 failed`)
58
-
59
- try {
60
- const dataset = await getTargetDataset({ localDb, repairId: repair.id, client })
61
-
62
- for (const operation of batch.operations) {
63
- cidToOperation.set(operation.cid, operation)
64
- }
65
-
66
- // sync pieces onchain to avoid duplicates
67
- const completedOperations1 = await syncPiecesOnchain({
68
- indexerDb,
69
- localDb,
70
- dataSetId: dataset.dataSetId,
71
- cidToOperation,
72
- })
73
- state.completedOperations += completedOperations1
74
- completedCids += completedOperations1
75
-
76
- // create pull pieces
77
- const pullPieces: SP.PullPieceInput[] = []
78
- for (const [cid, operation] of cidToOperation) {
79
- const pieceCid = Piece.from(cid)
80
- const sourceUrl = createPieceUrlPDP({
81
- cid,
82
- serviceURL: operation.alternateProvider,
83
- })
84
- pullPieces.push({ pieceCid, sourceUrl })
85
- }
86
-
87
- if (pullPieces.length > 0) {
88
- // wait for pull pieces
89
- const pullResult = await SP.waitForPullPieces(client, {
90
- serviceURL: repair.targetProviderUrl,
91
- dataSetId: dataset.dataSetId,
92
- clientDataSetId: dataset.clientDataSetId,
93
- pieces: pullPieces,
94
- timeout: 1000 * 60 * 30,
95
- onStatus: (_status) => {
96
- const completed = _status.pieces.filter((piece) => piece.status === 'complete').length
97
- const failed = _status.pieces.filter((piece) => piece.status === 'failed').length
98
- spin.message(`Pull ${completed} completed, ${failed} failed`)
99
- },
100
- })
101
-
102
- for (const { pieceCid, status } of pullResult.pieces) {
103
- const cid = pieceCid.toString()
104
- const operation = cidToOperation.get(cid)
105
- if (!operation) {
106
- console.log(`operation not found for cid ${cid}`)
107
- continue
108
- }
109
-
110
- if (status !== 'complete') {
111
- state.failedOperations++
112
- failedCids++
113
- cidToOperation.delete(cid)
114
- await updateOperation({
115
- localDb,
116
- operationId: operation.id,
117
- status: 'failed',
118
- error: `pull failed with status ${status}`,
119
- })
120
- }
121
- }
122
- }
123
-
124
- // sync against indexer to avoid duplicates
125
- const completedOperations2 = await syncPiecesOnchain({
126
- indexerDb,
127
- localDb,
128
- dataSetId: dataset.dataSetId,
129
- cidToOperation,
130
- })
131
- state.completedOperations += completedOperations2
132
- completedCids += completedOperations2
133
-
134
- const commitPieces: SP.addPieces.PieceType[] = []
135
- for (const [cid] of cidToOperation) {
136
- commitPieces.push({
137
- pieceCid: Piece.from(cid),
138
- })
139
- }
140
-
141
- if (commitPieces.length > 0) {
142
- const addPiecesResult = await SP.addPieces(client, {
143
- serviceURL: repair.targetProviderUrl,
144
- dataSetId: dataset.dataSetId,
145
- clientDataSetId: dataset.clientDataSetId,
146
- pieces: commitPieces,
147
- })
148
-
149
- spin.message(`Waiting for add pieces ${hashLink(addPiecesResult.txHash, client.chain)}...`)
150
- const addPiecesResult2 = await SP.waitForAddPieces(addPiecesResult)
151
- state.completedOperations += cidToOperation.size
152
- completedCids += cidToOperation.size
153
- await upsertOperations({
154
- localDb,
155
- operations: Array.from(cidToOperation.values()).map((operation) => ({
156
- ...operation,
157
- status: 'completed',
158
- error: null,
159
- result: { dataSetId: addPiecesResult2.dataSetId, txHash: addPiecesResult2.txHash },
160
- })),
161
- })
162
- }
163
- spin.success(`Batch ${batchNumber}/${state.totalBatches} ${completedCids} added, ${failedCids} failed`)
164
- } catch (error) {
165
- state.failedOperations += cidToOperation.size
166
- const message = error instanceof Error ? error.message : 'Unknown error'
167
- spin.error(`Batch ${batchNumber}/${state.totalBatches} - ${message.replace(/\n/g, ' ')}`)
168
- await upsertOperations({
169
- localDb,
170
- operations: Array.from(cidToOperation.values()).map((operation) => ({
171
- ...operation,
172
- status: 'failed',
173
- error: message,
174
- })),
175
- })
176
- }
177
- }
178
- }
179
-
180
- /**
181
- * Pull pending `add_piece` operations without loading the whole repair into memory.
182
- *
183
- * Pending piece operations are fetched lazily and queued with bounded backpressure. Failed piece
184
- * operations are intentionally skipped unless `reset` is set.
185
- */
186
- export async function runPullPiecesPhase({
187
- localDb,
188
- indexerDb,
189
- repair,
190
- concurrency,
191
- batchSize,
192
- client,
193
- reset,
194
- }: RunPullPiecesPhaseOptions): Promise<void> {
195
- const localSchema = localDb._.fullSchema
196
- const pullConcurrency = Math.max(1, concurrency)
197
- const pullBatchSize = Math.max(1, batchSize)
198
- let pullCursor = 0
199
-
200
- const totalOperations = await localDb.$count(
201
- localSchema.operations,
202
- and(
203
- eq(localSchema.operations.repairId, repair.id),
204
- eq(localSchema.operations.type, 'add_piece'),
205
- inArray(localSchema.operations.status, reset ? ['pending', 'failed'] : ['pending'])
206
- )
207
- )
208
- let batchNumber = 0
209
- const state = {
210
- totalBatches: Math.ceil(totalOperations / pullBatchSize),
211
- totalOperations,
212
- completedOperations: 0,
213
- failedOperations: 0,
214
- }
215
-
216
- const log = taskLog({
217
- title: 'Pulling pieces',
218
- limit: 1,
219
- })
220
-
221
- async function getNextPullBatch(): Promise<PullPiecesBatch | null> {
222
- const operations = await localDb.query.operations.findMany({
223
- where: and(
224
- eq(localSchema.operations.repairId, repair.id),
225
- eq(localSchema.operations.type, 'add_piece'),
226
- inArray(localSchema.operations.status, reset ? ['pending', 'failed'] : ['pending']),
227
- gt(localSchema.operations.id, pullCursor)
228
- ),
229
- orderBy: [asc(localSchema.operations.id)],
230
- limit: pullBatchSize,
231
- })
232
- if (operations.length === 0) {
233
- return null
234
- }
235
-
236
- pullCursor = operations.at(-1)?.id ?? pullCursor
237
- return { operations }
238
- }
239
-
240
- const pullPiecesWorker = createPullPiecesWorker({ localDb, indexerDb, repair, client, state, log })
241
- const pullPiecesQueue = new PQueue({ concurrency: pullConcurrency })
242
-
243
- while (true) {
244
- await pullPiecesQueue.onSizeLessThan(pullConcurrency)
245
- const batch = await getNextPullBatch()
246
- if (!batch) break
247
- batchNumber++
248
- const currentBatchNumber = batchNumber
249
- pullPiecesQueue.add(() => pullPiecesWorker(batch, currentBatchNumber)).catch(console.error)
250
- }
251
-
252
- await pullPiecesQueue.onIdle()
253
-
254
- log.success(`Pulled ${state.completedOperations} pieces, ${state.failedOperations} failed`)
255
- }