xiaoshu-runtime-compat.mjs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. // The multi-app worker provides a deliberately small REST facade, not the Parse SDK.
  2. // Adapt only Xiaoshu gateway-local bindings inside its own isolated worker.
  3. export async function resolveXiaoshuRuntime(nativeParse, nativePsql, request, loadEnvironment) {
  4. if (typeof nativeParse.User === 'function' && typeof nativePsql.tx === 'function') {
  5. return { Parse: nativeParse, Psql: nativePsql };
  6. }
  7. const load = loadEnvironment || (async () => {
  8. const { workerData } = await import('node:worker_threads');
  9. const { createRequire } = await import('node:module');
  10. const require = createRequire('/opt/future-server/package.json');
  11. const SDK = require('parse/node');
  12. const coreModule = require('parse/lib/node/CoreManager.js');
  13. return { SDK, CoreManager: coreModule.default || coreModule, workerData };
  14. });
  15. const { SDK, CoreManager, workerData } = await load();
  16. const db = nativePsql.db;
  17. if (workerData?.companyId !== '7pIbDBJmKx' || workerData.config?.appId !== '7pIbDBJmKx_main'
  18. || nativeParse.applicationId !== workerData.config.appId
  19. || !nativeParse.masterKey || nativeParse.masterKey !== workerData.config.masterKey
  20. || typeof workerData.token !== 'string' || !workerData.token
  21. || !/^http:\/\/127\.0\.0\.1:\d+\/data\/?$/.test(nativeParse.serverURL)
  22. || typeof db?.tx !== 'function') {
  23. throw new Error('Unsupported Xiaoshu isolated runtime');
  24. }
  25. // One tenant per worker thread; these SDK settings never cross tenant workers.
  26. SDK.initialize(nativeParse.applicationId, undefined, nativeParse.masterKey);
  27. SDK.serverURL = nativeParse.serverURL;
  28. CoreManager.set('REQUEST_HEADERS', { 'x-fmode-worker-token': workerData.token });
  29. CoreManager.set('REQUEST_ATTEMPT_LIMIT', 1);
  30. for (const [field, className] of [['user', '_User'], ['company', 'Company'], ['account', 'Account']]) {
  31. const value = request[field];
  32. if (!value) continue;
  33. const json = typeof value.toJSON === 'function' ? value.toJSON() : value;
  34. if (!json.objectId) throw new Error('Invalid Xiaoshu runtime identity');
  35. request[field] = SDK.Object.fromJSON({ ...json, className });
  36. }
  37. return { Parse: SDK, Psql: db };
  38. }
  39. export function withXiaoshuRuntime(code) {
  40. const marker = '// XIAOSHU_ISOLATED_RUNTIME_COMPAT_V1';
  41. if (code.includes(marker)) return code;
  42. const pattern = /async function handler\s*\(/g;
  43. if ([...code.matchAll(pattern)].length !== 1) throw new Error('Expected exactly one async handler');
  44. return code.replace(pattern, 'async function xiaoshuBusinessHandler(') + '\n' + marker + '\n'
  45. + resolveXiaoshuRuntime.toString() + `
  46. async function handler(request, response) {
  47. try {
  48. const runtime = await resolveXiaoshuRuntime(Parse, Psql, request);
  49. Parse = runtime.Parse;
  50. Psql = runtime.Psql;
  51. } catch (error) {
  52. console.error('[XiaoshuRuntime] ' + String(error?.message || error));
  53. return response.status(503).json({ success: false, error: 'runtime_compatibility_error', message: '小树服务暂时不可用,请稍后重试', retcode: -1, retmsg: '小树服务暂时不可用,请稍后重试', result: null });
  54. }
  55. return xiaoshuBusinessHandler(request, response);
  56. }
  57. `;
  58. }