Spaces:
Paused
Paused
| import { Router } from 'express'; | |
| import { | |
| APIError, | |
| constants, | |
| createLogger, | |
| RegexAccess, | |
| SelAccess, | |
| UserRepository, | |
| } from '@aiostreams/core'; | |
| import { z } from 'zod'; | |
| import { createResponse } from '../../utils/responses.js'; | |
| const router: Router = Router(); | |
| const logger = createLogger('server'); | |
| const ResolveSyncedSchema = z.object({ | |
| regexUrls: z.array(z.string().url()).max(10).optional(), | |
| selUrls: z.array(z.string().url()).max(10).optional(), | |
| uuid: z.string().optional(), | |
| password: z.string().optional(), | |
| }); | |
| router.post('/resolve', async (req, res, next) => { | |
| const parsed = ResolveSyncedSchema.safeParse(req.body); | |
| if (!parsed.success) { | |
| next( | |
| new APIError( | |
| constants.ErrorCode.MISSING_REQUIRED_FIELDS, | |
| undefined, | |
| 'regexUrls and selUrls must be arrays of valid URLs (max 10 each)' | |
| ) | |
| ); | |
| return; | |
| } | |
| const { regexUrls, selUrls, uuid, password } = parsed.data; | |
| if (!regexUrls?.length && !selUrls?.length) { | |
| next( | |
| new APIError( | |
| constants.ErrorCode.MISSING_REQUIRED_FIELDS, | |
| undefined, | |
| 'At least one of regexUrls or selUrls must be provided' | |
| ) | |
| ); | |
| return; | |
| } | |
| try { | |
| const userData = | |
| (uuid && password | |
| ? await UserRepository.getUser(uuid, password) | |
| : undefined) ?? undefined; | |
| const [regexResults, selResults] = await Promise.all([ | |
| regexUrls?.length | |
| ? RegexAccess.resolvePatternsWithErrors(regexUrls, userData) | |
| : Promise.resolve(undefined), | |
| selUrls?.length | |
| ? SelAccess.resolveExpressionsWithErrors(selUrls, userData) | |
| : Promise.resolve(undefined), | |
| ]); | |
| // Flatten successful items | |
| const patterns = regexResults?.flatMap((r) => r.items); | |
| const expressions = selResults?.flatMap((r) => r.items); | |
| // Collect per-URL errors | |
| const errors: { url: string; error: string }[] = []; | |
| if (regexResults) { | |
| for (const r of regexResults) { | |
| if (r.error) errors.push({ url: r.url, error: r.error }); | |
| } | |
| } | |
| if (selResults) { | |
| for (const r of selResults) { | |
| if (r.error) errors.push({ url: r.url, error: r.error }); | |
| } | |
| } | |
| res.status(200).json( | |
| createResponse({ | |
| success: true, | |
| detail: | |
| errors.length > 0 | |
| ? `Resolved with ${errors.length} error(s)` | |
| : 'Synced items resolved successfully', | |
| data: { | |
| ...(patterns !== undefined && { patterns }), | |
| ...(expressions !== undefined && { expressions }), | |
| ...(errors.length > 0 && { errors }), | |
| }, | |
| }) | |
| ); | |
| } catch (error) { | |
| if (error instanceof APIError) { | |
| next(error); | |
| } else { | |
| logger.error(error); | |
| next(new APIError(constants.ErrorCode.INTERNAL_SERVER_ERROR)); | |
| } | |
| } | |
| }); | |
| export default router; | |