Skip to content

Commit a09b105

Browse files
committed
Validate env using zod and load using bun
1 parent b9cdb1b commit a09b105

File tree

7 files changed

+27
-34
lines changed

7 files changed

+27
-34
lines changed
File renamed without changes.

bun.lock

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"": {
55
"name": "sleep-tracker",
66
"dependencies": {
7-
"dotenv-safe": "^9.1.0",
87
"geo-tz": "^8.1.4",
98
"googleapis": "^160.0.0",
109
"moment": "^2.30.1",
@@ -15,7 +14,6 @@
1514
"@biomejs/biome": "2.2.4",
1615
"@tsconfig/bun": "^1.0.8",
1716
"@types/bun": "^1.2.22",
18-
"@types/dotenv-safe": "^9.1.0",
1917
"@types/node": "^24.5.2",
2018
"@types/pug": "^2.0.10",
2119
"ultracite": "5.4.4",
@@ -159,8 +157,6 @@
159157

160158
"@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
161159

162-
"@types/dotenv-safe": ["@types/dotenv-safe@9.1.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "dotenv": ">=8.2.0" } }, "sha512-cL9PCogrlu+uDtq3M9qvAs+G5rfHwx+untcZGzA3fX8++NVdg9f01zdA175h55TstsEFRogXMUObo6QDduc/5w=="],
163-
164160
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
165161

166162
"@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="],
@@ -231,10 +227,6 @@
231227

232228
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
233229

234-
"dotenv": ["dotenv@8.6.0", "", {}, "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g=="],
235-
236-
"dotenv-safe": ["dotenv-safe@9.1.0", "", { "peerDependencies": { "dotenv": ">= 8.2.0" } }, "sha512-2qwVAnUN+EDpu41pIK1XiJpHXKHV9Dnti3cE1EnUXT1/BV5+B7xuSZtgZ/4LExkCpp5F6BGikraezQL+8hKCOA=="],
237-
238230
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
239231

240232
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
@@ -437,8 +429,6 @@
437429

438430
"zod": ["zod@4.1.11", "", {}, "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg=="],
439431

440-
"@types/dotenv-safe/@types/node": ["@types/node@17.0.24", "", {}, "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g=="],
441-
442432
"bun-types/@types/node": ["@types/node@17.0.24", "", {}, "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g=="],
443433

444434
"shapefile/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@
1010
"@biomejs/biome": "2.2.4",
1111
"@tsconfig/bun": "^1.0.8",
1212
"@types/bun": "^1.2.22",
13-
"@types/dotenv-safe": "^9.1.0",
1413
"@types/node": "^24.5.2",
1514
"@types/pug": "^2.0.10",
1615
"ultracite": "5.4.4"
1716
},
1817
"dependencies": {
19-
"dotenv-safe": "^9.1.0",
2018
"geo-tz": "^8.1.4",
2119
"googleapis": "^160.0.0",
2220
"moment": "^2.30.1",

src/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import z from "zod";
2+
3+
const ProcessEnvSchema = z.object({
4+
API_KEY: z.string().min(1),
5+
SPREADSHEET_ID: z.string().min(1),
6+
SPREADSHEET_RANGE: z.string().min(1),
7+
PUSHBULLET_API_KEY: z.string().min(1),
8+
});
9+
10+
export const env = ProcessEnvSchema.parse(process.env);

src/controller.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
22
import type { BunRequest } from "bun";
33
import moment from "moment-timezone";
44
import { successResponse } from "./apiUtils";
5+
import { env } from "./config";
56
import { ApiError } from "./error";
67
import { sendEntryNotification } from "./notifications";
78
import {
@@ -33,16 +34,16 @@ export const logSleepRoute = async (req: BunRequest) => {
3334

3435
const result: GoogleSheetsAppendUpdates = await append(
3536
sheetsObj,
36-
process.env.SPREADSHEET_ID!,
37-
process.env.SPREADSHEET_RANGE!,
37+
env.SPREADSHEET_ID,
38+
env.SPREADSHEET_RANGE,
3839
valuesToAppend
3940
).catch((error) => {
4041
throw new ApiError("Failed to append rows to Google Sheet", error);
4142
});
4243

4344
const updatedRows = await getObjectArrayHeader(
4445
sheetsObj,
45-
process.env.SPREADSHEET_ID!,
46+
env.SPREADSHEET_ID,
4647
result.updatedRange
4748
).catch((error) => {
4849
throw new ApiError("Failed to retrieve row after writing", error);
@@ -62,8 +63,8 @@ export const getSleepRoute = async () => {
6263

6364
const result: SheetsSleepEntry[] = await getObjectArray(
6465
sheetsObj,
65-
process.env.SPREADSHEET_ID!,
66-
process.env.SPREADSHEET_RANGE!
66+
env.SPREADSHEET_ID,
67+
env.SPREADSHEET_RANGE
6768
).catch((error: Error) => {
6869
throw new ApiError("Failed to retrieve rows", error);
6970
});
@@ -78,8 +79,8 @@ export const getLastSleep = async () => {
7879

7980
const result: SheetsSleepEntry[] = await getObjectArray(
8081
sheetsObj,
81-
process.env.SPREADSHEET_ID!,
82-
process.env.SPREADSHEET_RANGE!
82+
env.SPREADSHEET_ID,
83+
env.SPREADSHEET_RANGE
8384
).catch((error: Error) => {
8485
throw new ApiError("Failed to retrieve rows", error);
8586
});
@@ -115,8 +116,8 @@ export const replaceLastSleepRoute = async (req: BunRequest) => {
115116

116117
const rows = await getArray(
117118
sheetsObj,
118-
process.env.SPREADSHEET_ID!,
119-
process.env.SPREADSHEET_RANGE!
119+
env.SPREADSHEET_ID,
120+
env.SPREADSHEET_RANGE
120121
).catch((error: Error) => {
121122
throw new ApiError("Failed to retrieve rows", error);
122123
});
@@ -125,7 +126,7 @@ export const replaceLastSleepRoute = async (req: BunRequest) => {
125126

126127
const result: GoogleSheetsAppendUpdates = await update(
127128
sheetsObj,
128-
process.env.SPREADSHEET_ID!,
129+
env.SPREADSHEET_ID,
129130
rangeToUpdate,
130131
valuesToAppend
131132
).catch((error) => {
@@ -134,7 +135,7 @@ export const replaceLastSleepRoute = async (req: BunRequest) => {
134135

135136
const updatedRows = await getObjectArrayHeader(
136137
sheetsObj,
137-
process.env.SPREADSHEET_ID!,
138+
env.SPREADSHEET_ID,
138139
result.updatedRange
139140
).catch((error) => {
140141
throw new ApiError("Failed to retrieve row after updating", error);
@@ -192,7 +193,7 @@ const getSleepEntryFromGeolocationPosition = (
192193
export const checkRequestApiKey = (req: BunRequest) => {
193194
const { searchParams } = new URL(req.url);
194195
const apiKey = searchParams.get("apiKey");
195-
if (apiKey != process.env.API_KEY) {
196+
if (apiKey != env.API_KEY) {
196197
throw new ApiError("Invalid API key");
197198
}
198199
};

src/index.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import path from "node:path";
21
import { serve } from "bun";
3-
import dotenv from "dotenv-safe";
42
import { checkReminderLoop } from "./checkReminderLoop";
53
import {
64
checkRequestApiKey,
@@ -12,11 +10,6 @@ import {
1210
import { handleError } from "./error";
1311
import sleepHtml from "./views/sleep.html";
1412

15-
dotenv.config({
16-
path: path.resolve(__dirname, "..", "secret/.env"),
17-
example: path.resolve(__dirname, "..", "secret/.env.example"),
18-
});
19-
2013
const server = serve({
2114
port: "8000",
2215
routes: {
@@ -27,7 +20,7 @@ const server = serve({
2720
},
2821
async GET(req) {
2922
checkRequestApiKey(req);
30-
return getSleepRoute(req);
23+
return getSleepRoute();
3124
},
3225
},
3326
"/api/sleep/replace": {
@@ -39,7 +32,7 @@ const server = serve({
3932
"/api/sleep/last": {
4033
async GET(req) {
4134
checkRequestApiKey(req);
42-
return getLastSleepRoute(req);
35+
return getLastSleepRoute();
4336
},
4437
},
4538
"/": sleepHtml,

src/notifications.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { env } from "./config";
12
import { ApiError } from "./error";
23
import type { Notification, SheetsSleepEntry } from "./types";
34
import { millisecondsToHours, sheetsSleepEntryIsStop } from "./utils";
@@ -7,7 +8,7 @@ const sendNotification = async (notification: Notification) => {
78
await fetch("https://api.pushbullet.com/v2/pushes", {
89
method: "POST",
910
headers: {
10-
"Access-Token": process.env.PUSHBULLET_API_KEY!,
11+
"Access-Token": env.PUSHBULLET_API_KEY,
1112
"Content-Type": "application/json",
1213
},
1314
body: JSON.stringify({

0 commit comments

Comments
 (0)