recover-all.mjs 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /**
  2. * Recovery script: deploy the original saas-voc-gateway.js to restore cloud functions.
  3. * The gateway is a single consolidated function that handles all actions via routing.
  4. */
  5. import 'dotenv/config';
  6. import { readFile } from 'node:fs/promises';
  7. import { randomUUID } from 'node:crypto';
  8. import { fileURLToPath } from 'node:url';
  9. import { dirname, resolve } from 'node:path';
  10. const required = ['PARSE_SERVER_URL', 'PARSE_APP_ID', 'PARSE_MASTER_KEY'];
  11. for (const name of required) if (!process.env[name]?.trim()) throw new Error(`${name} is required`);
  12. const registryBase = (process.env.FUNCTION_REGISTRY_SERVER_URL || process.env.PARSE_SERVER_URL).replace(/\/+$/, '');
  13. const registryAppId = process.env.FUNCTION_REGISTRY_APP_ID || process.env.PARSE_APP_ID;
  14. const registryMasterKey = process.env.FUNCTION_REGISTRY_MASTER_KEY || process.env.PARSE_MASTER_KEY;
  15. const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': registryAppId, 'X-Parse-Master-Key': registryMasterKey };
  16. const __dirname = dirname(fileURLToPath(import.meta.url));
  17. // Each ObjectId -> function name, path, description
  18. const FUNCTIONS = [
  19. { objectId: 'BzgrlznLbV', name: 'vContext', path: '/v-context', desc: 'Context & Workspace actions' },
  20. { objectId: 'Yp1RkzNmXK', name: 'vDomesticVoc', path: '/v-domestic-voc', desc: 'Domestic VOC, data-source, import, audit' },
  21. { objectId: 'Hd4FmnOpQR', name: 'vSync', path: '/v-sync', desc: 'Sync enqueue, jobs, retry, cancel' },
  22. { objectId: 'Tk7WvXyZAb', name: 'vCompetitor', path: '/v-competitor', desc: 'Competitor overview, refresh, history, alerts, tasks' },
  23. { objectId: 'Qm2BnDeFgH', name: 'vListing', path: '/v-listing', desc: 'Listing product, overview, products' },
  24. { objectId: 'Lr3CsEfGhI', name: 'vListingJob', path: '/v-listing-job', desc: 'Listing score-job, version' },
  25. { objectId: 'Nv4DtGhIjK', name: 'vAnalysis', path: '/v-analysis', desc: 'Analysis, insight-decision' },
  26. { objectId: 'Pw5EuHiJkL', name: 'vActions', path: '/v-actions', desc: 'Action, alert CRUD' },
  27. { objectId: 'Qx6FvIjKlM', name: 'vKnowledge', path: '/v-knowledge', desc: 'Knowledge products' },
  28. { objectId: 'Ry7GwJkLmN', name: 'vAI', path: '/v-ai', desc: 'AI status, prompts, chat' },
  29. { objectId: 'Sz8HxKlMnO', name: 'vUpstream', path: '/v-upstream', desc: 'Upstream Amazon, Sorftime, Tikhub, Domestic' },
  30. ];
  31. async function deployFunction(fn) {
  32. const code = await readFile(resolve(__dirname, '..', 'cloud-functions', 'saas-voc-gateway.js'), 'utf8');
  33. const url = `${registryBase}/classes/Function/${fn.objectId}`;
  34. const payload = {
  35. name: fn.name,
  36. desc: fn.desc,
  37. type: 'standalone',
  38. path: fn.path,
  39. paramList: [{ name: 'params', type: 'Object', required: true }],
  40. code,
  41. respType: 'json',
  42. respJson: { success: true, data: null, requestId: randomUUID() },
  43. isDeleted: false,
  44. };
  45. const response = await fetch(url, { method: 'PUT', headers, body: JSON.stringify(payload) });
  46. if (!response.ok) {
  47. const errorText = await response.text();
  48. throw new Error(`Deploy ${fn.name} failed: HTTP ${response.status} - ${errorText}`);
  49. }
  50. const result = await response.json();
  51. return { ok: true, objectId: result.objectId };
  52. }
  53. async function main() {
  54. console.log('Recovering all cloud functions with original gateway...\n');
  55. for (const fn of FUNCTIONS) {
  56. try {
  57. const result = await deployFunction(fn);
  58. console.log(` ✓ ${fn.name} (${fn.objectId})`);
  59. } catch (err) {
  60. console.log(` ✗ ${fn.name}: ${err.message}`);
  61. }
  62. }
  63. console.log('\nDone. Test with: POST to /api/functions with {"id":"<objectId>","params":{"action":"..."}}');
  64. }
  65. main();