// 执行真实UTS服务及页面逻辑;仅微信授权、HTTP和设备存储采用边界替身。 const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const ts = require(process.env.AIRZ_TYPESCRIPT_PATH || 'D:/Develop/HBuilderX/plugins/uniapp-uts-v1/node_modules/@dcloudio/uni-uts-v1/lib/typescript/lib/typescript.js'); const root = path.resolve(__dirname, '..'); class JsonObject { constructor(value = {}) { Object.assign(this, value); } getString(key) { return typeof this[key] === 'string' ? this[key] : null; } getNumber(key) { return typeof this[key] === 'number' ? this[key] : null; } getBoolean(key) { return typeof this[key] === 'boolean' ? this[key] : null; } } const json = value => Array.isArray(value) ? value.map(json) : value && typeof value === 'object' ? new JsonObject(Object.fromEntries(Object.entries(value).map(([k, v]) => [k, json(v)]))) : value; const hash = 'a'.repeat(64); const ticket = 'b'.repeat(64); const terms = { revisionId: '1', code: 'terms', version: '2026.10-v1', scope: 'account-terms', title: '合成用户协议', content: '合成全文', contentHash: hash, effectiveAt: '2026-10-21T00:00:00Z' }; const privacy = { ...terms, revisionId: '2', code: 'privacy', scope: 'account-privacy' }; const agreements = [terms, privacy].map((item, i) => json({ agreementCode: item.code, agreementVersion: item.version, contentHash: hash, requestId: 'synthetic_consent_' + i })); const authenticated = () => ({ status: 'authenticated', token: 'synthetic-wechat-token', userId: '7', phone: '13800000000', expiresAt: '2099-01-01T00:00:00Z', profile: { nickname: '合成用户', avatarUrl: '' }, consentsConfirmed: true }); const pending = () => ({ status: 'bind_required', bindingTicket: ticket, expiresIn: 600 }); function preprocess(source, platform) { const stack = [true]; return source.split(/\r?\n/).filter(line => { let match = line.match(/^\s*\/\/\s*#(ifdef|ifndef)\s+(.+)$/); if (match) { const found = match[2].split(/\s*\|\|\s*/).includes(platform); stack.push(stack.at(-1) && (match[1] === 'ifdef' ? found : !found)); return false; } if (/^\s*\/\/\s*#endif/.test(line)) { stack.pop(); return false; } return stack.at(-1); }).join('\n'); } function environment(platform = 'MP-WEIXIN') { let now = Date.now(); class Clock extends Date { static now() { return now; } } const state = { session: null, calls: [], saves: [], redirects: [], authorizationCalls: 0, show: null, hide: null, unload: null }; state.reply = url => { if (url === '/agreements/terms') return terms; if (url === '/agreements/privacy') return privacy; if (url === '/auth/wechat-login') return pending(); if (url === '/auth/wechat/sms-code' || url === '/auth/sms-code') return { retryAfter: 60, expiresIn: 300 }; if (url === '/auth/wechat/bind-phone') return authenticated(); throw Error('Unexpected request ' + url); }; state.authorize = options => options.success({ code: 'synthetic-wechat-code' }); class ApiError extends Error { constructor(message, status, errorCode) { super(message); this.status = status; this.errorCode = errorCode; } } state.ApiError = ApiError; const api = { API_BASE_URL: 'https://synthetic.invalid/api/v1', ApiRequestError: ApiError, getSession: () => state.session, clearSession: () => { state.session = null; }, saveSession: (token, phone, userId, expiresAt) => { state.session = json({ token, phone, userId, expiresAt }); state.saves.push(state.session); }, requestJson: async (url, method, payload) => { state.calls.push({ url, method, payload: JSON.parse(JSON.stringify(payload)) }); return json(await state.reply(url, method, payload)); } }; const watches = new Map(); const uni = { login: options => { state.authorizationCalls++; state.authorize(options); }, showToast() {}, showModal() {}, navigateTo() {}, redirectTo: ({ url }) => state.redirects.push(url), setStorageSync() {}, getStorageSync() { return null; } }; const modules = {}; function load(relative) { if (modules[relative]) return modules[relative]; const full = path.join(root, relative); assert.ok(fs.existsSync(full), '微信绑定服务尚未实现:' + relative); const exports = {}; modules[relative] = exports; run(preprocess(fs.readFileSync(full, 'utf8'), platform), relative, exports); return exports; } function dependencies(name, relative) { if (name === '@/services/api.uts' || name === './api.uts') return api; if (name === '@/services/storage.uts') return { setUserStorage() {} }; if (name === '@/services/layout.uts') return { usePageLayout: () => ({ pageStyle() {}, contentStyle() {}, statusStyle() {} }) }; if (name === '@/services/launch.uts') return { consumeInitialLaunch() {} }; if (name.endsWith('.uvue')) return {}; return load(name.startsWith('@/') ? name.slice(2) : path.posix.normalize(path.posix.join(path.posix.dirname(relative), name))); } function run(source, relative, exports) { const code = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 } }).outputText; vm.runInNewContext(code, { exports, require: name => dependencies(name, relative), UTSJSONObject: JsonObject, Date: Clock, Error, Math, Number, uni, ref: value => { const item = {}; Object.defineProperty(item, 'value', { get: () => value, set: next => { value = next; watches.get(item)?.(); } }); return item; }, computed: fn => ({ get value() { return fn(); } }), watch: (item, fn) => watches.set(item, fn), onLoad() {}, onShow: fn => { state.show = fn; }, onHide: fn => { state.hide = fn; }, onUnload: fn => { state.unload = fn; }, onUnmounted() {}, setInterval: () => 1, clearInterval() {} }, { filename: relative }); } state.load = load; state.advance = ms => { now += ms; }; state.page = () => { const relative = 'packages/account/login/login.uvue'; const source = fs.readFileSync(path.join(root, relative), 'utf8').match(/