import fs from 'node:fs'; import path from 'node:path'; import {fileURLToPath} from 'node:url'; export const ROOT=path.dirname(path.dirname(fileURLToPath(import.meta.url))); const configPath=process.env.KSF_CONNECTION_CONFIG||'F:/文档/正式环境连接配置.txt'; const cfg={};for(const line of fs.readFileSync(configPath,'utf8').split(/\r?\n/)){const m=line.match(/^\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|/);if(m)cfg[m[1].trim()]=m[2].trim().replace(/^`|`$/g,'');} if(cfg.appId!=='FKieRbIoGt_main'||!cfg.masterKey)throw Error('配置缺失或不是目标应用'); export const appId=cfg.appId; export const parseUrl=cfg['Parse 端点'].replace(/\/$/,''); export const functionsUrl=cfg['云函数 URL'].replace(/\/$/,''); if(new URL(parseUrl).origin!=='https://kangshifu.fmode.cn'||new URL(functionsUrl).origin!=='https://kangshifu.fmode.cn')throw Error('部署目标不匹配'); export const adminHeaders={'X-Parse-Application-Id':cfg.appId,'X-Parse-Master-Key':cfg.masterKey,'Content-Type':'application/json'}; export const redact=s=>String(s).split(cfg.masterKey).join('[REDACTED]'); export async function request(method,route,body){const res=await fetch(parseUrl+route,{method,headers:adminHeaders,body:body===undefined?undefined:JSON.stringify(body),signal:AbortSignal.timeout(45000),redirect:'error'});const j=await res.json().catch(()=>({}));if(!res.ok)throw Error(redact(method+' '+route+' HTTP '+res.status+' '+JSON.stringify(j)));return j;} export async function invoke(name,params={},headers=adminHeaders){const res=await fetch(functionsUrl,{method:'POST',headers,body:JSON.stringify({path:'/'+name,params}),signal:AbortSignal.timeout(45000),redirect:'error'});return{http:res.status,body:await res.json().catch(()=>({}))};} export function evidence(name,value){fs.writeFileSync(path.join(ROOT,'evidence',name),JSON.stringify(value,null,2));} export async function classRows(name,where={}){return(await request('GET','/classes/'+name+'?'+new URLSearchParams({where:JSON.stringify(where),limit:'1000'}))).results;}