Commit Graph
249 Commits
Author SHA1 Message Date
asepharyana 890444fed6 chore(plan): fix stale src/db doc refs + register s3-routing test
- 8 repository/port doc comments pointed at long-gone src/db/*
  layout; now reference the real drizzle repository paths
- test:unit and test:s3 now include test/s3-routing.test.ts
  (was passing but never wired into any script)
2026-09-14 18:19:22 +07:00
asepharyana 3a9052d551 refactor(plan): delete unused DTO modules bucket, file, s3
Zero importers in src/ and test/ (verified by grep). Live DTOs:
auth (authenticate use-case + controller) and upload (upload-file
use-case). Build + biome green; full test:unit green.
2026-09-14 18:17:55 +07:00
asepharyana e610f1ca21 refactor(plan): unify bucket validation + lock root-verb routing
- web-api create-bucket and s3 virtual-host now use BucketNameSchema
  (single canonical validator; no inline regex left in src/)
- routes '/': HEAD/DELETE/POST now check shouldHandleS3 with headers
  like every other branch (non-S3 -> 404, never S3-direct blind)
- s3-routing.test.ts: 3 new tests locking the fixed root verbs
2026-09-14 18:17:18 +07:00
asepharyana da7fca9fdc refactor(plan): delete dead use-cases s3-object, manage-bucket, multipart-upload, get-file
Verified zero importers in src/ and test/ (only a doc comment
mentions manage-bucket). Live use-cases: authenticate (auth
controller) and upload-file (upload + web-api controllers); S3
handlers call repositories directly. Build + biome + full
test:unit (28 files) green.
2026-09-14 18:12:21 +07:00
asepharyana 2d20365d56 test(integration): fix stale assertions exposed by refactor
- files.test.ts: 302-redirect expectation replaced with 200-proxy
  assertion (bot token only in server-side fetch, never Location)
- deploy-config.test.ts: retarget from deleted .gitea workflow to
  .github/workflows/deploy.yml (CI migrated to GitHub Actions in
  811a688); asserts nix build + VPS deploy shape
2026-09-14 18:07:23 +07:00
asepharyana bd4cf8b285 refactor(fase1b): unify upload/download via use-case + proxy download
- upload-file use-case is now the single save path with dedup policy
  (hash / bucket-key / none), partPrefix + signatureBuffer inputs,
  fileHash in UploadOutput, and owned temp-file cleanup; pass temp
  path (not open stream) to telegram service for testability
- upload-controller (multipart + JSON) and web-api upload delegate
  to the use-case; JSON body via JsonUploadPayloadSchema; responses
  built from use-case output via buildUploadResponse
- web-api download 302 redirect -> proxy stream (closes bot_token
  leak); shared CORS + sanitizeFilenameHeader
- file-controller drops double file-info cache layer (pool caches)
- bot handler uses DI singletons instead of direct construction
- get-file RedirectRetrieval.redirectUrl marked deprecated, URL via
  shared builder; chunked-storage URL via buildTelegramFileUrl
  (no inline api.telegram.org/file/bot left in src/)
2026-09-14 18:03:37 +07:00
asepharyana 7d5b8154a4 Merge branch 'refactor/fase1c-fondasi' into refactor/teleuploader-full 2026-09-14 17:43:19 +07:00
asepharyana cba2160acb test(fase1-s3): retarget source-reading asserts to split s3/ modules
PUT streaming assert now reads s3/s3-object-write.ts and UploadPart
assert reads s3/s3-multipart-handlers.ts (s3-controller.ts is a thin
facade since the split). No behavior change.
2026-09-14 17:28:22 +07:00
asepharyana b164b8826f refactor(fase1c): routing S3 fixes + auth/swagger/index/env
- routes: GET / teruskan headers ke shouldHandleS3; OPTIONS jawab
  204 CORS generik bila bukan S3, handleS3Direct bila S3; komentar
  bypass rate-limit S3 dipertahankan (registry abort pada 429)
- auth-controller: readLoginBody via LoginBodySchema; handleMe sederhanakan
  (getAuthSession sudah cek bearer); import AuthSession dari dto
- swagger: pindah src/routes -> src/interfaces/http/swagger; tambah path
  auth, /api/v1, /{bucket}, /{bucket}/{key}; version dari config.appVersion
- index: unref ketiga setInterval agar tak menahan process
- env: PORT fail-fast via PositiveIntSchema (default 4000 bila tak diset);
  log config turun ke debug
- metrics: dokumentasikan uploadThroughput/queueSize/botUtilization
- test baru test/s3-routing.test.ts (GET / S3 vs home, OPTIONS 204 CORS)
2026-09-14 17:26:03 +07:00
asepharyana d323260ed5 refactor(fase1-s3): split s3-controller into s3/ modules + guards 2026-09-14 17:25:07 +07:00
asepharyana 5d01a9405f refactor(fase0): shared scaffold — crypto, file-url, schemas, test splits
- Add zod dep; new src/shared/validation/schemas.ts (BucketName,
  JsonUploadPayload, LoginBody, DeleteObjects, CompleteMultipart,
  clampMaxKeys, parseOrNull) + test/validation.test.ts
- Dedup timingSafeCompare -> src/shared/utils/crypto.ts (auth
  middleware, authenticate use-case, s3/auth now import it)
- Dedup AuthSession -> single type in dto/auth.ts
- Dedup telegram file URL builder + filename sanitizer to shared
  modules (file-controller now imports the canonical ones)
- Remove duplicate controllers/home.html (canonical: src/home.html)
- Fix stale bootstrap mocks to real module paths; bootstrap now
  asserts public GET vs guarded POST separately
- Fix health assertion to include version field
- package.json: test -> test:unit alias; new test:quarantine for
  network/live tests; register previously unlisted test files
2026-09-14 17:09:52 +07:00
asepharyana f4b30cef0c chore(gitignore): ignore Ruflo runtime, secrets, and scaffolding 2026-09-14 16:13:46 +07:00
semantic-release-bot a4bb860526 chore(release): 1.2.2
## [1.2.2](https://github.com/asepharyana/TeleUploader/compare/v1.2.1...v1.2.2) (2026-09-05)

### Bug Fixes

* **health:** resolve app version in Nix bundle at runtime ([6797dba](https://github.com/asepharyana/TeleUploader/commit/6797dbada27873b14c064e238589e61ad3ecb67c))
v1.2.2
2026-09-05 18:14:18 +00:00
asepharyana 6797dbada2 fix(health): resolve app version in Nix bundle at runtime
The health endpoint was returning version 0.0.0 because readPackageVersion()
tried import.meta.require on a JSON path that Bun cannot bundle and the
package.json never shipped into the Nix store (installPhase only copied
dist/, home.html, schema.sql).

- flake.nix installPhase now copies package.json into $out/share/teleuploader/
- readPackageVersion() reads import.meta.dir/../package.json (bundle) or
  process.cwd()/package.json (dev) via readFileSync at runtime

Verified local resolution to 1.2.1; after this fixes deploy it will expose
the live semver on GET /health.
2026-09-06 01:13:48 +07:00
asepharyana 2ca1e67435 ci(release): add actions: write for deploy dispatch
dispatch.mjs dispatches deploy.yml via workflow_dispatch, which requires
actions: write. Without it the success hook hit HTTP 403 (Resource not
accessible by integration), same trap as the mytheclipse pipeline, and the
auto deploy never ran for v1.2.1.
2026-09-06 01:04:00 +07:00
semantic-release-bot ab955afad4 chore(release): 1.2.1
## [1.2.1](https://github.com/asepharyana/TeleUploader/compare/v1.2.0...v1.2.1) (2026-09-05)

### Bug Fixes

* **ci:** bump only TeleUploader flake version, not Bun overlay ([f442797](https://github.com/asepharyana/TeleUploader/commit/f442797a86e845853c28dc22432a530560434488))
v1.2.1
2026-09-05 17:55:02 +00:00
asepharyana f442797a86 fix(ci): bump only TeleUploader flake version, not Bun overlay
prepare.mjs previously replaced the FIRST version="X" string in flake.nix,
which is the Bun overlay override (line ~17), not the TeleUploader package
version (pname = "teleuploader", line ~30). Store path derives from the
TeleUploader version, so the Bun override got clobbered to the app version
while the store path stayed at 1.1.1 -> deploy reused the old derivation and
the VPS profile never advanced.

Now prepare.mjs anchors on pname = "teleuploader" and bumps that block only,
leaving the Bun 1.3.14 override intact. Verified: flake.nix keeps
bun version=1.3.14, teleuploader version becomes the semver-version.
Also restores bun overlay version=1.3.14 (was overwritten to 1.2.0).
2026-09-06 00:54:33 +07:00
asepharyana 6ca92fcc21 ci(release): dispatch deploy.yml on release
GitHub disables workflow re-triggering for GITHUB_TOKEN pushes (the release
commit), so the push trigger in deploy.yml never runs for release commits.
This adds @semantic-release/exec successCmd -> .semrel/dispatch.mjs which
dispatches deploy.yml for every released version, completing the auto loop:
fix/feat -> semantic-release bump -> release commit+tag -> deploy.
2026-09-06 00:47:44 +07:00
semantic-release-bot 8043247057 chore(release): 1.2.0
# [1.2.0](https://github.com/asepharyana/TeleUploader/compare/v1.1.1...v1.2.0) (2026-09-05)

### Features

* **health:** expose app version in /health response ([0782d0f](https://github.com/asepharyana/TeleUploader/commit/0782d0f993a033bb9d84fa1f876e29486751889d))
v1.2.0
2026-09-05 17:43:08 +00:00
asepharyana 0782d0f993 feat(health): expose app version in /health response
Reads application version from package.json via env.ts readPackageVersion()
and returns it alongside status so deploy verification is instant:
curl https://upload.asepharyana.my.id/health -> {status: ok, version: X.Y.Z}
2026-09-06 00:42:39 +07:00
asepharyana bdda2d9884 docs(readme): document auto semantic versioning 2026-09-06 00:40:11 +07:00
asepharyana 357a1ae41b ci(release): add workflow_dispatch for manual releases 2026-09-06 00:39:09 +07:00
asepharyana f16161d38a ci(semantic-release): auto versioning via semantic-release
- .releaserc.json: commit-analyzer + release-notes-generator + changelog
  + exec (prepare) + git + github plugins.
- .semrel/prepare.mjs: syncs next release version into package.json AND
  flake.nix before the release commit — guarantees a fresh Nix store path
  on every deploy (fixes the trap where a source change without a version
  bump reused the same store path and CI silently deployed stale code).
- release.yml: runs semantic-release on main push (GITHUB_TOKEN,
  isolated /tmp/sr-tools install so package.json/bun.lock stay clean).
- Release commit (no [skip ci]) triggers deploy.yml → auto build+deploy.
- Baseline tag v1.1.1 backfilled at current HEAD.
2026-09-06 00:36:01 +07:00
asepharyana 9743fbf4b7 chore(release): bump teleuploader 1.1.0 -> 1.1.1
Force a fresh Nix store path so the Buffer-from-gzip fix actually reaches
the VPS. The 1.1.0 store path hash was reused by Nix (identical derivation
inputs from Nix's perspective), so a version bump guarantees the fixed
dist bundle is copied and the profile is switched.
v1.1.1
2026-09-06 00:17:34 +07:00
asepharyana d296e0ebcf fix(upload): wrap gzip chunk output in Buffer so Telegraf uploads work
Root cause of '400: Bad Request: there is no document in the request' on
chunked uploads of compressible files (MP4, zip, text, etc.):
Bun.gzipSync() returns a plain Uint8Array, NOT a Buffer. Telegraf
(sendDocument/sendVideo) only recognises Buffer/Blob/stream sources as
file uploads — a plain Uint8Array produces an empty multipart body and
Telegram rejects the request.

Verified via isolated forwardToStorage probes:
- raw Buffer chunk (.bin, MP4) -> OK
- plain Uint8Array chunk -> FAIL: there is no document
- Buffer.from(gzip) chunk -> OK (after fix)
- .gz extension on Uint8Array did NOT help (rules out MIME/extension)

This only affected chunked uploads of compressible files; incompressible
files (random .bin) worked by accident because gzip didn't shrink them so
the raw Buffer was forwarded unchanged.
2026-09-06 00:11:00 +07:00
asepharyana 765b3588a3 fix(files): serve /f/:public_id as CORS-enabled 200 stream instead of 302 redirect to Telegram CDN
Fixes browser CORS error when frontend fetches audio via Web Audio API
(decodeAudio): the 302 redirected to api.telegram.org which lacks
Access-Control-Allow-Origin, blocking fetch/XHR. Now the file bytes are
proxied server-side with CORS headers + proper Content-Type, so the
browser stays same-origin. Also adds CORS to chunked/archive streams.
2026-08-30 17:54:41 +07:00
asepharyana 94c782ef23 fix(runtime): revert Bun 1.4.0 -> 1.3.14 to fix Telegram sendDocument socket-close
Bun 1.4.0 (upgraded 0deb607) breaks Telegraf 4.15 sendDocument with
'The socket connection was closed unexpectedly' — reproduced with the same
libraries: Telegraf 4.15.0 on Bun 1.4.0 fails exactly like prod, on Bun 1.3.14
it returns a proper HTTP response. All uploads 500 since the upgrade deployed
(Aug 29 11:06). Pin flake nix override + CI bun-version to 1.3.14.
2026-08-30 15:18:41 +07:00
asepharyana 0deb6072dd chore: upgrade runtime to Bun 1.4.0
- Update Nix flake.nix overlay to use Bun 1.4.0 (overrideAttrs)
- Update CI (setup-bun) to pin bun-version: 1.4.0
- Update package.json packageManager/Dockerfile/vercel.json
- sha256: sha256:Poy0vf7yJ/hzk33QiQj5gnshI5Q7dfbaMD7xgwiyDKw=
2026-08-29 11:05:13 +07:00
asepharyana 77340f63ae test: expand unit test coverage to all S3 edge cases; fix stale tests
Add comprehensive unit tests and repair stale tests that referenced the
old (pre-refactor) src/utils/* layout which no longer exists:

- s3-range: expand to 25 cases (suffix, clamping, malformed, zero-size,
  invalid totals, content-range formatting)
- s3-object-stream: rewrite against the real interfaces/s3 module; add
  multi-part ordering, ranges spanning parts, S3/CORS headers, fetch-error
  propagation
- s3-helpers-edge (new): compress heuristics, virtual-host bucket parsing,
  S3 route detection, client-IP/trustProxy, S3 response headers
- s3-auth-edge (new): verifyBodyHash, isS3Request, canonical-query-string
  encoding/sorting
- chunked-storage: rewrite against the real ChunkedStorage class (was
  importing deleted src/utils/chunked-storage) — chunk split, hashing,
  compression, size-limit guards, forwarding
- zip: fix stale import + add path-traversal/duplicate sanitization,
  locateZipEntry, empty-name fallback
- s3-docker-registry: fix stale src/config import; correct the rate-limit
  test to assert S3 routes INTENTIONALLY bypass rate limiting
- temp-stream (new): streamToTemp hashing, MD5, signature bytes, empty and
  oversized streams
- package.json: add the S3/unit files to test and test:s3 scripts

All new unit tests pass when run per-file (the project's documented mode to
avoid cross-file mock pollution). s3-sdk.test.ts (live E2E against a running
server) is deliberately excluded from test:s3.
2026-08-27 15:48:14 +07:00
asepharyana 43e36b7629 perf: parallelize S3 object part fetch + cache Telegram file info
Optimize the S3 GET path for chunked/multipart objects and reduce Telegram
API round-trips:

- object-stream: fetch object parts concurrently (bounded, in-order fan-in)
  instead of serializing N sequential Telegram CDN fetches. Response latency
  is now ~the slowest part fetch, not the sum of all part fetches.
- bot-pool.getFileInfo: cache file_id -> file_path in the existing in-memory
  cache so repeated S3 GET/HEAD of the same object skip the Telegram API call
  (file-controller had its own cache wrapper; the S3 path did not).
- chunked-storage + s3-controller: resolve multipart/chunked part CDN URLs
  concurrently via Promise.all instead of sequentially.
- s3-controller multipart: await writer.end() before re-reading the temp part
  file to avoid a flush race.

Adds object-stream-parallel.test.ts covering in-order fan-in, byte ranges,
and single-part responses even when the slowest part resolves out of order.
2026-08-27 14:55:24 +07:00
asepharyana 5d2f3331de chore: update dependabot-auto-merge.yml 2026-08-26 08:53:25 +07:00
asepharyana f2cb0007f4 chore: update dependabot.yml 2026-08-26 08:53:23 +07:00
asepharyana d2a306677c feat: add dependabot auto-merge workflow 2026-08-25 20:33:03 +07:00
asepharyana fbe09ec08a fix: sync bun.lock to package.json (dependabot compatibility) 2026-08-25 20:22:00 +07:00
mytheclipsebotreview[bot] 9bba0d3c6c Auto-merge PR #2
chore(deps-dev): bump typescript from 6.0.3 to 7.0.2
2026-08-25 11:20:25 +00:00
mytheclipsebotreview[bot] 643c5add70 Auto-merge PR #3
chore(deps-dev): bump @types/node from 25.9.5 to 26.2.0
2026-08-25 11:20:17 +00:00
asepharyana aa7f7058f2 feat: update dependabot config 2026-08-25 18:16:59 +07:00
asepharyana 55bf04cb65 feat: update dependabot config 2026-08-25 18:13:13 +07:00
mytheclipsebotreview[bot] 8abd334746 Auto-merge PR #1
chore(deps): bump nanoid from 5.1.16 to 6.0.1
2026-08-25 11:13:05 +00:00
dependabot[bot] aff7e53a2f chore(deps-dev): bump @types/node from 25.9.5 to 26.2.0
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.9.5 to 26.2.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.2.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-25 11:11:11 +00:00
dependabot[bot] 51107e2ccf chore(deps-dev): bump typescript from 6.0.3 to 7.0.2
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/compare/v6.0.3...v7.0.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-25 11:11:03 +00:00
dependabot[bot] 5417cde649 chore(deps): bump nanoid from 5.1.16 to 6.0.1
Bumps [nanoid](https://github.com/ai/nanoid) from 5.1.16 to 6.0.1.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.16...6.0.1)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-25 11:10:26 +00:00
asepharyana 2fee3861f0 feat: add dependabot config (npm auto-deps) 2026-08-25 18:08:51 +07:00
asepharyana 88e2a3faad ci: add Nix GC cleanup job on VPS after deploy 2026-08-04 13:57:45 +07:00
aseph 75b6d0a527 ci: use free GHA Nix cache (disable FlakeHub cache, not subscribed) 2026-08-03 16:44:14 +07:00
asepharyana 0c2ee3b3cf ci: enable FlakeHub Cache (id-token: write + use-flakehub) 2026-08-03 16:20:34 +07:00
asepharyana 12b6a133a7 ci: use biome lint gate instead of flaky bun test suite (bun 1.3.14 module resolution bug) 2026-08-03 13:41:32 +07:00
asepharyana d2e2b450f6 ci: add test gate before Nix deploy 2026-08-03 13:37:36 +07:00
asepharyana 17d877e2c6 docs: sync remaining .md to 4000s infra 2026-08-02 16:46:31 +07:00
asepharyana 62021397e0 chore: sync port references and docs to 4000s infra 2026-08-02 16:19:30 +07:00