{"id":18262406,"url":"https://github.com/anitrend/on-the-edge","last_synced_at":"2026-06-28T14:00:34.682Z","repository":{"id":166176276,"uuid":"609874208","full_name":"AniTrend/on-the-edge","owner":"AniTrend","description":"edge functions for anitrend-v2 to offload data aggregation out of the main application.","archived":false,"fork":false,"pushed_at":"2026-06-25T20:46:13.000Z","size":1333,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2026-06-25T22:13:43.433Z","etag":null,"topics":["anitrend","deno","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AniTrend.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2023-03-05T13:59:03.000Z","updated_at":"2026-06-25T20:46:24.000Z","dependencies_parsed_at":"2026-04-04T11:02:57.261Z","dependency_job_id":null,"html_url":"https://github.com/AniTrend/on-the-edge","commit_stats":null,"previous_names":["anitrend/on-the-edge"],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/AniTrend/on-the-edge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AniTrend%2Fon-the-edge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AniTrend%2Fon-the-edge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AniTrend%2Fon-the-edge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AniTrend%2Fon-the-edge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AniTrend","download_url":"https://codeload.github.com/AniTrend/on-the-edge/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AniTrend%2Fon-the-edge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34890795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anitrend","deno","typescript"],"created_at":"2024-11-05T11:07:38.309Z","updated_at":"2026-06-28T14:00:34.676Z","avatar_url":"https://github.com/AniTrend.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# on-the-edge\n[![Deploy](https://github.com/AniTrend/on-the-edge/actions/workflows/deploy.yml/badge.svg)](https://github.com/AniTrend/on-the-edge/actions/workflows/deploy.yml) [![CI](https://github.com/AniTrend/on-the-edge/actions/workflows/ci.yml/badge.svg)](https://github.com/AniTrend/on-the-edge/actions/workflows/ci.yml)\n\n\u003e AniTrend’s Danet-based edge service for aggregating anime metadata, normalising provider payloads, and exposing a typed API surface at the edge.\n\n## What changed with the Danet migration?\n\n- **Framework**: We replaced Oak with [Danet](https://danet.land) to gain decorator-based dependency injection, module scoping, and easier composition for edge deployments.\n- **Modules-first architecture**: `AppModule` wires together cache, database, experiment, logger, secret, telemetry, and domain packages. Each module exports a focused public surface via `@scope/*` aliases.\n- **HTTP client + services**: Remote integrations (TMDB, Trakt, TheXem, etc.) now use a shared request client with interceptors, Zod parsing, and OTEL instrumentation.\n- **Persistence abstraction**: MongoDB access flows through a `Collection\u003cT\u003e` interface with Mongo and in-memory adapters, making tests deterministic.\n- **Edge bootstrap**: `bootstrap.ts` hosts the server, handles graceful shutdown, and optionally emits Swagger specs via `--swagger`.\n\n## Getting started\n\n1. **Install prerequisites**\n\t - [Deno **2.7.10**](https://deno.land/) or newer (matches CI `denoland/setup-deno@v2` pin).\n\t - Optional: Docker for local MongoDB if you want realistic persistence.\n2. **Clone \u0026 configure**\n\t ```bash\n\t git clone https://github.com/AniTrend/on-the-edge.git\n\t cd on-the-edge\n\t cp .env.example .env\n\t ```\n\t Fill in provider URLs/keys (`TMDB`, `TRAKT`, `ANIME_THEMES`, GrowthBook, Mongo creds, etc.). Keep secrets out of source control.\n\t `ANIME_THEMES` is the active base URL for AnimeThemes lookups.\n3. **Install dependencies** (cached by Deno on demand)\n\t ```bash\n\t deno task cache\n\t ```\n\n## Running the service locally\n\n- Launch the Danet application (listens on `PORT`, default `9800`):\n\t```bash\n\tdeno task dev\n\t```\n- Generate and host Swagger docs while running:\n\t```bash\n\tdeno task dev -- --swagger\n\t```\n- Hot reload during development:\n\t```bash\n\tdeno task dev:watch\n\t```\n\n`bootstrap.ts` ensures graceful shutdown on `SIGINT`/`SIGTERM` and will clean up active timers before exit.\n\n## Deno 2.7 stabilization notes\n\n- Removed deprecated unstable flags for stabilized features:\n\t- `--unstable-temporal`\n\t- `--unstable-experimentalDecorators`\n\t- `--unstable-emitDecoratorMetadata`\n- Removed `--unstable-otel` and `--unstable-cron` after Phase 2 validation:\n\t- `deno compile` works without both flags\n\t- app startup and OpenTelemetry bootstrap succeed without both flags\n\n## Quality gates\n\n| Purpose              | Command                              |\n|-----------------------|---------------------------------------|\n| Format                | `deno task fmt` / `deno task fmt:check` |\n| Lint                  | `deno task lint`                      |\n| Type check            | `deno task check`                     |\n| Tests                 | `deno task test`                      |\n| Targeted test         | `deno task test --filter \u003cpattern\u003e`   |\n| Swagger spec generate | `deno task swagger:generate`           |\n| Swagger spec validate | `deno task swagger:validate`           |\n\nTests are fully offline: use `@c4spar/mock-fetch`, in-memory cache/database adapters, and `FakeTime` for TTL-sensitive flows.\n\n## Enrichment endpoints\n\nThe service exposes Jikan-backed enrichment routes for MAL entities. Each route accepts query parameters instead of a required path parameter.\n\n- `name` should be a non-empty string and is the preferred identifier when a MAL ID is unavailable.\n- `malId` is optional and, when provided, must be a positive integer.\n- At least one of `name` or `malId` is required.\n\n- `GET /v1/studios?name=\u0026malId=` returns cached studio metadata.\n- `GET /v1/people?name=\u0026malId=` returns cached staff or voice actor metadata.\n- `GET /v1/characters?name=\u0026malId=` returns cached fictional character metadata, including anime, manga, and voice actor relations.\n\n## Project layout\n\n```\nsrc/\n\tapp.module.ts        # Danet root module wiring all infrastructure\n\tsetup.ts             # Application bootstrap + middleware + swagger\n\tcache/               # In-memory cache service (Redis planned post-migration)\n\tclient/              # Shared HTTP client, interceptors, and tests\n\tcommon/              # Core utilities, DI helpers, logging \u0026 OTEL support\n\tdatabase/            # Mongo adapters + in-memory collections for tests\n\texperiment/          # GrowthBook feature flag provider\n\tguard/               # Global header guard for API requests\n\tlogger/              # LoggerService + stream wiring\n\tmiddleware/          # Logger, tracing, header, and GrowthBook middleware\n\tpackage/             # Domain packages (config, news, series, episodes, studio, people, character)\n\tsecret/              # Environment-backed secret service\n\tservice/             # External service clients (Trakt, TMDB, TheXem, etc.)\n\ttelemetry/           # OTEL SDK bootstrap and exporters\n```\n\nEach folder exposes its public surface via `deno.json`/`index.ts`, enabling imports like `import { TheXemService } from '@scope/service/thexem';`.\n\n## Caching strategy\n\n- `CacheService` currently ships as an in-memory map suitable for local dev and tests. It enforces TTL on read but has **no** persistence or eviction policy.\n- Production deployments should wire a Redis-backed client (planned once the Danet migration stabilises). Until then, cache misses should be expected on restarts.\n\n## Observability\n\n- `TelemetryModule` bootstraps OTEL tracing, metrics, and logs. Enable exporters by providing:\n\t- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`\n\t- `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`\n\t- `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`\n\t- `OTEL_DENO_SERVICE_NAME`\n- Global middleware wraps requests with structured logging and trace context; remote service clients instrument outbound calls with span metadata.\n\n## Testing utilities\n\n- Review `docs/testing-utilities.md` for helper APIs (mock fetch, environment scoping, dependency spies).\n- Centralized test helpers (mocks, stubs, spies) live in `src/common/testing/` and are exported via `@scope/common/testing`.\n- Domain-specific helpers (e.g., in-memory database collections) may live under `src/**/testing/` as needed.\n\n## Contributing checklist\n\n- Follow the [CONTRIBUTING.md](CONTRIBUTING.md) guidelines, especially the OpenAPI contract rules.\n- Keep pull requests focused; update docs when behavior changes.\n- Run `deno fmt`, `deno lint`, and targeted `deno task test` before pushing.\n- If you changed API schemas or endpoints, run `deno task swagger:generate` + `deno task swagger:validate` (requires local MongoDB/Redis) or rely on CI's `contract-check` job.\n- Document new secrets/flags in `.env.example` or `docs/` as appropriate.\n\nFor deeper architecture notes, see the documents under `docs/` (service audit, series pipeline, test infrastructure phases).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanitrend%2Fon-the-edge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanitrend%2Fon-the-edge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanitrend%2Fon-the-edge/lists"}