| 123456789101112131415161718192021 |
- import 'dotenv/config';
- import { z } from 'zod';
- import { ParseRestClient } from '../src/db/parse-rest.client.js';
- import { VOC_PARSE_CLASSES } from '../src/db/parse-rest.schema.js';
- import type { ListingScoreJob, ListingScoreJobItem, ListingScoreResult, ListingSourceSnapshot } from '../src/modules/listing-ai/domain.js';
- interface Stored<T>{workspaceId:string;productId?:string;jobId?:string;idempotencyKey?:string;payload:T}
- async function main(){const env=z.object({PARSE_SERVER_URL:z.url(),PARSE_APP_ID:z.string().min(1),PARSE_MASTER_KEY:z.string().min(1),SAAS_DEFAULT_WORKSPACE_ID:z.string().default('demashi')}).parse(process.env);const client=new ParseRestClient({serverUrl:env.PARSE_SERVER_URL,appId:env.PARSE_APP_ID,masterKey:env.PARSE_MASTER_KEY});const workspaceId=env.SAAS_DEFAULT_WORKSPACE_ID;
- const [sourceRows,resultRows,itemRows,jobRows]=await Promise.all([
- client.findAll<Stored<ListingSourceSnapshot>>(VOC_PARSE_CLASSES.listingSourceSnapshot,{workspaceId}),
- client.findAll<Stored<ListingScoreResult>>(VOC_PARSE_CLASSES.listingScoreResult,{workspaceId}),
- client.findAll<Stored<ListingScoreJobItem>>(VOC_PARSE_CLASSES.listingScoreItem,{workspaceId}),
- client.findAll<Stored<ListingScoreJob>&{idempotencyKey:string}>(VOC_PARSE_CLASSES.listingScoreJob,{workspaceId}),
- ]);
- const latestSources=new Map<string,ListingSourceSnapshot>();for(const row of sourceRows){const value=row.payload;const current=latestSources.get(value.productId);if(!current||value.syncedAt>current.syncedAt)latestSources.set(value.productId,value);}
- const latestResults=new Map<string,ListingScoreResult>();for(const row of resultRows){const value=row.payload;const current=latestResults.get(value.productId);if(!current||value.createdAt>current.createdAt)latestResults.set(value.productId,value);}
- const orphanResults=[...latestResults.values()].filter((result)=>!latestSources.has(result.productId));const missingResults=[...latestSources.values()].filter((source)=>!latestResults.has(source.productId));const invalidDimensions=[...latestResults.values()].filter((result)=>result.dimensions.length!==5);const staleResults=[...latestResults.values()].filter((result)=>latestSources.get(result.productId)?.sourceHash!==result.sourceHash);const scores=[...latestResults.values()].map((result)=>result.overallScore).filter((value):value is number=>value!==null);const job=jobRows.map((row)=>row.payload).sort((a,b)=>b.requestedAt.localeCompare(a.requestedAt))[0]??null;const jobItems=job?itemRows.map((row)=>row.payload).filter((item)=>item.jobId===job.id):[];
- const dimensionUnavailable=Object.fromEntries(['title','selling_points','images','description','specifications'].map((dimension)=>[dimension,[...latestResults.values()].filter((result)=>result.dimensions.find((item)=>item.dimension===dimension)?.score===null).length]));
- const report={workspaceId,sources:latestSources.size,results:latestResults.size,scored:scores.length,partialResults:latestResults.size-scores.length,blocked:[...latestResults.values()].filter((result)=>result.coverage.status==='blocked').length,averageScore:scores.length?Math.round(scores.reduce((sum,value)=>sum+value,0)/scores.length*10)/10:null,dimensionUnavailable,missingResults:missingResults.length,orphanResults:orphanResults.length,staleResults:staleResults.length,invalidDimensions:invalidDimensions.length,latestJob:job?{id:job.id,status:job.status,total:job.total,processed:job.processed,succeeded:job.succeeded,partial:job.partial,blocked:job.blocked,failed:job.failed}:null,latestJobItems:jobItems.length};console.log(JSON.stringify(report,null,2));if(missingResults.length||orphanResults.length||staleResults.length||invalidDimensions.length||!job||job.processed!==job.total)process.exitCode=2;
- }
- main().catch((error)=>{console.error(`[verify-listing-rollout] ${error instanceof Error?error.message:error}`);process.exitCode=1;});
|