init: inital commit

This commit is contained in:
2026-07-23 13:06:41 +05:30
commit cd412b0eef
6 changed files with 304 additions and 0 deletions

34
.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules
# output
out
dist
*.tgz
# code coverage
coverage
*.lcov
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

15
README.md Normal file
View File

@@ -0,0 +1,15 @@
# daily-digest
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run index.ts
```
This project was created using `bun init` in bun v1.2.19. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.

30
bun.lock Normal file
View File

@@ -0,0 +1,30 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "daily-digest",
"dependencies": {
"dayjs": "^1.11.20",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
"@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
"dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
}
}

181
index.ts Normal file
View File

@@ -0,0 +1,181 @@
import { $ } from "bun"
import dayjs from "dayjs"
import "dayjs/locale/es"
const TOPIC = "daily-digest"
const TOKEN = process.env.NTFY_TOKEN
if (!TOKEN) {
console.error("ntfy token not set")
process.exit(1)
}
const API =
"https://api.frankfurter.app/latest?from=USD&to=INR"
async function getUSD() {
const res = await fetch(API)
if (!res.ok) {
throw new Error(`Exchange API failed: ${res.status}`)
}
const data = await res.json()
const rate = data.rates.INR
if (typeof rate !== "number") {
throw new Error("Invalid exchange rate")
}
const helions = (rate / 100).toFixed(2)
return `**📈 Exchange Rate**
$1 = ₹${rate.toFixed(2)} = ⚙${helions}
`
}
async function getUsage() {
//
// CPU LOAD
//
const loadavg = await $`cat /proc/loadavg`.text()
const [load1] = loadavg.trim().split(" ")
//
// MEMORY
//
const memRaw = await $`free -b`.text()
const memLine = memRaw
.split("\n")
.find((line) => line.startsWith("Mem:"))
if (!memLine) {
throw new Error("Failed to parse memory info")
}
const [
,
totalMem,
usedMem,
] = memLine.trim().split(/\s+/)
//
// DISK
//
const diskRaw = await $`df -B1 /`.text()
const diskLine = diskRaw
.split("\n")[1]
if (!diskLine) {
throw new Error("Failed to parse disk info")
}
const [
,
totalDisk,
usedDisk,
] = diskLine.trim().split(/\s+/)
const temp = await $`vcgencmd measure_temp`.text()
const tempData = temp.split("=")[1].replace("'", "°")
//
// HELPERS
//
function formatBytesIEC(bytes: number) {
const units = ["B", "KiB", "MiB", "GiB", "TiB"]
let i = 0
let value = bytes
while (value >= 1024 && i < units.length - 1) {
value /= 1024
i++
}
return `${value.toFixed(1)} ${units[i]}`
}
//
// OUTPUT
//
return `**💾 Usage**
• **CPU:** ${load1}
• **Memory:** ${formatBytesIEC(Number(usedMem))} / ${formatBytesIEC(Number(totalMem))}
• **Disk:** ${formatBytesIEC(Number(usedDisk))} / ${formatBytesIEC(Number(totalDisk))}
• **Temperature:** ${tempData}
`
}
async function getWeather() {
const res = await fetch(`https://wttr.in/Bengaluru?format="%c%C| %f | %h | %m | %w | %p"`)
const data = await res.text()
const [weather, temp, humidity, moon, winds, preci] = data.replace(/\"/g, '').split("|")
return `**🌥️ Weather Report**
• **Weather:** ${weather}
• **Temperature:** ${temp}
• **Humidity:** ${humidity}
• **Moon Phase:** ${moon}
• **Winds:** ${winds}
• **Precipitation:** ${preci}
`
console.log(data)
}
async function main() {
const usd = await getUSD()
const usage = await getUsage()
const weather = await getWeather()
const message = `Good Morning, SilicoFlare!
Today is **${dayjs().format("dddd, DD MMMM YYYY")}**.
Hoy es **${dayjs().locale("es").format("dddd, D [de] MMMM [de] YYYY")}**.
${weather}
${usd}
${usage}
Have a great day!`
const ntfy = await fetch(
`https://ntfy.hy-pr.link/${TOPIC}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
Title: `Daily Digest for ${dayjs().format("YYYY-MM-DD")}`,
Markdown: "yes",
Tags: "calendar"
},
body: message,
},
)
if (!ntfy.ok) {
throw new Error(`ntfy failed: ${ntfy.status}`)
}
console.log("Notification sent at " + dayjs().format("YYYY-MM-dd HH:mm:ss"))
}
main().catch((err) => {
console.error(err)
process.exit(1)
})

15
package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "daily-digest",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"dayjs": "^1.11.20"
}
}

29
tsconfig.json Normal file
View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}