create-openfort 0.1.10 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/index.js +20 -20
- package/package.json +1 -1
- package/template/openfort-templates/firebase/AGENTS.md +1 -1
- package/template/openfort-templates/firebase/package.json +3 -3
- package/template/openfort-templates/firebase/src/App.tsx +2 -1
- package/template/openfort-templates/firebase/src/integrations/openfort/providers.tsx +36 -35
- package/template/openfort-templates/firebase/src/lib/contracts.ts +34 -0
- package/template/openfort-templates/firebase/src/ui/openfort/blockchain/ActionsCard.tsx +25 -13
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletCreation.tsx +108 -63
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletListCard.tsx +211 -41
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletPasswordSheets.tsx +45 -21
- package/template/openfort-templates/headless/AGENTS.md +1 -1
- package/template/openfort-templates/headless/package.json +2 -2
- package/template/openfort-templates/headless/src/components/cards/actions.tsx +30 -21
- package/template/openfort-templates/headless/src/components/cards/profile.tsx +0 -2
- package/template/openfort-templates/headless/src/components/cards/wallets.tsx +230 -67
- package/template/openfort-templates/headless/src/components/createWallet.tsx +115 -73
- package/template/openfort-templates/headless/src/components/passwordRecovery.tsx +48 -23
- package/template/openfort-templates/headless/src/components/providers.tsx +30 -25
- package/template/openfort-templates/headless/src/lib/contracts.ts +43 -0
- package/template/openfort-templates/openfort-ui/AGENTS.md +1 -1
- package/template/openfort-templates/openfort-ui/package.json +3 -3
- package/template/openfort-templates/openfort-ui/src/components/cards/actions.tsx +30 -15
- package/template/openfort-templates/openfort-ui/src/components/cards/auth.tsx +1 -1
- package/template/openfort-templates/openfort-ui/src/components/cards/wallets.tsx +232 -67
- package/template/openfort-templates/openfort-ui/src/components/createWallet.tsx +115 -73
- package/template/openfort-templates/openfort-ui/src/components/passwordRecovery.tsx +48 -23
- package/template/openfort-templates/openfort-ui/src/components/providers.tsx +34 -30
- package/template/openfort-templates/openfort-ui/src/lib/contracts.ts +35 -0
- package/template/openfort-templates/solana-headless/biome.json +70 -0
- package/template/openfort-templates/solana-headless/index.html +16 -0
- package/template/openfort-templates/solana-headless/package.json +34 -0
- package/template/openfort-templates/solana-headless/public/githubLogo.svg +5 -0
- package/template/openfort-templates/solana-headless/public/openfort.svg +13 -0
- package/template/openfort-templates/solana-headless/public/solanaLogo.svg +11 -0
- package/template/openfort-templates/solana-headless/src/App.tsx +7 -0
- package/template/openfort-templates/solana-headless/src/components/cards/auth.tsx +167 -0
- package/template/openfort-templates/solana-headless/src/components/cards/head.tsx +359 -0
- package/template/openfort-templates/solana-headless/src/components/cards/history.tsx +134 -0
- package/template/openfort-templates/solana-headless/src/components/cards/main.tsx +140 -0
- package/template/openfort-templates/solana-headless/src/components/cards/profile.tsx +80 -0
- package/template/openfort-templates/solana-headless/src/components/cards/send.tsx +242 -0
- package/template/openfort-templates/solana-headless/src/components/cards/sign.tsx +48 -0
- package/template/openfort-templates/solana-headless/src/components/cards/wallets.tsx +199 -0
- package/template/openfort-templates/solana-headless/src/components/createWallet.tsx +117 -0
- package/template/openfort-templates/solana-headless/src/components/passwordRecovery.tsx +167 -0
- package/template/openfort-templates/solana-headless/src/components/providers.tsx +23 -0
- package/template/openfort-templates/solana-headless/src/components/ui/Sheet.tsx +47 -0
- package/template/openfort-templates/solana-headless/src/components/ui/Tabs.tsx +111 -0
- package/template/openfort-templates/solana-headless/src/components/ui/TruncateData.tsx +31 -0
- package/template/openfort-templates/solana-headless/src/hooks/useSolanaMessageSigner.ts +37 -0
- package/template/openfort-templates/solana-headless/src/index.css +180 -0
- package/template/openfort-templates/solana-headless/src/lib/errors.ts +4 -0
- package/template/openfort-templates/solana-headless/src/lib/solana/balance.ts +17 -0
- package/template/openfort-templates/solana-headless/src/lib/solana/index.ts +4 -0
- package/template/openfort-templates/solana-headless/src/lib/solana/kora.ts +137 -0
- package/template/openfort-templates/solana-headless/src/lib/solana/transaction.ts +146 -0
- package/template/openfort-templates/solana-headless/src/lib/solana/transactionHistory.ts +39 -0
- package/template/openfort-templates/solana-headless/src/main.tsx +13 -0
- package/template/openfort-templates/solana-headless/src/vite-env.d.ts +1 -0
- package/template/openfort-templates/solana-headless/tsconfig.app.json +24 -0
- package/template/openfort-templates/solana-headless/tsconfig.json +7 -0
- package/template/openfort-templates/solana-headless/tsconfig.node.json +22 -0
- package/template/openfort-templates/solana-headless/vite.config.ts +8 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { OpenfortEmbeddedSolanaWalletProvider } from '@openfort/react/solana'
|
|
2
|
+
import {
|
|
3
|
+
type Address,
|
|
4
|
+
appendTransactionMessageInstructions,
|
|
5
|
+
type Blockhash,
|
|
6
|
+
createNoopSigner,
|
|
7
|
+
createTransactionMessage,
|
|
8
|
+
getBase64EncodedWireTransaction,
|
|
9
|
+
type Instruction,
|
|
10
|
+
type MicroLamports,
|
|
11
|
+
partiallySignTransactionMessageWithSigners,
|
|
12
|
+
type SignatureBytes,
|
|
13
|
+
setTransactionMessageFeePayerSigner,
|
|
14
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
15
|
+
} from '@solana/kit'
|
|
16
|
+
import { KoraClient } from '@solana/kora'
|
|
17
|
+
import {
|
|
18
|
+
updateOrAppendSetComputeUnitLimitInstruction,
|
|
19
|
+
updateOrAppendSetComputeUnitPriceInstruction,
|
|
20
|
+
} from '@solana-program/compute-budget'
|
|
21
|
+
import { Base58 } from 'ox'
|
|
22
|
+
|
|
23
|
+
const COMPUTE_UNIT_LIMIT = 200_000
|
|
24
|
+
const COMPUTE_UNIT_PRICE = 50_000n as MicroLamports
|
|
25
|
+
|
|
26
|
+
interface KoraConfig {
|
|
27
|
+
rpcUrl: string
|
|
28
|
+
apiKey: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface SendGaslessTransactionParams {
|
|
32
|
+
from: Address
|
|
33
|
+
to: Address
|
|
34
|
+
amountInSol: number
|
|
35
|
+
provider: OpenfortEmbeddedSolanaWalletProvider
|
|
36
|
+
koraConfig: KoraConfig
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface GaslessTransactionResult {
|
|
40
|
+
signature: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Validate that the signature is a 64-byte Ed25519 signature */
|
|
44
|
+
function validateEd25519Signature(raw: Uint8Array): Uint8Array {
|
|
45
|
+
if (raw.length !== 64) {
|
|
46
|
+
throw new Error(`Invalid Ed25519 signature: expected 64 bytes, got ${raw.length}`)
|
|
47
|
+
}
|
|
48
|
+
return raw
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildTransactionMessage(
|
|
52
|
+
feePayer: ReturnType<typeof createNoopSigner>,
|
|
53
|
+
blockhash: string,
|
|
54
|
+
instructions: Instruction[]
|
|
55
|
+
) {
|
|
56
|
+
const msg = createTransactionMessage({ version: 0 })
|
|
57
|
+
const withPayer = setTransactionMessageFeePayerSigner(feePayer, msg)
|
|
58
|
+
const withLifetime = setTransactionMessageLifetimeUsingBlockhash(
|
|
59
|
+
{ blockhash: blockhash as Blockhash, lastValidBlockHeight: 0n },
|
|
60
|
+
withPayer
|
|
61
|
+
)
|
|
62
|
+
const withPrice = updateOrAppendSetComputeUnitPriceInstruction(COMPUTE_UNIT_PRICE, withLifetime)
|
|
63
|
+
const withLimit = updateOrAppendSetComputeUnitLimitInstruction(COMPUTE_UNIT_LIMIT, withPrice)
|
|
64
|
+
return appendTransactionMessageInstructions(instructions, withLimit)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function sendGaslessSolTransaction({
|
|
68
|
+
from,
|
|
69
|
+
to,
|
|
70
|
+
amountInSol,
|
|
71
|
+
provider,
|
|
72
|
+
koraConfig,
|
|
73
|
+
}: SendGaslessTransactionParams): Promise<GaslessTransactionResult> {
|
|
74
|
+
const client = new KoraClient({
|
|
75
|
+
rpcUrl: koraConfig.rpcUrl,
|
|
76
|
+
apiKey: koraConfig.apiKey,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Step 1: Get Kora's signer address
|
|
80
|
+
const { signer_address } = await client.getPayerSigner()
|
|
81
|
+
const koraNoopSigner = createNoopSigner(signer_address as Address)
|
|
82
|
+
|
|
83
|
+
// Step 2: Create transfer instruction via Kora
|
|
84
|
+
const transferLamports = Math.floor(amountInSol * 1_000_000_000)
|
|
85
|
+
const transferSol = await client.transferTransaction({
|
|
86
|
+
amount: transferLamports,
|
|
87
|
+
token: '11111111111111111111111111111111',
|
|
88
|
+
source: from,
|
|
89
|
+
destination: to,
|
|
90
|
+
signer_key: signer_address,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Step 3: Build transaction with Kora as fee payer
|
|
94
|
+
const { blockhash } = await client.getBlockhash()
|
|
95
|
+
const transaction = buildTransactionMessage(koraNoopSigner, blockhash, transferSol.instructions)
|
|
96
|
+
|
|
97
|
+
// Step 4: Partially sign (noop for Kora placeholder), then sign with Openfort
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
+
const partiallySignedTx = await partiallySignTransactionMessageWithSigners(transaction as any)
|
|
100
|
+
|
|
101
|
+
const result = await provider.signTransaction(new Uint8Array(partiallySignedTx.messageBytes))
|
|
102
|
+
const signatureBytes = validateEd25519Signature(Base58.toBytes(result.signature))
|
|
103
|
+
|
|
104
|
+
const userSignedTx = {
|
|
105
|
+
...partiallySignedTx,
|
|
106
|
+
signatures: {
|
|
107
|
+
...partiallySignedTx.signatures,
|
|
108
|
+
[from]: signatureBytes as SignatureBytes,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
const userSignedWire = getBase64EncodedWireTransaction(userSignedTx)
|
|
112
|
+
|
|
113
|
+
// Step 5: Send to Kora for co-signing and submission to Solana
|
|
114
|
+
const response = await client.signAndSendTransaction({
|
|
115
|
+
transaction: userSignedWire,
|
|
116
|
+
signer_key: signer_address,
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Extract signature: Kora may return it directly or in signed_transaction wire format
|
|
120
|
+
let txSignature = (response as unknown as Record<string, unknown>).signature as string | undefined
|
|
121
|
+
if (!txSignature) {
|
|
122
|
+
const signedTxB64 = (response as unknown as Record<string, unknown>).signed_transaction as string | undefined
|
|
123
|
+
if (signedTxB64) {
|
|
124
|
+
const wireBytes = Uint8Array.from(atob(signedTxB64), (c) => c.charCodeAt(0))
|
|
125
|
+
// Wire format: [num_signatures (1 byte), ...signatures (64 bytes each), ...]
|
|
126
|
+
// First signature (bytes 1..65) is the tx signature
|
|
127
|
+
const firstSig = wireBytes.slice(1, 65)
|
|
128
|
+
txSignature = Base58.fromBytes(firstSig)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!txSignature) {
|
|
133
|
+
throw new Error('Failed to extract transaction signature from Kora response')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return { signature: txSignature }
|
|
137
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { OpenfortEmbeddedSolanaWalletProvider } from '@openfort/react/solana'
|
|
2
|
+
import {
|
|
3
|
+
type Address,
|
|
4
|
+
appendTransactionMessageInstruction,
|
|
5
|
+
assertIsTransactionWithBlockhashLifetime,
|
|
6
|
+
createSolanaRpc,
|
|
7
|
+
createSolanaRpcSubscriptions,
|
|
8
|
+
createTransactionMessage,
|
|
9
|
+
lamports,
|
|
10
|
+
pipe,
|
|
11
|
+
type SignatureBytes,
|
|
12
|
+
type SignatureDictionary,
|
|
13
|
+
sendAndConfirmTransactionFactory,
|
|
14
|
+
setTransactionMessageFeePayer,
|
|
15
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
16
|
+
signTransactionMessageWithSigners,
|
|
17
|
+
type TransactionSigner,
|
|
18
|
+
} from '@solana/kit'
|
|
19
|
+
import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from '@solana-program/compute-budget'
|
|
20
|
+
import { getTransferSolInstruction } from '@solana-program/system'
|
|
21
|
+
import { Base58 } from 'ox'
|
|
22
|
+
|
|
23
|
+
const COMPUTE_UNIT_LIMIT = 200_000
|
|
24
|
+
const COMPUTE_UNIT_PRICE = 50_000n // microlamports
|
|
25
|
+
|
|
26
|
+
interface SendTransactionParams {
|
|
27
|
+
from: Address
|
|
28
|
+
to: Address
|
|
29
|
+
amountInSol: number
|
|
30
|
+
provider: OpenfortEmbeddedSolanaWalletProvider
|
|
31
|
+
rpcUrl?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface TransactionResult {
|
|
35
|
+
signature: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Convert a decimal amount to the smallest unit (e.g. SOL to lamports) without floating-point loss */
|
|
39
|
+
function toSmallestUnit(amount: number, decimals: number): bigint {
|
|
40
|
+
const str = amount.toString()
|
|
41
|
+
const [whole, frac = ''] = str.split('.')
|
|
42
|
+
const padded = (frac + '0'.repeat(decimals)).slice(0, decimals)
|
|
43
|
+
return BigInt(whole + padded)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Validate that the signature is a 64-byte Ed25519 signature */
|
|
47
|
+
function validateEd25519Signature(raw: Uint8Array): Uint8Array {
|
|
48
|
+
if (raw.length !== 64) {
|
|
49
|
+
throw new Error(`Invalid Ed25519 signature: expected 64 bytes, got ${raw.length}`)
|
|
50
|
+
}
|
|
51
|
+
return raw
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Extract the fee payer's signature from the signed transaction */
|
|
55
|
+
function getTransactionSignature(signatures: Record<string, SignatureBytes | null>, feePayer: Address): string {
|
|
56
|
+
const sig = signatures[feePayer]
|
|
57
|
+
if (!sig) {
|
|
58
|
+
throw new Error(`Fee payer signature not found for address: ${feePayer}`)
|
|
59
|
+
}
|
|
60
|
+
return Base58.fromBytes(sig)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function deriveWssUrl(rpcUrl: string): string {
|
|
64
|
+
try {
|
|
65
|
+
const parsed = new URL(rpcUrl)
|
|
66
|
+
const hostname = parsed.hostname
|
|
67
|
+
if (hostname === 'openfort.io' || hostname.endsWith('.openfort.io')) {
|
|
68
|
+
return 'wss://api.devnet.solana.com'
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// fall through
|
|
72
|
+
}
|
|
73
|
+
return rpcUrl.replace(/^https?:\/\//, 'wss://')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function createProviderSigner(
|
|
77
|
+
signerAddress: Address,
|
|
78
|
+
provider: OpenfortEmbeddedSolanaWalletProvider
|
|
79
|
+
): TransactionSigner {
|
|
80
|
+
return {
|
|
81
|
+
address: signerAddress,
|
|
82
|
+
signTransactions: async (transactions): Promise<readonly SignatureDictionary[]> => {
|
|
83
|
+
return Promise.all(
|
|
84
|
+
transactions.map(async (transaction) => {
|
|
85
|
+
const result = await provider.signTransaction({
|
|
86
|
+
messageBytes: new Uint8Array(transaction.messageBytes),
|
|
87
|
+
})
|
|
88
|
+
const signatureBytes = validateEd25519Signature(Base58.toBytes(result.signature))
|
|
89
|
+
return Object.freeze({
|
|
90
|
+
[signerAddress]: signatureBytes as SignatureBytes,
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
)
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function sendSolTransaction({
|
|
99
|
+
from,
|
|
100
|
+
to,
|
|
101
|
+
amountInSol,
|
|
102
|
+
provider,
|
|
103
|
+
rpcUrl,
|
|
104
|
+
}: SendTransactionParams): Promise<TransactionResult> {
|
|
105
|
+
const httpUrl = rpcUrl ?? 'https://api.devnet.solana.com'
|
|
106
|
+
const rpc = createSolanaRpc(httpUrl)
|
|
107
|
+
const rpcSubscriptions = createSolanaRpcSubscriptions(deriveWssUrl(httpUrl))
|
|
108
|
+
|
|
109
|
+
const signer = createProviderSigner(from, provider)
|
|
110
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send()
|
|
111
|
+
|
|
112
|
+
const transactionMessage = pipe(
|
|
113
|
+
createTransactionMessage({ version: 0 }),
|
|
114
|
+
(tx) => setTransactionMessageFeePayer(from, tx),
|
|
115
|
+
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
|
|
116
|
+
(tx) => appendTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: COMPUTE_UNIT_LIMIT }), tx),
|
|
117
|
+
(tx) =>
|
|
118
|
+
appendTransactionMessageInstruction(getSetComputeUnitPriceInstruction({ microLamports: COMPUTE_UNIT_PRICE }), tx),
|
|
119
|
+
(tx) =>
|
|
120
|
+
appendTransactionMessageInstruction(
|
|
121
|
+
getTransferSolInstruction({
|
|
122
|
+
source: signer,
|
|
123
|
+
destination: to,
|
|
124
|
+
amount: lamports(toSmallestUnit(amountInSol, 9)),
|
|
125
|
+
}),
|
|
126
|
+
tx
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage)
|
|
131
|
+
assertIsTransactionWithBlockhashLifetime(signedTransaction)
|
|
132
|
+
|
|
133
|
+
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })
|
|
134
|
+
const abortController = new AbortController()
|
|
135
|
+
const timeout = setTimeout(() => abortController.abort(), 60_000)
|
|
136
|
+
try {
|
|
137
|
+
await sendAndConfirmTransaction(signedTransaction, {
|
|
138
|
+
commitment: 'confirmed',
|
|
139
|
+
abortSignal: abortController.signal,
|
|
140
|
+
})
|
|
141
|
+
} finally {
|
|
142
|
+
clearTimeout(timeout)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { signature: getTransactionSignature(signedTransaction.signatures, from) }
|
|
146
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
interface TransactionHistoryItem {
|
|
2
|
+
signature: string
|
|
3
|
+
slot: number
|
|
4
|
+
blockTime: number | null
|
|
5
|
+
err: unknown | null
|
|
6
|
+
memo: string | null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const DEFAULT_RPC = 'https://api.devnet.solana.com'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fetches tx history via raw JSON-RPC (avoids @solana/kit transport issues in browser).
|
|
13
|
+
*/
|
|
14
|
+
export async function getTransactionHistory(
|
|
15
|
+
address: string,
|
|
16
|
+
limit = 10,
|
|
17
|
+
rpcUrl?: string
|
|
18
|
+
): Promise<TransactionHistoryItem[]> {
|
|
19
|
+
const rpc = rpcUrl ?? DEFAULT_RPC
|
|
20
|
+
const res = await fetch(rpc, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: { 'Content-Type': 'application/json' },
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
jsonrpc: '2.0',
|
|
25
|
+
id: 1,
|
|
26
|
+
method: 'getSignaturesForAddress',
|
|
27
|
+
params: [address, { limit, commitment: 'confirmed' }],
|
|
28
|
+
}),
|
|
29
|
+
})
|
|
30
|
+
const data = await res.json()
|
|
31
|
+
if (!data.result) return []
|
|
32
|
+
return data.result.map((sig: Record<string, unknown>) => ({
|
|
33
|
+
signature: sig.signature as string,
|
|
34
|
+
slot: sig.slot as number,
|
|
35
|
+
blockTime: (sig.blockTime as number) ?? null,
|
|
36
|
+
err: sig.err ?? null,
|
|
37
|
+
memo: (sig.memo as string) ?? null,
|
|
38
|
+
}))
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StrictMode } from 'react'
|
|
2
|
+
import { createRoot } from 'react-dom/client'
|
|
3
|
+
import App from './App.tsx'
|
|
4
|
+
import { Providers } from './components/providers.tsx'
|
|
5
|
+
import './index.css'
|
|
6
|
+
|
|
7
|
+
createRoot(document.getElementById('root')!).render(
|
|
8
|
+
<StrictMode>
|
|
9
|
+
<Providers>
|
|
10
|
+
<App />
|
|
11
|
+
</Providers>
|
|
12
|
+
</StrictMode>,
|
|
13
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
/* Linting */
|
|
16
|
+
"strict": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"erasableSyntaxOnly": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedSideEffectImports": true
|
|
22
|
+
},
|
|
23
|
+
"include": ["src"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
/* Bundler mode */
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
/* Linting */
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"erasableSyntaxOnly": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"noUncheckedSideEffectImports": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["vite.config.ts"]
|
|
22
|
+
}
|