diff --git a/public/style/4nk.css b/public/style/4nk.css
index abf34bd..852af49 100644
--- a/public/style/4nk.css
+++ b/public/style/4nk.css
@@ -20,6 +20,10 @@ body {
background-blend-mode :soft-light;
height: 100vh;
}
+ .message {
+ font-size: 14px;
+ overflow-wrap: anywhere;
+ }
/** Modal Css */
.modal {
@@ -35,7 +39,7 @@ body {
}
.modal-content {
- width: 40%;
+ width: 55%;
height: 30%;
background-color: white;
border-radius: 4px;
@@ -55,14 +59,14 @@ body {
}
.confirmation-box {
- margin-top: 20px;
+ /* margin-top: 20px; */
align-content: center;
width: 70%;
height: 20%;
- padding: 20px;
- font-size: 1.6em;
+ /* padding: 20px; */
+ font-size: 1.5em;
color: #333333;
- top: 20%;
+ top: 5%;
position: relative;
}
diff --git a/src/html/confirmation-modal.html b/src/html/confirmation-modal.html
new file mode 100644
index 0000000..2c3557c
--- /dev/null
+++ b/src/html/confirmation-modal.html
@@ -0,0 +1,15 @@
+
+
Login
-
Confirm
-
Refuse
+
+ Attempting to pair device with address
+ {{device1}}
+ with device with address
+ {{device2}}
+
+
+ Awaiting pairing validation...
+
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index f140d45..62f23c6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,7 +1,7 @@
import Services from './services/service';
// import { WebSocketClient } from './websockets';
-const wsurl = `ws://74.234.68.175:8090`;
+const wsurl = `ws://74.234.68.175:8091`;
document.addEventListener('DOMContentLoaded', async () => {
try {
@@ -20,6 +20,13 @@ document.addEventListener('DOMContentLoaded', async () => {
}
await services.addWebsocketConnection(wsurl);
await services.recoverInjectHtml()
+
+ const queryString = window.location.search;
+ const urlParams = new URLSearchParams(queryString)
+ const pairingAddress = urlParams.get('address')
+ if(pairingAddress) {
+ await services.sendPairingTx(pairingAddress)
+ }
})
} catch (error) {
console.error(error);
diff --git a/src/services/database.ts b/src/services/database.ts
index b3042aa..a246429 100644
--- a/src/services/database.ts
+++ b/src/services/database.ts
@@ -37,7 +37,7 @@ class Database {
},
AnkMessages: {
name: "messages",
- options: {'keyPath': 'transaction'},
+ options: {'keyPath': 'id'},
indices: []
}
}
diff --git a/src/services/routing.service.ts b/src/services/routing.service.ts
index cc0386b..4813529 100644
--- a/src/services/routing.service.ts
+++ b/src/services/routing.service.ts
@@ -1,6 +1,8 @@
import Database from './database';
import modalHtml from '../html/login-modal.html?raw';
+import confirmationModalHtml from '../html/confirmation-modal.html?raw';
import modalScript from '../html/login-modal.js?raw';
+import confirmationModalScript from '../html/confirmation-modal.js?raw';
import Services from './service';
@@ -8,7 +10,8 @@ export default class Routing {
private static instance: Routing;
private database: any;
private sdkClient: any;
- private prd: any;
+ private currentPrd: any;
+ private currentOutpoint?: string;
private constructor() {}
// Method to access the singleton instance of Services
@@ -25,20 +28,46 @@ export default class Routing {
this.database = Database.getInstance()
}
- public openLoginModal(prd?: any) {
+ public openLoginModal(myAddress: string, receiverAddress: string) {
const container = document.querySelector('.page-container');
- if (container) container.innerHTML += modalHtml;
+ let html = modalHtml
+ html = html.replace('{{device1}}', myAddress)
+ html = html.replace('{{device2}}', receiverAddress)
+ if (container) container.innerHTML += html;
+ const modal = document.getElementById('login-modal')
+ if (modal) modal.style.display = 'flex';
+ const newScript = document.createElement('script');
+
+
+ newScript.setAttribute('type', 'module')
+ newScript.textContent = modalScript;
+ document.head.appendChild(newScript).parentNode?.removeChild(newScript);
+ }
+
+ public openConfirmationModal(prd?: any, outpointCommitment?: string) {
+ this.currentPrd = prd;
+ const sender = JSON.parse(prd.sender)?.sp_addresses
+ let html = confirmationModalHtml
+ html = html.replace('{{device1}}', sender[0])
+ html = html.replace('{{device2}}', sender[1])
+ this.currentOutpoint = outpointCommitment as string;
+ const container = document.querySelector('.page-container');
+
+ if (container) container.innerHTML += html;
const modal = document.getElementById('modal')
if (modal) modal.style.display = 'flex';
const newScript = document.createElement('script');
newScript.setAttribute('type', 'module')
- newScript.textContent = modalScript;
+ newScript.textContent = confirmationModalScript;
document.head.appendChild(newScript).parentNode?.removeChild(newScript);
+
+ // Add correct text
+
// Close modal when clicking outside of it
window.onclick = (event) => {
const modal = document.getElementById('modal');
if (event.target === modal) {
- this.closeLoginModal(prd);
+ this.confirm(this.currentPrd || prd, outpointCommitment || this.currentOutpoint);
}
}
}
@@ -48,10 +77,20 @@ export default class Routing {
console.log("🚀 ~ Routing ~ confirmLogin ~ loginTx:", loginTx)
this.sdkClient.login('LOGIN', loginTx)
}
- async closeLoginModal(prd?: any) {
+ async closeLoginModal() {
+ const modal = document.getElementById('login-modal')
+ if (modal) modal.style.display = 'none';
+ }
+
+ async confirm(prd?: any, outpointCommitment?: string) {
const service = await Services.getInstance()
const modal = document.getElementById('modal')
+ console.log("🚀 ~ Routing ~ confirm ~ prd:", this.currentPrd || prd, outpointCommitment)
if (modal) modal.style.display = 'none';
- if(prd) service.pairDevice(prd)
+ if(this.currentPrd || prd) service.pairDevice(this.currentPrd || prd, outpointCommitment || this.currentOutpoint as string)
}
+ async closeConfirmationModal() {
+ const modal = document.getElementById('modal')
+ if (modal) modal.style.display = 'none';
+ }
}
\ No newline at end of file
diff --git a/src/services/service.ts b/src/services/service.ts
index 7b107c0..b64a681 100644
--- a/src/services/service.ts
+++ b/src/services/service.ts
@@ -9,7 +9,7 @@ import Database from './database';
import { WebSocketClient } from '../websockets';
import QRCode from 'qrcode'
import { servicesVersion } from 'typescript';
-import { CachedMessage } from '../../dist/pkg/sdk_client';
+import { ApiReturn, CachedMessage, Member } from '../../dist/pkg/sdk_client';
import Routing from './routing.service';
export default class Services {
@@ -28,7 +28,6 @@ export default class Services {
// Method to access the singleton instance of Services
public static async getInstance(): Promise
{
if (!Services.instance) {
- console.log("🚀 ~ Services ~ getInstance ~ Services.instance:", Services.instance)
Services.instance = new Services();
await Services.instance.init();
}
@@ -68,17 +67,18 @@ export default class Services {
if(btn) {
this.addSubscription(btn, 'click', 'injectProcessListPage')
}
+ const url = location.href
this.generateQRCode(this.sp_address || '')
}
private generateQRCode = async (text: string) => {
+ console.log("🚀 ~ Services ~ generateQRCode= ~ text:", text)
try {
const container = document.getElementById('containerId');
const url = await QRCode.toDataURL(text);
const qrCode = container?.querySelector('.qr-code img');
qrCode?.setAttribute('src', url)
- console.log(url);
} catch (err) {
console.error(err);
}
@@ -89,78 +89,84 @@ export default class Services {
const txid = '0'.repeat(64)
var vout = Number.MAX_SAFE_INTEGER;
const paringTemplate = {
- "uuid": "",
"html": "",
- "script": "",
"style": "",
- "init_state": {
- "roles": {
- "owner": {
- "members": [{sp_addresses: [myAddress]}, {sp_addresses:[recipientAddress]}],
- "validation_rules":
- [
- {
- "quorum": 0.0,
- "fields": [
- "roles",
- "pairing_tx"
- ],
- "min_sig_member": 0.0
- }
- ]
- }
- },
- "pairing_tx": "",
+ "script": "",
+ "description": "AliceBob",
+ "roles": {
+ "owner": {
+ "members": [{sp_addresses: [myAddress]}, {sp_addresses:[recipientAddress]}],
+ "validation_rules":
+ [
+ {
+ "quorum": 1.0,
+ "fields": [
+ "roles",
+ "pairing_tx"
+ ],
+ "min_sig_member": 1.0
+ }
+ ]
+ }
},
- "commited_in": `${txid}:4294967295`
+ "pairing_tx": `${txid}:4294967295`,
}
+
const service = await Services.getInstance();
- const process = await service.sdkClient.create_process_from_template(JSON.stringify(paringTemplate))
- console.log("🚀 ~ Services ~ prepareProcessTx ~ process:", process)
+ const process = await service.sdkClient.create_update_transaction(undefined, JSON.stringify(paringTemplate), 1)
return process
}
async sendPairingTx(sp_address: string): Promise {
const services = await Services.getInstance();
const amount = await this.getAmount() as any
- console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", typeof amount)
console.log("🚀 ~ Services ~ sendPairingTx ~ amount:", amount)
- if(amount === 0n) {
- const faucetMessage = await services.createFaucetMessage()
- console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage)
- services.websocketConnection?.sendNormalMessage(faucetMessage)
- }
+ // if(amount === 0n) {
+ // const faucetMessage = await services.createFaucetMessage()
+ // console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage)
+ // services.websocketConnection?.sendNormalMessage(faucetMessage)
+ // }
const spAddress = await this.getDeviceAddress() as any
- const process = await this.prepareProcessTx(spAddress, 'sprt1qqdxya9n4pzc9vetzug7fch2xag4x5vxxrjc6rnh2rh3xhlvalmlrsqmy5t6vfa0nuf92dudf9uvaye3afw6uu86kw34q2x3k9qmmf8qp0vtfm9xa')
- if(process) await services.sdkClient.pair_device(process.uuid, ['sprt1qqdxya9n4pzc9vetzug7fch2xag4x5vxxrjc6rnh2rh3xhlvalmlrsqmy5t6vfa0nuf92dudf9uvaye3afw6uu86kw34q2x3k9qmmf8qp0vtfm9xa'])
+ let txid = '0'.repeat(64)
+
setTimeout(async () => {
- const tx = await services.sdkClient.create_process_init_transaction(process, 1)
- console.log("🚀 ~ Services ~ sendPairingTx ~ tx:", tx)
- services.websocketConnection?.sendMessage('NewTx', JSON.stringify(tx))
- if(tx?.new_messages && tx.new_messages.length) {
- await this.sendCipherMessages(tx.new_messages)
+ let pairing = await services.sdkClient.pair_device(`${txid}:4294967295`, [sp_address])
+ const process = await this.prepareProcessTx(spAddress, sp_address)
+ const tx = process.new_tx_to_send
+ const parsedTx = JSON.parse(tx)
+ const transaction = parsedTx.transaction
+ txid = await services.sdkClient.get_txid(transaction)
+ const root_commitment = process.updated_process[0];
+ const init_process = process.updated_process[1];
+ console.log("🚀 ~ Services ~ setTimeout ~ init_process:", init_process, init_process.payload)
+ console.log("🚀 ~ Services ~ setTimeout ~ txToSend:", tx)
+ const prd = JSON.stringify(init_process.impending_requests[0]);
+ services.websocketConnection?.sendMessage('NewTx', tx)
+ pairing = await services.sdkClient.pair_device(`${txid}:0`, [sp_address])
+
+ const dump = await services.sdkClient.dump_device()
+
+ const prd_response = await services.sdkClient.response_prd(root_commitment, prd, true)
+ console.log("🚀 ~ Services ~ setTimeout ~ prd_response:", prd_response, prd, root_commitment)
+ if(process?.ciphers_to_send && process.ciphers_to_send.length) {
+ await this.sendCipherMessages(process.ciphers_to_send)
}
- },2000)
- // setTimeout(() => {
- // const paringin = services.sdkClient.create_pairing_transaction('sprt1qqf7jes989hkmfh0w9526pqy0rd5hlflclzez5dzateeza7hhl0vqzqhnmhe0kkez9m5vx2rastph5patqr5h3tr9pcsukzea0lz0dp6tcqaz2u8j', 1)
- // console.log("🚀 ~ Services ~ setTimeout ~ paringin:", paringin)
- // services.websocketConnection?.sendMessage('NewTx', JSON.stringify(paringin))
- // if(paringin?.new_network_msg?.ciphertext) {
- // services.websocketConnection?.sendMessage('Cipher', paringin?.new_network_msg?.ciphertext)
- // let get_outputs_result = services.sdkClient.get_outputs()
- // console.log("🚀 ~ Services ~ setTimeout ~ get_outputs_result:", get_outputs_result)
- // }
- // }, 5000)
+ const router = await Routing.getInstance();
+ router.openLoginModal(spAddress, sp_address)
+ }, 2000)
}
- async sendCipherMessages(messages: CachedMessage[]) {
+ async resetDevice() {
+ const service = await Services.getInstance()
+ await service.sdkClient.reset_device()
+ }
+
+ async sendCipherMessages(messages: string[]) {
const service = await Services.getInstance();
messages.forEach((message) => {
- message.cipher?.forEach((cipher => {
- service.websocketConnection?.sendMessage('Cipher', cipher)
- }))
+ service.websocketConnection?.sendMessage('Cipher', message)
})
}
@@ -174,10 +180,18 @@ export default class Services {
async parseCipher(message: string) {
try {
const services = await Services.getInstance();
+ try {
+ JSON.parse(message)
+ const router = await Routing.getInstance();
+ router.closeLoginModal()
+ this.injectProcessListPage()
+ } catch {
+ console.log('Not proper format for cipher')
+ }
const parsedTx = await services.sdkClient.parse_cipher(message, 0.00001)
console.log("🚀 ~ Services ~ parseCipher ~ parsedTx:", parsedTx)
await this.processTx(parsedTx)
- await this.saveCipherTxToDb(parsedTx)
+ // await this.saveCipherTxToDb(parsedTx)
} catch(e) {
console.log(e)
}
@@ -191,60 +205,112 @@ export default class Services {
console.log("🚀 ~ Services ~ parseNewTx ~ parsedTx:", parsedTx)
if(parsedTx) {
await this.processTx(parsedTx)
- await this.saveTxToDb(parsedTx)
+ // await this.saveTxToDb(parsedTx)
}
} catch(e) {
console.log(e)
}
}
- async processTx(tx: CachedMessage) {
- if(tx.status) {
- switch(tx.status) {
- case 'Opened':
- if(tx.prd) {
- const parsedPrd = JSON.parse(tx.prd)
- console.log("🚀 ~ Services ~ processTx ~ Opened:", parsedPrd)
- const router = await Routing.getInstance();
+ async processTx(tx: ApiReturn) {
+ const service = await Services.getInstance()
+ if(tx.ciphers_to_send && tx.ciphers_to_send.length) {
+ await this.sendCipherMessages(tx.ciphers_to_send)
+ }
- // Mocker le fait que c'est une transaction de connection
- if(parsedPrd && parsedPrd.prd_type === 'Init') {
- router.openLoginModal(parsedPrd)
- } else if(parsedPrd && parsedPrd.prd_type === 'Signed') {
- router.closeLoginModal()
- }
- }
- break;
- case 'TxWaitingPrd':
- console.log("🚀 ~ Services ~ processTx ~ TxWaitingPrd:", tx)
- break;
- case 'CipherWaitingTx':
- console.log("🚀 ~ Services ~ processTx ~ CipherWaitingTx:", tx)
- break;
+ if(tx.new_tx_to_send) {
+ service.websocketConnection?.sendMessage('NewTx', tx.new_tx_to_send)
+ }
+ if(tx.updated_process && tx.updated_process.length) {
+ // if(tx.ciphers_to_send?.length != 1 || tx.updated_process?.length != 2) return
+ const impendingRequest = tx.updated_process[1].impending_requests[0]
+ const pcdCommitment = impendingRequest.payload
+ const outpointCommitment = tx.updated_process[0]
+ console.log("🚀 ~ Services ~ processTx ~ pcdCommitment:", pcdCommitment)
+ if(impendingRequest.prd_type === 'Update' && tx.ciphers_to_send.length === 0) {
+ const router = await Routing.getInstance();
+
+ // Mocker le fait que c'est une transaction de connection
+ const services = await Services.getInstance();
+ // const faucetMessage = await services.createFaucetMessage()
+ // console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage)
+ // services.websocketConnection?.sendNormalMessage(faucetMessage)
+ router.openConfirmationModal(impendingRequest, outpointCommitment)
}
}
- }
-
- async pairDevice(prd: any) {
- const service = await Services.getInstance();
- await service.sdkClient.pair_device(prd.process_uuid, ['sprt1qqwp87lrahm2ye9kje45dqgsncvkg94fr7amrnaaflxkx6kn62za7uq4kpegfp3ks475e9jp7y0h0xzsqydkf35lg7g0kukr6zkynde552gk6z92n'])
- const spAddress = await this.getDeviceAddress() as any
- const process = await this.prepareProcessTx(spAddress, 'sprt1qqwp87lrahm2ye9kje45dqgsncvkg94fr7amrnaaflxkx6kn62za7uq4kpegfp3ks475e9jp7y0h0xzsqydkf35lg7g0kukr6zkynde552gk6z92n')
- const tx = await service.sdkClient.create_process_init_transaction(process, 1)
- for(const msg of tx.new_messages) {
- msg.prd?.replace('Init', 'Signed')
+
+ if(tx.updated_cached_msg && tx.updated_cached_msg.length) {
+ tx.updated_cached_msg.forEach(message => this.saveTxToDb(message))
}
- console.log("🚀 ~ Services ~ pairDevice ~ tx:", tx)
- service.websocketConnection?.sendMessage('NewTx', JSON.stringify(tx))
+
+ // if(tx.prd) {
+ // const parsedPrd = JSON.parse(tx.prd)
+ // console.log("🚀 ~ Services ~ processTx ~ Opened:", parsedPrd)
+ // const router = await Routing.getInstance();
+
+ // // Mocker le fait que c'est une transaction de connection
+ // if(parsedPrd && parsedPrd.prd_type === 'Init') {
+ // const services = await Services.getInstance();
+ // const faucetMessage = await services.createFaucetMessage()
+ // console.log("🚀 ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", faucetMessage)
+ // services.websocketConnection?.sendNormalMessage(faucetMessage)
+ // router.openConfirmationModal(parsedPrd)
+ // } else if(parsedPrd && parsedPrd.prd_type === 'Signed') {
+ // router.closeLoginModal()
+ // }
+ // }
}
- async saveTxToDb(tx: string) {
+ async pairDevice(prd: any, outpointCommitment: string) {
+ console.log("🚀 ~ Services ~ pairDevice ~ prd:", prd)
+ const service = await Services.getInstance();
+ const spAddress = await this.getDeviceAddress() as any;
+ const sender = JSON.parse(prd?.sender)
+ const senderAddress = sender?.sp_addresses?.find((address: string) => address !== spAddress)
+ console.log("🚀 ~ Services ~ pairDevice ~ senderAddress:", senderAddress)
+ if(senderAddress) {
+ const proposal = service.sdkClient.get_update_proposals(outpointCommitment);
+ console.log("🚀 ~ Services ~ pairDevice ~ proposal:", proposal)
+ // const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '')
+ const parsedProposal = JSON.parse(proposal[0])
+
+ console.log("🚀 ~ Services ~ pairDevice ~ parsedProposal:", parsedProposal)
+ const roles = JSON.parse(parsedProposal.roles)
+ console.log("🚀 ~ Services ~ pairDevice ~ roles:", roles, Array.isArray(roles), !roles.owner)
+ if(Array.isArray(roles) || !roles.owner) return
+ const proposalMembers = roles?.owner?.members
+ const isFirstDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === spAddress))
+ const isSecondDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === senderAddress))
+ console.log("🚀 ~ Services ~ pairDevice ~ proposalMembers:", proposalMembers)
+ if(proposalMembers?.length !== 2 || !isFirstDevice || !isSecondDevice) return
+ const pairingTx = parsedProposal?.pairing_tx?.replace(/^\"+|\"+$/g, '')
+
+ let txid = '0'.repeat(64)
+ console.log("🚀 ~ Services ~ pairDevice ~ pairingTx:", pairingTx, `${txid}:4294967295`)
+
+ const pairing = await service.sdkClient.pair_device(`${txid}:4294967295`, [senderAddress])
+ const device = this.dumpDevice()
+ console.log("🚀 ~ Services ~ pairDevice ~ device:", device)
+ this.saveDevice(device)
+ // await service.sdkClient.pair_device(pairingTx, [senderAddress])
+ console.log("🚀 ~ Services ~ pairDevice ~ pairing:", pairing)
+ // const process = await this.prepareProcessTx(spAddress, senderAddress)
+ console.log("🚀 ~ Services ~ pairDevice ~ process:", outpointCommitment, prd, prd.payload)
+ const prdString = JSON.stringify(prd).trim()
+ console.log("🚀 ~ Services ~ pairDevice ~ prdString:", prdString)
+ let tx = await service.sdkClient.response_prd(outpointCommitment, prdString, true)
+ console.log("🚀 ~ Services ~ pairDevice ~ tx:", tx)
+ if(tx.ciphers_to_send) {
+ tx.ciphers_to_send.forEach((cipher: string) => service.websocketConnection?.sendMessage('Cipher', cipher))
+ }
+ this.injectProcessListPage()
+ }
+ }
+
+ async saveTxToDb(tx: CachedMessage) {
const database = await Database.getInstance();
const indexedDb = await database.getDb();
-
- if(tx) {
- await database.writeObject(indexedDb, database.getStoreList().AnkMessages, tx, null);
- }
+ await database.writeObject(indexedDb, 'messages', tx, null);
}
async saveCipherTxToDb(tx: string) {
@@ -315,9 +381,8 @@ export default class Services {
async createNewDevice() {
const service = await Services.getInstance();
- const sp_address = await service.sdkClient.create_new_device(1994, 'regtest')
+ const sp_address = await service.sdkClient.create_new_device(0, 'regtest')
if(sp_address) {
- console.log("🚀 ~ Services ~ createNewDevice ~ device:", {sp_adress: sp_address})
const database = await Database.getInstance();
const indexedDb = await database.getDb();
await database.writeObject(indexedDb, database.getStoreList().AnkSpAddress, {sp_address: sp_address}, null);
@@ -326,7 +391,6 @@ export default class Services {
await service.saveDevice(device)
}
this.sp_address = sp_address;
- console.log("🚀 ~ Services ~ createNewDevice ~ device:", sp_address)
return sp_address;
}
@@ -559,4 +623,4 @@ export default class Services {
}
}
-}
\ No newline at end of file
+}
diff --git a/src/websockets.ts b/src/websockets.ts
index a839ec9..939076b 100644
--- a/src/websockets.ts
+++ b/src/websockets.ts
@@ -15,6 +15,13 @@ class WebSocketClient {
console.log('WebSocket connection established');
// Once the connection is open, send all messages in the queue
// this.sendNormalMessage(faucetMessage)
+ const service = await Services.getInstance();
+ const amount = await service.getAmount() as bigint
+
+ if(amount === 0n) {
+ const faucetMessage = await services.createFaucetMessage()
+ this.sendNormalMessage(faucetMessage)
+ }
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
diff --git a/vite.config.ts b/vite.config.ts
index 6a2636c..71672c7 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -2,6 +2,8 @@ import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue'; // or react from '@vitejs/plugin-react' if using React
import wasm from 'vite-plugin-wasm';
import {createHtmlPlugin} from 'vite-plugin-html';
+import fs from 'fs'
+import path from 'path'
export default defineConfig({
optimizeDeps: {