Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6218f7a

Browse files
committedJan 29, 2025·
Refactor importActorProfile and validateExportStream functions to improve error handling, normalize file names, and skip system-generated files
1 parent f575f7d commit 6218f7a

File tree

2 files changed

+56
-20
lines changed

2 files changed

+56
-20
lines changed
 

‎src/index.ts

+41-19
Original file line numberDiff line numberDiff line change
@@ -182,31 +182,35 @@ export async function exportActorProfile({
182182
/**
183183
* Imports an ActivityPub profile from a .tar archive stream.
184184
* @param tarStream - A ReadableStream containing the .tar archive.
185+
* @param options - Options for the import process.
185186
* @returns A promise that resolves to the parsed profile data.
186187
*/
187188
export async function importActorProfile(
188-
tarStream: Readable
189+
tarStream: Readable,
190+
options: {
191+
console?: Pick<Console, 'log' | 'warn' | 'error'>
192+
onError?: (error: Error, context: { fileName?: string }) => void
193+
} = {}
189194
): Promise<Record<string, any>> {
190-
console.log('🚀 Starting to process tar stream...')
195+
const { console = undefined, onError = undefined } = options
191196
const extract = tar.extract()
192197
const result: Record<string, any> = {}
193198

194199
return await new Promise((resolve, reject) => {
195200
extract.on('entry', (header, stream, next) => {
196-
// Normalize fileName to include only `activitypub/filename`
197201
const originalFileName = header.name
198-
const fileName = `activitypub/${path.basename(originalFileName)}`
202+
const basename = path.basename(originalFileName)
203+
console?.log('🚀 ~ extract.on ~ basename:', basename)
204+
const fileName = `activitypub/${basename}`
199205

200206
// Skip system-generated files
201-
if (
202-
fileName.startsWith('activitypub/._') ||
203-
fileName.endsWith('.DS_Store')
204-
) {
205-
console.warn(`Skipping system-generated file: ${fileName}`)
207+
if (basename.startsWith('.')) {
208+
console?.warn(`Skipping system-generated file: ${fileName}`)
206209
next()
210+
return
207211
}
208212

209-
console.log(`Processing file: ${fileName}`)
213+
console?.log(`Processing file: ${fileName}`)
210214
let content = ''
211215

212216
stream.on('data', (chunk) => {
@@ -217,40 +221,58 @@ export async function importActorProfile(
217221
try {
218222
if (fileName.endsWith('.json')) {
219223
result[fileName] = JSON.parse(content)
220-
console.log('Parsed JSON file successfully:', fileName)
224+
console?.log('Parsed JSON file successfully:', fileName)
221225
} else if (fileName.endsWith('.yaml') || fileName.endsWith('.yml')) {
222226
result[fileName] = YAML.parse(content)
223227
} else if (fileName.endsWith('.csv')) {
224228
result[fileName] = content
225229
} else {
226-
console.warn(`Unsupported file type: ${fileName}, skipping...`)
230+
console?.warn(`Unsupported file type: ${fileName}, skipping...`)
227231
}
228232
} catch (error: any) {
229-
console.error(`Error processing file ${fileName}:`, error.message)
233+
const errorMessage = `Error processing file ${fileName}: ${error.message}`
234+
if (onError) {
235+
onError(new Error(errorMessage), { fileName })
236+
} else {
237+
reject(new Error(errorMessage))
238+
}
230239
} finally {
231240
next() // Always continue
232241
}
233242
})
234243

235244
stream.on('error', (error: any) => {
236-
console.error(`Stream error on file ${fileName}:`, error.message)
245+
const errorMessage = `Stream error on file ${fileName}: ${error.message}`
246+
if (onError) {
247+
onError(new Error(errorMessage), { fileName })
248+
} else {
249+
reject(new Error(errorMessage))
250+
}
237251
next() // Continue even on stream error
238252
})
239253
})
240254

241255
extract.on('finish', () => {
242-
console.log('All files processed successfully.')
256+
console?.log('All files processed successfully.')
243257
resolve(result)
244258
})
245259

246260
extract.on('error', (error) => {
247-
console.error('Error during tar extraction:', error.message)
248-
reject(new Error('Failed to extract tar file.'))
261+
const errorMessage = `Error during tar extraction: ${error.message}`
262+
if (onError) {
263+
onError(new Error(errorMessage), {})
264+
} else {
265+
reject(new Error(errorMessage))
266+
}
249267
})
250268

251269
tarStream.on('error', (error) => {
252-
console.error('Error in tar stream:', error.message)
253-
reject(new Error('Failed to process tar stream.'))
270+
const errorMessage = `Error in tar stream: ${error.message}`
271+
if (onError) {
272+
onError(new Error(errorMessage), {})
273+
} else {
274+
reject(new Error(errorMessage))
275+
}
254276
})
255277

256278
tarStream.pipe(extract)

‎src/verify.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as tar from 'tar-stream'
22
import { type Readable } from 'stream'
33
import YAML from 'yaml'
4+
import path from 'path'
45

56
/**
67
* Validates the structure and content of an exported ActivityPub tarball.
@@ -22,7 +23,20 @@ export async function validateExportStream(
2223

2324
return await new Promise((resolve) => {
2425
extract.on('entry', (header, stream, next) => {
25-
const fileName = header.name.toLowerCase() // Normalize file name
26+
const originalFileName = header.name
27+
const basename = path.basename(originalFileName)
28+
console?.log('🚀 ~ extract.on ~ basename:', basename)
29+
const fileName =
30+
basename === 'manifest.yaml'
31+
? 'manifest.yaml'
32+
: `activitypub/${basename}`
33+
34+
// Skip system-generated files
35+
if (basename.startsWith('.')) {
36+
console?.warn(`Skipping system-generated file: ${fileName}`)
37+
next()
38+
return
39+
}
2640
foundFiles.add(fileName)
2741

2842
let content = ''

0 commit comments

Comments
 (0)
Please sign in to comment.