Add server/addresses.js

This commit is contained in:
2026-08-29 10:17:46 +00:00
parent ed5213f00b
commit b13136b6e4
+129
View File
@@ -0,0 +1,129 @@
const crypto = require('crypto')
const fs = require('fs/promises')
const storePath = '/data/store.json'
async function readStore() {
try {
const data = await fs.readFile(storePath, 'utf8')
return JSON.parse(data)
} catch (error) {
if (error.code === 'ENOENT') {
return {}
}
throw error
}
}
async function writeStore(store) {
const temporaryPath =
`${storePath}.${crypto.randomBytes(8).toString('hex')}.tmp`
await fs.writeFile(
temporaryPath,
JSON.stringify(store, null, 2) + '\n',
{
mode: 0o600,
},
)
await fs.rename(temporaryPath, storePath)
}
function normalizeAddress(address) {
if (typeof address !== 'string') {
return null
}
const normalized = address.trim()
if (!normalized) {
return null
}
return normalized
}
function normalizeLabel(label) {
if (typeof label !== 'string') {
return undefined
}
const normalized = label.trim()
return normalized || undefined
}
async function listAddresses() {
const store = await readStore()
return Array.isArray(store.addresses)
? store.addresses
: []
}
async function addAddress(address, label) {
const normalizedAddress = normalizeAddress(address)
if (!normalizedAddress) {
throw new Error('Bitcoin address is required')
}
const addresses = await listAddresses()
if (addresses.some((item) => item.address === normalizedAddress)) {
throw new Error('Bitcoin address is already being watched')
}
const entry = {
address: normalizedAddress,
}
const normalizedLabel = normalizeLabel(label)
if (normalizedLabel) {
entry.label = normalizedLabel
}
const store = await readStore()
store.addresses = [...addresses, entry]
await writeStore(store)
return entry
}
async function removeAddress(address) {
const normalizedAddress = normalizeAddress(address)
if (!normalizedAddress) {
throw new Error('Bitcoin address is required')
}
const store = await readStore()
const addresses = Array.isArray(store.addresses)
? store.addresses
: []
const filtered = addresses.filter(
(item) => item.address !== normalizedAddress,
)
if (filtered.length === addresses.length) {
throw new Error('Bitcoin address is not being watched')
}
store.addresses = filtered
await writeStore(store)
return true
}
module.exports = {
listAddresses,
addAddress,
removeAddress,
}