verify-parse-rest.ts 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import 'dotenv/config';
  2. import { loadConfig } from '../src/config/env.js';
  3. import { ParseRestClient } from '../src/db/parse-rest.client.js';
  4. import { requiredVocClassNames, VOC_PARSE_CLASSES } from '../src/db/parse-rest.schema.js';
  5. const config = loadConfig();
  6. if (config.storageDriver !== 'parse_rest') throw new Error('STORAGE_DRIVER must be parse_rest');
  7. const workspaceId = process.argv[2] || config.auth.defaultWorkspaceId;
  8. const platform = process.argv[3] || 'jd';
  9. const client = new ParseRestClient({
  10. serverUrl: config.parse.serverUrl,
  11. appId: config.parse.appId,
  12. masterKey: config.parse.masterKey,
  13. timeoutMs: config.parse.timeoutMs,
  14. });
  15. const schemaResponse = await client.request<{
  16. results: Array<{
  17. className: string;
  18. classLevelPermissions?: Record<string, Record<string, unknown>>;
  19. }>;
  20. }>('/schemas');
  21. const vocSchemas = schemaResponse.results.filter((schema) => requiredVocClassNames.includes(schema.className));
  22. const operations = ['find', 'get', 'count', 'create', 'update', 'delete', 'addField'];
  23. const masterOnly = vocSchemas.every((schema) => operations.every((operation) => (
  24. Object.keys(schema.classLevelPermissions?.[operation] ?? {}).length === 0
  25. )));
  26. const where = { workspaceId, platform };
  27. const [ownProducts, competitorProducts, competitorDetailsReady, metrics, relations, reviews, workspace, completedImport] = await Promise.all([
  28. client.count(VOC_PARSE_CLASSES.product, { ...where, role: 'own' }),
  29. client.count(VOC_PARSE_CLASSES.product, { ...where, role: 'competitor' }),
  30. client.count(VOC_PARSE_CLASSES.product, { ...where, role: 'competitor', source: 'fmode_gateway' }),
  31. client.count(VOC_PARSE_CLASSES.dailyMetric, where),
  32. client.count(VOC_PARSE_CLASSES.productRelation, where),
  33. client.count(VOC_PARSE_CLASSES.review, where),
  34. client.findOne(VOC_PARSE_CLASSES.workspace, { publicId: workspaceId, status: 'active' }),
  35. client.findOne(VOC_PARSE_CLASSES.importBatch, { workspaceId, platform, status: 'completed' }),
  36. ]);
  37. const publicResponse = await fetch(
  38. `${config.parse.serverUrl.replace(/\/+$/, '')}/classes/${VOC_PARSE_CLASSES.workspace}?limit=1`,
  39. {
  40. headers: { 'X-Parse-Application-Id': config.parse.appId },
  41. signal: AbortSignal.timeout(config.parse.timeoutMs),
  42. },
  43. );
  44. const publicPayload = await publicResponse.json().catch(() => ({})) as { code?: number };
  45. console.log(JSON.stringify({
  46. schemas: {
  47. expected: requiredVocClassNames.length,
  48. actual: vocSchemas.length,
  49. masterOnly,
  50. },
  51. workspaceReady: Boolean(workspace),
  52. completedImport: Boolean(completedImport),
  53. counts: {
  54. ownProducts,
  55. competitorProducts,
  56. competitorDetailsReady,
  57. competitorDetailsPending: competitorProducts - competitorDetailsReady,
  58. products: ownProducts + competitorProducts,
  59. metrics,
  60. relations,
  61. reviews,
  62. },
  63. publicReadBlocked: !publicResponse.ok,
  64. publicReadStatus: publicResponse.status,
  65. publicReadCode: publicPayload.code ?? null,
  66. }, null, 2));