- {typeof externalDecimals === 'number' && (
-
+ {typeof resolvedExternalDecimals === 'number' && (
+
+ {t('forge.decimalsHint', { decimals: resolvedExternalDecimals })}
+ {usingFallbackDecimals ? ` (${t('forge.decimalsFallback')})` : null}
+
)}
{contractDisplay && (
diff --git a/miniapps/forge/src/api/schemas.ts b/miniapps/forge/src/api/schemas.ts
index d7c580aba..66f9a48a3 100644
--- a/miniapps/forge/src/api/schemas.ts
+++ b/miniapps/forge/src/api/schemas.ts
@@ -12,7 +12,7 @@ const externalAssetInfoItemSchema = z.object({
depositAddress: z.string(),
assetType: z.string(),
logo: z.string().optional(),
- decimals: z.number().optional(),
+ decimals: z.coerce.number().optional(),
}).passthrough()
const redemptionConfigSchema = z.object({
diff --git a/miniapps/forge/src/i18n/locales/en.json b/miniapps/forge/src/i18n/locales/en.json
index 6e55b75bc..e4ab0299d 100644
--- a/miniapps/forge/src/i18n/locales/en.json
+++ b/miniapps/forge/src/i18n/locales/en.json
@@ -25,6 +25,7 @@
"continue": "Continue",
"amountHint": "Amount is in {{symbol}}",
"decimalsHint": "Token decimals: {{decimals}}",
+ "decimalsFallback": "default",
"contractHint": "Contract: {{address}}"
},
"redemption": {
@@ -75,6 +76,7 @@
"sdkNotInit": "Bio SDK not initialized",
"connectionFailed": "Connection failed",
"invalidAmount": "Please enter a valid amount",
+ "missingDecimals": "Missing token decimals configuration",
"forgeFailed": "Operation failed"
},
"picker": {
diff --git a/miniapps/forge/src/i18n/locales/zh-CN.json b/miniapps/forge/src/i18n/locales/zh-CN.json
index aaa2789e3..3661545c8 100644
--- a/miniapps/forge/src/i18n/locales/zh-CN.json
+++ b/miniapps/forge/src/i18n/locales/zh-CN.json
@@ -25,6 +25,7 @@
"continue": "继续",
"amountHint": "数量单位:{{symbol}}",
"decimalsHint": "精度:{{decimals}} 位",
+ "decimalsFallback": "默认",
"contractHint": "合约:{{address}}"
},
"redemption": {
@@ -75,6 +76,7 @@
"sdkNotInit": "Bio SDK 未初始化",
"connectionFailed": "连接失败",
"invalidAmount": "请输入有效金额",
+ "missingDecimals": "缺少资产精度配置",
"forgeFailed": "操作失败"
},
"picker": {
diff --git a/miniapps/forge/src/i18n/locales/zh-TW.json b/miniapps/forge/src/i18n/locales/zh-TW.json
index 744f5d7bc..b90475f4b 100644
--- a/miniapps/forge/src/i18n/locales/zh-TW.json
+++ b/miniapps/forge/src/i18n/locales/zh-TW.json
@@ -25,6 +25,7 @@
"continue": "繼續",
"amountHint": "數量單位:{{symbol}}",
"decimalsHint": "精度:{{decimals}} 位",
+ "decimalsFallback": "預設",
"contractHint": "合約:{{address}}"
},
"redemption": {
@@ -75,6 +76,7 @@
"sdkNotInit": "Bio SDK 未初始化",
"connectionFailed": "連接失敗",
"invalidAmount": "請輸入有效金額",
+ "missingDecimals": "缺少資產精度配置",
"forgeFailed": "操作失敗"
},
"picker": {
diff --git a/miniapps/forge/src/i18n/locales/zh.json b/miniapps/forge/src/i18n/locales/zh.json
index aaa2789e3..3661545c8 100644
--- a/miniapps/forge/src/i18n/locales/zh.json
+++ b/miniapps/forge/src/i18n/locales/zh.json
@@ -25,6 +25,7 @@
"continue": "继续",
"amountHint": "数量单位:{{symbol}}",
"decimalsHint": "精度:{{decimals}} 位",
+ "decimalsFallback": "默认",
"contractHint": "合约:{{address}}"
},
"redemption": {
@@ -75,6 +76,7 @@
"sdkNotInit": "Bio SDK 未初始化",
"connectionFailed": "连接失败",
"invalidAmount": "请输入有效金额",
+ "missingDecimals": "缺少资产精度配置",
"forgeFailed": "操作失败"
},
"picker": {
diff --git a/miniapps/teleport/src/components/AuroraBackground.tsx b/miniapps/teleport/src/components/AuroraBackground.tsx
index f12be2902..b7caa3715 100644
--- a/miniapps/teleport/src/components/AuroraBackground.tsx
+++ b/miniapps/teleport/src/components/AuroraBackground.tsx
@@ -14,7 +14,7 @@ export const AuroraBackground = ({
...props
}: AuroraBackgroundProps) => {
return (
-
+
);
};
diff --git a/package.json b/package.json
index 8d9ac0b3c..e56b702f1 100644
--- a/package.json
+++ b/package.json
@@ -92,6 +92,7 @@
"@noble/hashes": "^2.0.1",
"@noble/secp256k1": "^3.0.0",
"@number-flow/react": "^0.5.10",
+ "@plaoc/is-dweb": "^0.1.2",
"@plaoc/plugins": "^1.1.9",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-dialog": "^1.1.15",
@@ -143,8 +144,8 @@
"@axe-core/playwright": "^4.11.0",
"@biochain/e2e-tools": "workspace:*",
"@inquirer/prompts": "^8.0.2",
- "@playwright/test": "^1.57.0",
"@plaoc/cli": "^1.2.2",
+ "@playwright/test": "^1.57.0",
"@storybook/addon-docs": "^10.1.4",
"@storybook/addon-vitest": "^10.1.4",
"@storybook/react": "^10.1.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d786e330b..34675ab56 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -77,6 +77,9 @@ importers:
'@number-flow/react':
specifier: ^0.5.10
version: 0.5.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ '@plaoc/is-dweb':
+ specifier: ^0.1.2
+ version: 0.1.2
'@plaoc/plugins':
specifier: ^1.1.9
version: 1.1.9(typescript@5.9.3)
@@ -1626,6 +1629,9 @@ packages:
'@dweb-browser/js-process@0.4.7':
resolution: {integrity: sha512-XUBSPxcgpKjjEibIo1f7f5RWH4VqYW9M4RunUSVIsI64ENk4FjG7AjeD27FBikwbuku+rmTWzgH3wQyNDDnEyg==}
+ '@dweb-browser/polyfill@0.0.8':
+ resolution: {integrity: sha512-OhjyCJiaOKFTmUoRBugn+bcmjZqKSek6WesB/2vASnPMTODpyqKLQ6uUguGuYb9mAC64lwi0P7eoCJmRyzQ6Jw==}
+
'@dweb-browser/polyfill@0.0.9':
resolution: {integrity: sha512-1siZWAvzXMVZ5z6TmFPCSYXHTNTu5qmZv5UR0QSlujXuQr93I+BX6bhyu2FG4pCqqkoE3OAVlQ15D9Nj+beS4g==}
@@ -2877,6 +2883,9 @@ packages:
resolution: {integrity: sha512-4txWq8sytf6HCNt+ryWJzjhXVtNMrckdO/sBb2Xd3MbHPBMo1rvRIvVy0FCkPHe8cODF60SF9W/tovAFyYSuVw==}
hasBin: true
+ '@plaoc/is-dweb@0.1.2':
+ resolution: {integrity: sha512-H2QdJVjOVhnE75mTq5vQQYVLZzqDFHoPUVtMnJRGpFCgjkTA36mswo3St9kxnAZlAMJziDckMbu6+/1daXn87Q==}
+
'@plaoc/plugins@1.1.9':
resolution: {integrity: sha512-TnFNddIYsX0myjhhNVRR+HZS415CPnw0Xe4ipyP0ICUm94dleGZodJTDAPkgsKZi085gI7dlSXp8hYsNI3TIhw==}
@@ -9537,6 +9546,8 @@ snapshots:
transitivePeerDependencies:
- typescript
+ '@dweb-browser/polyfill@0.0.8': {}
+
'@dweb-browser/polyfill@0.0.9': {}
'@dweb-browser/svg-wasm@0.9.0': {}
@@ -10788,6 +10799,10 @@ snapshots:
- typescript
- utf-8-validate
+ '@plaoc/is-dweb@0.1.2':
+ dependencies:
+ '@dweb-browser/polyfill': 0.0.8
+
'@plaoc/plugins@1.1.9(typescript@5.9.3)':
dependencies:
'@dweb-browser/core': 0.1.4(typescript@5.9.3)
diff --git a/scripts/vite-plugin-miniapps.ts b/scripts/vite-plugin-miniapps.ts
index 004ac75c0..28d81e83c 100644
--- a/scripts/vite-plugin-miniapps.ts
+++ b/scripts/vite-plugin-miniapps.ts
@@ -7,10 +7,13 @@
*/
import { createServer, build as viteBuild, type Plugin, type ViteDevServer } from 'vite';
-import { resolve, join } from 'node:path';
+import type { IncomingMessage, ServerResponse } from 'node:http';
+import { resolve, join, basename } from 'node:path';
import { readdirSync, existsSync, readFileSync, writeFileSync, mkdirSync, cpSync } from 'node:fs';
import detectPort from 'detect-port';
import https from 'node:https';
+import type { RollupWatcher } from 'rollup';
+import sirv from 'sirv';
import { getRemoteMiniappsForEcosystem, type RemoteMiniappConfig } from './vite-plugin-remote-miniapps';
import type { WujieRuntimeConfig } from '../src/services/ecosystem/types';
@@ -23,6 +26,8 @@ interface MiniappRuntimeConfig {
build?: MiniappRuntime | { runtime: MiniappRuntime; wujieConfig?: WujieRuntimeConfig };
}
+type MiniappDevMode = 'proxy' | 'build';
+
function parseRuntimeConfig(config?: MiniappRuntime | { runtime: MiniappRuntime; wujieConfig?: WujieRuntimeConfig }): {
runtime: MiniappRuntime;
wujieConfig?: WujieRuntimeConfig;
@@ -69,23 +74,27 @@ interface MiniappServer {
dirName: string;
port: number;
server: ViteDevServer;
- baseUrl: string;
}
interface MiniappsPluginOptions {
miniappsDir?: string;
apps?: Record;
remoteMiniapps?: RemoteMiniappConfig[];
+ devMode?: MiniappDevMode;
}
// ==================== Plugin ====================
export function miniappsPlugin(options: MiniappsPluginOptions = {}): Plugin {
- const { miniappsDir = 'miniapps', apps = {}, remoteMiniapps = [] } = options;
+ const { miniappsDir = 'miniapps', apps = {}, remoteMiniapps = [], devMode } = options;
+ const resolvedDevMode: MiniappDevMode =
+ devMode ?? (process.env.MINIAPPS_DEV_MODE === 'build' ? 'build' : 'proxy');
let root: string;
let isBuild = false;
const miniappServers: MiniappServer[] = [];
+ const miniappBuildWatchers: RollupWatcher[] = [];
+ let miniappsDevDistDir: string | null = null;
return {
name: 'vite-plugin-miniapps',
@@ -112,6 +121,85 @@ export function miniappsPlugin(options: MiniappsPluginOptions = {}): Plugin {
const miniappsPath = resolve(root, miniappsDir);
const manifests = scanMiniapps(miniappsPath);
+ if (resolvedDevMode === 'build') {
+ miniappsDevDistDir = resolve(root, 'public', 'miniapps');
+ mkdirSync(miniappsDevDistDir, { recursive: true });
+
+ await Promise.all(
+ manifests.map(async (manifest) => {
+ const miniappPath = join(miniappsPath, manifest.dirName);
+ const outputDir = resolve(miniappsDevDistDir!, manifest.dirName);
+ const result = await viteBuild({
+ root: miniappPath,
+ configFile: join(miniappPath, 'vite.config.ts'),
+ base: './',
+ build: {
+ outDir: outputDir,
+ emptyOutDir: true,
+ watch: {},
+ minify: false,
+ sourcemap: true,
+ },
+ logLevel: 'warn',
+ });
+
+ if (result && typeof (result as RollupWatcher).on === 'function') {
+ miniappBuildWatchers.push(result as RollupWatcher);
+ }
+
+ console.log(`[miniapps] ${manifest.name} built (watch mode)`);
+ }),
+ );
+
+ server.middlewares.use(
+ '/miniapps',
+ sirv(miniappsDevDistDir, {
+ dev: true,
+ single: false,
+ }),
+ );
+
+ const localApps = manifests.map((manifest) => {
+ const appConfig = apps[manifest.id];
+ const { runtime, wujieConfig } = parseRuntimeConfig(appConfig?.server);
+ return {
+ ...manifest,
+ dirName: manifest.dirName,
+ icon: resolveMiniappDevAsset(manifest.icon, manifest.dirName),
+ url: `/miniapps/${manifest.dirName}/`,
+ screenshots: manifest.screenshots.map((sc) => resolveMiniappDevAsset(sc, manifest.dirName)),
+ runtime,
+ wujieConfig,
+ };
+ });
+
+ const remoteApps = getRemoteMiniappsForEcosystem();
+ const ecosystemData: EcosystemJson = {
+ name: 'Bio 官方生态',
+ version: '1.0.0',
+ updated: new Date().toISOString().split('T')[0],
+ icon: '/logos/logo-256.webp',
+ apps: [...localApps, ...remoteApps],
+ };
+ const ecosystemCache = JSON.stringify(ecosystemData, null, 2);
+
+ server.middlewares.use((req, res, next) => {
+ if (req.url === '/miniapps/ecosystem.json') {
+ res.setHeader('Content-Type', 'application/json');
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.end(ecosystemCache);
+ return;
+ }
+ next();
+ });
+
+ const cleanup = async () => {
+ await Promise.all(miniappBuildWatchers.map((watcher) => watcher.close()));
+ };
+ server.httpServer?.on('close', cleanup);
+ return;
+ }
+
// 预分配端口
const portAssignments: Array<{ manifest: MiniappManifest; port: number }> = [];
for (const manifest of manifests) {
@@ -130,13 +218,38 @@ export function miniappsPlugin(options: MiniappsPluginOptions = {}): Plugin {
dirName: manifest.dirName,
port,
server: miniappServer,
- baseUrl: `https://localhost:${port}`,
});
console.log(`[miniapps] ${manifest.name} (${manifest.id}) started at https://localhost:${port}`);
}),
);
+ // 同源代理:/miniapps/{dirName}/ -> miniapp dev server
+ const proxyRoutes: Array<{ prefix: string; miniapp: MiniappServer }> = [];
+ for (const miniapp of miniappServers) {
+ proxyRoutes.push({ prefix: `/miniapps/${miniapp.dirName}`, miniapp });
+ }
+ const proxyMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => {
+ const url = req.url ?? '';
+ for (const route of proxyRoutes) {
+ if (url === route.prefix) {
+ res.statusCode = 302;
+ res.setHeader('Location', `${route.prefix}/`);
+ res.end();
+ return;
+ }
+ if (!url.startsWith(`${route.prefix}/`)) {
+ continue;
+ }
+ const nextUrl = url.slice(route.prefix.length) || '/';
+ void proxyMiniappRequest(req, res, route, nextUrl).catch(next);
+ return;
+ }
+ next();
+ };
+
+ prependMiddleware(server, proxyMiddleware);
+
// 等待所有 miniapp 启动后,fetch 各自的 /manifest.json 生成 ecosystem
const generateEcosystem = async (): Promise => {
const localApps = await Promise.all(
@@ -148,9 +261,9 @@ export function miniappsPlugin(options: MiniappsPluginOptions = {}): Plugin {
return {
...manifest,
dirName: s.dirName,
- icon: new URL(manifest.icon, s.baseUrl).href,
- url: new URL('/', s.baseUrl).href,
- screenshots: manifest.screenshots.map((sc) => new URL(sc, s.baseUrl).href),
+ icon: resolveMiniappDevAsset(manifest.icon, s.dirName),
+ url: `/miniapps/${s.dirName}/`,
+ screenshots: manifest.screenshots.map((sc) => resolveMiniappDevAsset(sc, s.dirName)),
runtime,
wujieConfig,
};
@@ -197,6 +310,7 @@ export function miniappsPlugin(options: MiniappsPluginOptions = {}): Plugin {
async closeBundle() {
await Promise.all(miniappServers.map((s) => s.server.close()));
+ await Promise.all(miniappBuildWatchers.map((watcher) => watcher.close()));
},
};
}
@@ -280,6 +394,184 @@ function scanScreenshots(root: string, shortId: string): string[] {
.map((f) => `screenshots/${f}`);
}
+function resolveMiniappDevAsset(path: string, dirName: string): string {
+ if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('data:')) {
+ return path;
+ }
+ const normalized = path.replace(/^\.\//, '').replace(/^\//, '');
+ return `/miniapps/${dirName}/${normalized}`;
+}
+
+function getRewriteMode(url: string, req: IncomingMessage): 'html' | 'js' | null {
+ const accept = req.headers.accept ?? '';
+ const path = url.split('?', 1)[0] ?? '';
+
+ if (path.endsWith('/') || path.endsWith('.html') || accept.includes('text/html')) {
+ return 'html';
+ }
+
+ if (
+ path.includes('/@') ||
+ path.includes('/@id/') ||
+ path.endsWith('.js') ||
+ path.endsWith('.ts') ||
+ path.endsWith('.tsx') ||
+ path.endsWith('.jsx')
+ ) {
+ return 'js';
+ }
+
+ return null;
+}
+
+function rewriteMiniappBody(body: string, prefix: string): string {
+ const replacements: Array<[RegExp, string]> = [
+ [/(['"])\/@/g, `$1${prefix}/@`],
+ [/(['"])\/@id\//g, `$1${prefix}/@id/`],
+ [/(['"])\/src\//g, `$1${prefix}/src/`],
+ [/(['"])\/node_modules\//g, `$1${prefix}/node_modules/`],
+ [/(['"])\/@fs\//g, `$1${prefix}/@fs/`],
+ ];
+
+ let output = body;
+ for (const [pattern, replacement] of replacements) {
+ output = output.replace(pattern, replacement);
+ }
+ return output;
+}
+
+async function proxyMiniappRequest(
+ req: IncomingMessage,
+ res: ServerResponse,
+ route: { prefix: string; miniapp: MiniappServer },
+ nextUrl: string,
+): Promise {
+ const rewriteMode = getRewriteMode(`${route.prefix}${nextUrl}`, req);
+ const body = await readRequestBody(req);
+ const headers = buildProxyHeaders(req, body, rewriteMode !== null);
+
+ await new Promise((resolve, reject) => {
+ const proxyReq = https.request(
+ {
+ hostname: 'localhost',
+ port: route.miniapp.port,
+ path: nextUrl,
+ method: req.method,
+ headers,
+ rejectUnauthorized: false,
+ },
+ (proxyRes) => {
+ res.statusCode = proxyRes.statusCode ?? 502;
+
+ const outgoingHeaders = normalizeProxyHeaders(proxyRes.headers, rewriteMode !== null);
+ for (const [key, value] of Object.entries(outgoingHeaders)) {
+ if (typeof value !== 'undefined') {
+ res.setHeader(key, value);
+ }
+ }
+
+ if (!rewriteMode) {
+ proxyRes.pipe(res);
+ proxyRes.on('end', resolve);
+ proxyRes.on('error', reject);
+ return;
+ }
+
+ const chunks: Buffer[] = [];
+ proxyRes.on('data', (chunk) => {
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
+ });
+ proxyRes.on('end', () => {
+ const rawBody = Buffer.concat(chunks).toString('utf-8');
+ const rewritten = rewriteMiniappBody(rawBody, route.prefix);
+ res.setHeader('Content-Length', Buffer.byteLength(rewritten));
+ res.end(rewritten);
+ resolve();
+ });
+ proxyRes.on('error', reject);
+ },
+ );
+
+ proxyReq.on('error', reject);
+
+ if (body) {
+ proxyReq.write(body);
+ }
+ proxyReq.end();
+ });
+}
+
+async function readRequestBody(req: IncomingMessage): Promise {
+ const method = req.method?.toUpperCase();
+ if (!method || method === 'GET' || method === 'HEAD' || method === 'OPTIONS') {
+ return null;
+ }
+
+ const chunks: Buffer[] = [];
+ for await (const chunk of req) {
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
+ }
+ if (chunks.length === 0) return null;
+ return Buffer.concat(chunks);
+}
+
+function buildProxyHeaders(
+ req: IncomingMessage,
+ body: Buffer | null,
+ disableCompression: boolean,
+): Record {
+ const headers: Record = {};
+ for (const [key, value] of Object.entries(req.headers)) {
+ if (key.startsWith(':')) continue;
+ if (key === 'host') continue;
+ if (key === 'connection') continue;
+ if (key === 'content-length') continue;
+ if (key === 'transfer-encoding') continue;
+ if (key === 'accept-encoding' && disableCompression) continue;
+ if (typeof value === 'undefined') continue;
+ headers[key] = Array.isArray(value) ? value.join(', ') : value;
+ }
+
+ if (disableCompression) {
+ headers['accept-encoding'] = 'identity';
+ }
+ if (body) {
+ headers['content-length'] = String(body.length);
+ }
+ return headers;
+}
+
+function normalizeProxyHeaders(
+ headers: IncomingMessage['headers'],
+ stripEncoding: boolean,
+): Record {
+ const output: Record = {};
+ for (const [key, value] of Object.entries(headers)) {
+ if (typeof value === 'undefined') continue;
+ if (stripEncoding && (key === 'content-encoding' || key === 'content-length' || key === 'transfer-encoding')) {
+ continue;
+ }
+ output[key] = value;
+ }
+ return output;
+}
+
+function prependMiddleware(
+ server: ViteDevServer,
+ middleware: (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void,
+): void {
+ const stack = (
+ server.middlewares as {
+ stack?: Array<{ route: string; handle: typeof middleware }>;
+ }
+ ).stack;
+ if (stack) {
+ stack.unshift({ route: '', handle: middleware });
+ return;
+ }
+ server.middlewares.use(middleware);
+}
+
function generateEcosystemDataForBuild(
root: string,
miniappsDir: string,
diff --git a/src/lib/__tests__/dweb-update.test.ts b/src/lib/__tests__/dweb-update.test.ts
index 4606a9222..011d0b206 100644
--- a/src/lib/__tests__/dweb-update.test.ts
+++ b/src/lib/__tests__/dweb-update.test.ts
@@ -11,7 +11,10 @@ function stubGlobals() {
vi.stubGlobal('__KEYAPP_SITE_ORIGIN__', 'https://example.com/KeyApp/')
vi.stubGlobal('__DEV_MODE__', false)
vi.stubGlobal('__APP_VERSION__', '1.2.3')
- Object.defineProperty(window, 'dwebTarget', { value: true, configurable: true })
+ Object.defineProperty(window, '__native_close_watcher_kit__', {
+ value: {},
+ configurable: true,
+ })
}
describe('dweb update', () => {
diff --git a/src/lib/crypto/secure-storage.ts b/src/lib/crypto/secure-storage.ts
index a1428eae2..fa1dc149a 100644
--- a/src/lib/crypto/secure-storage.ts
+++ b/src/lib/crypto/secure-storage.ts
@@ -5,6 +5,7 @@
* - Web 环境:使用 AES-GCM 密码加密 + localStorage
*/
+import { isDweb } from '@plaoc/is-dweb';
import { encrypt, decrypt, type EncryptedData } from './encryption';
import i18n from '@/i18n';
@@ -47,7 +48,11 @@ export interface StoredData {
/** 检测是否在 DWEB 环境 */
export function isDwebEnvironment(): boolean {
- return typeof window !== 'undefined' && 'dwebTarget' in window;
+ try {
+ return isDweb();
+ } catch {
+ return false;
+ }
}
/** DWEB biometric 插件类型 */
diff --git a/vite.config.ts b/vite.config.ts
index 240167eb2..0f52c2f19 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -82,10 +82,10 @@ function getPreferredLanIPv4(): string | undefined {
function getPackageVersion(): string {
try {
- const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8')) as { version?: string }
- return pkg.version ?? '0.0.0'
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8')) as { version?: string };
+ return pkg.version ?? '0.0.0';
} catch {
- return '0.0.0'
+ return '0.0.0';
}
}
@@ -112,16 +112,13 @@ export default defineConfig(({ mode }) => {
const tronGridApiKey = env.TRONGRID_API_KEY ?? process.env.TRONGRID_API_KEY ?? '';
const etherscanApiKey = env.ETHERSCAN_API_KEY ?? process.env.ETHERSCAN_API_KEY ?? '';
const moralisApiKey = env.MORALIS_API_KEY ?? process.env.MORALIS_API_KEY ?? '';
- const isDevBuild = (env.VITE_DEV_MODE ?? process.env.VITE_DEV_MODE) === 'true'
- const siteOrigin =
- env.SITE_ORIGIN ??
- process.env.SITE_ORIGIN ??
- 'https://bioforestchain.github.io/KeyApp/'
+ const isDevBuild = (env.VITE_DEV_MODE ?? process.env.VITE_DEV_MODE) === 'true';
+ const siteOrigin = env.SITE_ORIGIN ?? process.env.SITE_ORIGIN ?? 'https://bioforestchain.github.io/KeyApp/';
- const buildTime = new Date()
- const pad = (value: number) => value.toString().padStart(2, '0')
- const buildSuffix = `-${pad(buildTime.getUTCMonth() + 1)}${pad(buildTime.getUTCDate())}${pad(buildTime.getUTCHours())}`
- const appVersion = `${getPackageVersion()}${isDevBuild ? buildSuffix : ''}`
+ const buildTime = new Date();
+ const pad = (value: number) => value.toString().padStart(2, '0');
+ const buildSuffix = `-${pad(buildTime.getUTCMonth() + 1)}${pad(buildTime.getUTCDate())}${pad(buildTime.getUTCHours())}`;
+ const appVersion = `${getPackageVersion()}${isDevBuild ? buildSuffix : ''}`;
return {
base: BASE_URL,
@@ -162,14 +159,15 @@ export default defineConfig(({ mode }) => {
retries: 3,
}),
miniappsPlugin({
+ devMode: 'build',
apps: {
'xin.dweb.teleport': {
- server: 'wujie',
- build: 'wujie',
+ server: 'iframe',
+ build: 'iframe',
},
'xin.dweb.biobridge': {
- server: 'wujie',
- build: 'wujie',
+ server: 'iframe',
+ build: 'iframe',
},
},
remoteMiniapps: remoteMiniappsConfig,