| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- import 'dotenv/config';
- import { readFile } from 'node:fs/promises';
- import { randomUUID } from 'node:crypto';
- import { fileURLToPath } from 'node:url';
- import { dirname, resolve } from 'node:path';
- const required = ['PARSE_SERVER_URL', 'PARSE_APP_ID', 'PARSE_MASTER_KEY'];
- for (const name of required) if (!process.env[name]?.trim()) throw new Error(`${name} is required`);
- const registryBase = (process.env.FUNCTION_REGISTRY_SERVER_URL || process.env.PARSE_SERVER_URL).replace(/\/+$/, '');
- const registryAppId = process.env.FUNCTION_REGISTRY_APP_ID || process.env.PARSE_APP_ID;
- const registryMasterKey = process.env.FUNCTION_REGISTRY_MASTER_KEY || process.env.PARSE_MASTER_KEY;
- const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': registryAppId, 'X-Parse-Master-Key': registryMasterKey };
- const __dirname = dirname(fileURLToPath(import.meta.url));
- const cloudFunctionsDir = resolve(__dirname, '..', 'cloud-functions');
- // Cloud function definitions
- const CLOUD_FUNCTIONS = [
- { name: 'vContext', path: '/v-context', file: 'vContext.js', desc: 'SaaS VOC context and workspace management' },
- { name: 'vDomesticVoc', path: '/v-domestic-voc', file: 'vDomesticVoc.js', desc: 'SaaS VOC domestic VOC data' },
- { name: 'vSync', path: '/v-sync', file: 'vSync.js', desc: 'SaaS VOC sync job management' },
- { name: 'vCompetitor', path: '/v-competitor', file: 'vCompetitor.js', desc: 'SaaS VOC competitor monitor' },
- { name: 'vListing', path: '/v-listing', file: 'vListing.js', desc: 'SaaS VOC listing scores' },
- { name: 'vListingJob', path: '/v-listing-job', file: 'vListingJob.js', desc: 'SaaS VOC listing score jobs' },
- { name: 'vAnalysis', path: '/v-analysis', file: 'vAnalysis.js', desc: 'SaaS VOC analysis and insights' },
- { name: 'vActions', path: '/v-actions', file: 'vActions.js', desc: 'SaaS VOC actions and alerts' },
- { name: 'vKnowledge', path: '/v-knowledge', file: 'vKnowledge.js', desc: 'SaaS VOC product knowledge' },
- { name: 'vAI', path: '/v-ai', file: 'vAI.js', desc: 'SaaS VOC AI gateway' },
- { name: 'vUpstream', path: '/v-upstream', file: 'vUpstream.js', desc: 'SaaS VOC upstream API proxy' },
- ];
- async function deployFunction(func) {
- const filePath = resolve(cloudFunctionsDir, func.file);
- const code = await readFile(filePath, 'utf8');
- const query = new URL(`${registryBase}/classes/Function`);
- query.searchParams.set('where', JSON.stringify({ path: func.path }));
- const existingResponse = await fetch(query, { headers });
- if (!existingResponse.ok) throw new Error(`Function lookup failed for ${func.name}: HTTP ${existingResponse.status}`);
- const existing = await existingResponse.json();
- const payload = {
- name: func.name,
- desc: func.desc,
- type: 'standalone',
- path: func.path,
- paramList: [{ name: 'params', type: 'Object', required: true }],
- code,
- respType: 'json',
- respJson: { success: true, data: null, requestId: randomUUID() },
- isDeleted: false,
- };
- const target = existing.results?.[0];
- const url = target
- ? `${registryBase}/classes/Function/${target.objectId}`
- : `${registryBase}/classes/Function`;
- const method = target ? 'PUT' : 'POST';
- const response = await fetch(url, {
- method,
- headers,
- body: JSON.stringify(payload),
- });
- if (!response.ok) {
- const errorText = await response.text();
- throw new Error(`Function deployment failed for ${func.name}: HTTP ${response.status} - ${errorText}`);
- }
- const result = await response.json();
- return {
- ok: true,
- name: func.name,
- path: func.path,
- objectId: target?.objectId || result.objectId,
- action: target ? 'updated' : 'created',
- };
- }
- async function main() {
- console.log(`Deploying ${CLOUD_FUNCTIONS.length} cloud functions...`);
- const results = [];
- for (const func of CLOUD_FUNCTIONS) {
- try {
- const result = await deployFunction(func);
- console.log(`✓ ${result.name} (${result.action}): ${result.objectId}`);
- results.push(result);
- } catch (error) {
- console.error(`✗ ${func.name}: ${error.message}`);
- results.push({ ok: false, name: func.name, error: error.message });
- }
- }
- const failed = results.filter((r) => !r.ok);
- if (failed.length > 0) {
- console.error(`\n${failed.length} function(s) failed to deploy`);
- process.exit(1);
- }
- console.log(`\nAll ${results.length} cloud functions deployed successfully!`);
- console.log(`\nCloud function paths:`);
- results.forEach((r) => console.log(` ${r.name}: ${r.path}`));
- }
- main().catch((error) => {
- console.error('Deployment failed:', error);
- process.exitCode = 1;
- });
|