4
Konfigurasi Environment dan Binding
Repository ini memisahkan konfigurasi ke dalam dua kanal yang tidak saling menggantikan. Tiga rahasia pihak ketiga masuk sebagai environment variable statis lewat modul $env/static/private, sedangkan database D1 hanya bisa dijangkau sebagai binding runtime lewat platform.env.DB. .env.example mendaftarkan tepat tiga kunci, semuanya bernilai string kosong: OPENAI_API_KEY, GITHUB_API_KEY, dan TELEGRAM_API_KEY (.env.example:1-31).
graph LR
ENVFILE[".env.example<br/>OPENAI_API_KEY / GITHUB_API_KEY / TELEGRAM_API_KEY"]
STATIC["$env/static/private"]
CLIENT["new OpenAI({ apiKey })"]
HDR["headers['Authorization']"]
UNUSED["TELEGRAM_API_KEY tidak dipakai"]
WRANGLE["wrangler.toml<br/>[[d1_databases]] binding = DB"]
PENV["platform.env.DB"]
D1[("tabel roasts")]
ENVFILE --> STATIC
STATIC -->|"OPENAI_API_KEY"| CLIENT
STATIC -->|"GITHUB_API_KEY"| HDR
STATIC -.->|"TELEGRAM_API_KEY"| UNUSED
WRANGLE --> PENV
PENV -->|"prepare().bind()"| D1
style ENVFILE fill:#f59e0b,color:#000
style STATIC fill:#f59e0b,color:#000
style WRANGLE fill:#f59e0b,color:#000
style PENV fill:#f59e0b,color:#000
style CLIENT fill:#8b5cf6,color:#fff
style HDR fill:#8b5cf6,color:#fff
style D1 fill:#336791,color:#fff
style UNUSED fill:#dc2626,color:#fff
%% fig: Dua kanal konfigurasi menuju kode handler
%% desc: Rahasia dari .env.example mengalir ke $env/static/private, sementara binding DB dari wrangler.toml muncul sebagai platform.env.DB lalu dipakai untuk query ke tabel roasts.| Nama | Dideklarasikan di | Dibaca di | Kanal |
|---|---|---|---|
OPENAI_API_KEY | .env.example:12 | src/routes/llama/+server.js:1-73 | environment statis ($env/static/private) |
GITHUB_API_KEY | .env.example:24 | src/routes/llama/+server.js:49-515 | environment statis ($env/static/private) |
TELEGRAM_API_KEY | .env.example:36 | tidak ada pemakaian | environment statis, tidak terpakai |
DB | wrangler.toml:28-317 | src/routes/llama/+server.js:40-448 | binding runtime (platform.env.DB) |
Rahasia build-time
Berkas .env.example adalah satu-satunya berkas environment yang lolos dari .gitignore. Pola .env dan .env.* diabaikan, sementara .env.example dan .env.test dikecualikan (.gitignore:13-17). Nilai rahasia lokal juga tidak pernah masuk lewat .dev.vars, yang ikut diabaikan bersama direktori .wrangler (.gitignore:23-25). Jadi berkas yang di-commit hanya memuat nama kunci, bukan nilainya.
Pemetaan ke $env/static/private
Handler POST di src/routes/llama/+server.js mengambil dua kunci pertama dari modul $env/static/private lalu langsung membangun satu instance OpenAI dengan apiKey: OPENAI_API_KEY (src/routes/llama/+server.js:1-73). Instance client itu dibuat di luar fungsi handler, tepat setelah import, sehingga nilainya terikat pada saat modul dimuat, bukan dibaca ulang per request.
GITHUB_API_KEY diperlakukan berbeda. Header Authorization hanya ditambahkan kalau nilainya truthy (src/routes/llama/+server.js:49-515), dan dihapus kembali ketika percobaan dengan token gagal (src/routes/llama/+server.js:73-769). Artinya kunci ini opsional: tanpa kunci, permintaan ke api.github.com tetap berjalan tanpa header otorisasi.
TELEGRAM_API_KEY tidak dirujuk di kode mana pun; satu-satunya kemunculannya adalah deklarasi kosong di .env.example (.env.example:36). Kunci itu tersedia untuk dipakai, tetapi belum ada jalur yang membacanya.
Binding D1 DB
Binding D1 dideklarasikan sebagai array [[d1_databases]] dengan binding = "DB", database_name = "githubroast", dan database_id = "e43f5850-f45d-4d01-a3fb-1c1f0b3da4bb" (wrangler.toml:28-317). Nama aplikasi di wrangler.toml juga githubroast, sama dengan database_name yang diikat (wrangler.toml:2-410).
Di runtime, binding itu hanya hadir sebagai platform.env.DB. Semua akses database di handler melewati jalur tersebut: pembacaan cache lewat SELECT * FROM roasts WHERE gh_username = ? AND language = ? (src/routes/llama/+server.js:40-448) dan penulisan hasil lewat INSERT INTO roasts (gh_username, response, created_at, country, ip_address, language) (src/routes/llama/+server.js:195-20611). Tidak ada pembacaan rahasia lewat platform.env; kedua kanal tetap terpisah.
wrangler.toml sengaja tidak mendefinisikan [vars]. Baris itu dikomentari lengkap dengan catatan agar data sensitif disimpan sebagai secret (wrangler.toml:13-1912). Jangan menambahkan OPENAI_API_KEY ke [vars] dalam bentuk plaintext.
Kapan binding aktif
Binding hanya terpasang ketika wrangler membaca wrangler.toml. Berkas itu menunjuk direktori keluaran .svelte-kit/cloudflare sebagai pages_build_output_dir (wrangler.toml:2-410), yang dihasilkan oleh adapter() dari @sveltejs/adapter-cloudflare di svelte.config.js (svelte.config.js:1-1013).
graph TD
SC["svelte.config.js adapter()"]
OUT[".svelte-kit/cloudflare"]
PREV["npm run preview<br/>wrangler pages dev"]
DEP["npm run deploy<br/>wrangler pages deploy"]
WT["wrangler.toml<br/>binding = DB"]
SC --> OUT
OUT --> PREV
OUT --> DEP
WT --> PREV
WT --> DEP
style SC fill:#f59e0b,color:#000
style WT fill:#f59e0b,color:#000
style OUT fill:#8b5cf6,color:#fff
style PREV fill:#2d7d46,color:#fff
style DEP fill:#2d7d46,color:#fff
%% fig: Artefak build dan dua jalur yang memasang binding
%% desc: adapter-cloudflare menulis ke .svelte-kit/cloudflare, lalu wrangler pages dev dan wrangler pages deploy memasang binding DB dari wrangler.toml pada artefak yang sama.Skrip di package.json memperlihatkan pemisahan itu: dev menjalankan vite dev, preview menjalankan wrangler pages dev, dan deploy menjalankan wrangler pages deploy (package.json:6-1114). Hanya dua perintah wrangler yang membaca wrangler.toml.
vite.config.js tidak menyentuh environment sama sekali. Berkas itu hanya menambahkan plugin lokal-vite-plugin dengan tunnelName: 'GitHub Roast' dan lanAddress: 'github-roast.local' (vite.config.js:5-1315).
⚠️ Deploy pertama lewat integrasi Git Cloudflare Pages akan gagal. Menurut
README.md, deployment awal harus diulang setelah environment produksi diisi nilai terenkripsi di dashboard (README.md:14-1716). Untuk urutan deploy dan perintah tooling, lihat Deployment ke Cloudflare Pages dan Perintah dan Tooling.