{"id":46026966,"url":"https://github.com/strataljs/stratal","last_synced_at":"2026-04-01T19:05:01.418Z","repository":{"id":340662717,"uuid":"1166098582","full_name":"strataljs/stratal","owner":"strataljs","description":"A modular framework for building Cloudflare Workers with dependency injection, OpenAPI documentation, queues, cron jobs, and more.","archived":false,"fork":false,"pushed_at":"2026-03-07T12:42:05.000Z","size":1147,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-07T17:46:02.473Z","etag":null,"topics":["cloudflare-workers","cron","dependency-injection","framework","hono","i18n","modules","openapi","queue","typescript"],"latest_commit_sha":null,"homepage":"https://stratal.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strataljs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-24T21:54:33.000Z","updated_at":"2026-03-07T12:42:09.000Z","dependencies_parsed_at":"2026-03-02T04:07:36.344Z","dependency_job_id":null,"html_url":"https://github.com/strataljs/stratal","commit_stats":null,"previous_names":["strataljs/stratal"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/strataljs/stratal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strataljs%2Fstratal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strataljs%2Fstratal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strataljs%2Fstratal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strataljs%2Fstratal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strataljs","download_url":"https://codeload.github.com/strataljs/stratal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strataljs%2Fstratal/sbom","scorecard":{"id":1244149,"data":{"date":"2026-03-01T01:48:36Z","repo":{"name":"github.com/strataljs/stratal","commit":"57bd486b439098eca721226ec136d54fad5d4533"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":6.1,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/18 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"project was created within the last 90 days. Please review its contents carefully","details":["Warn: Repository was created within the last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql.yml:31","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:32","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/publish.yml:17","Warn: topLevel 'contents' permission set to 'write': .github/workflows/benchmark.yml:12","Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yml:3","Info: topLevel 'contents' permission set to 'read': .github/workflows/codeql.yml:24","Info: topLevel 'contents' permission set to 'read': .github/workflows/dependency-review.yml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/docs.yml:9","Info: topLevel 'contents' permission set to 'read': .github/workflows/publish.yml:10","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:18"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:  25 out of  25 GitHub-owned GitHubAction dependencies pinned","Info:  15 out of  15 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"CII-Best-Practices","score":5,"reason":"badge detected: Passing","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":3,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'main'","Warn: could not determine whether codeowners review is allowed","Warn: no status checks found to merge onto branch 'main'","Warn: PRs are not required to make changes on branch 'main'; or we don't have data to detect it.If you think it might be the latter, make sure to run Scorecard with a PAT or use Repo Rules (that are always public) instead of Branch Protection settings"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (13) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}},{"name":"CI-Tests","score":10,"reason":"7 out of 7 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}}]},"last_synced_at":"2026-03-01T05:45:55.815Z","repository_id":340662717,"created_at":"2026-03-01T05:45:55.815Z","updated_at":"2026-03-01T05:45:55.815Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30314613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cloudflare-workers","cron","dependency-injection","framework","hono","i18n","modules","openapi","queue","typescript"],"created_at":"2026-03-01T03:07:53.164Z","updated_at":"2026-04-01T19:05:01.409Z","avatar_url":"https://github.com/strataljs.png","language":"TypeScript","readme":"# Stratal\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/banner.png\" alt=\"Stratal\" width=\"600\" /\u003e\n\u003c/p\u003e\n\nA modular framework for building Cloudflare Workers with dependency injection, OpenAPI documentation, queues, cron jobs, and more.\n\n[![npm version](https://img.shields.io/npm/v/stratal)](https://www.npmjs.com/package/stratal)\n[![CI](https://github.com/strataljs/stratal/actions/workflows/ci.yml/badge.svg)](https://github.com/strataljs/stratal/actions/workflows/ci.yml)\n[![Benchmark](https://github.com/strataljs/stratal/actions/workflows/benchmark.yml/badge.svg)](https://github.com/strataljs/stratal/actions/workflows/benchmark.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/strataljs/stratal/badge)](https://securityscorecards.dev/viewer/?uri=github.com/strataljs/stratal)\n[![Known Vulnerabilities](https://snyk.io/test/github/strataljs/stratal/badge.svg)](https://snyk.io/test/github/strataljs/stratal)\n[![npm downloads](https://img.shields.io/npm/dm/stratal)](https://www.npmjs.com/package/stratal)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5-blue?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![Bundle size](https://img.shields.io/bundlephobia/minzip/stratal)](https://bundlephobia.com/package/stratal)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/strataljs/stratal/pulls)\n[![GitHub stars](https://img.shields.io/github/stars/strataljs/stratal?style=social)](https://github.com/strataljs/stratal)\n\n## Features\n\n- **Dependency Injection** - Two-tier DI container (global + request-scoped) powered by tsyringe\n- **OpenAPI Documentation** - Define Zod schemas once and get a full OpenAPI 3.0 spec with interactive docs\n- **Modular Architecture** - NestJS-style modules with lifecycle hooks, dynamic configuration, and middleware\n- **Hono Routing** - Convention-based RESTful controllers with automatic HTTP method mapping\n- **Queue Consumers** - Typed Cloudflare Queue consumers with message-type filtering\n- **Cron Jobs** - Scheduled tasks via Cloudflare Workers cron triggers\n- **Storage** - S3-compatible file storage with presigned URLs and TUS upload support\n- **Email** - Resend and SMTP providers with React Email template support\n- **i18n** - Type-safe internationalization with locale detection from request headers\n- **Guards and Middleware** - Route protection and per-module middleware configuration\n\n\u003e **Note:** Stratal is in active development and APIs may change before v1. It is okay to use in projects, but consider pinning your dependency version so that a new patch does not break your existing code.\n\n## Installation\n\n```bash\nnpm install stratal\n# or\nyarn add stratal\n```\n\n## Packages\n\n| Package | npm | Description |\n|---|---|---|\n| `stratal` | [![npm](https://img.shields.io/npm/v/stratal)](https://www.npmjs.com/package/stratal) | Core framework — modules, DI, routing, OpenAPI, queues, cron, storage, email, i18n |\n| `@stratal/testing` | [![npm](https://img.shields.io/npm/v/@stratal/testing)](https://www.npmjs.com/package/@stratal/testing) | Testing utilities and mocks |\n| `@stratal/framework` | [![npm](https://img.shields.io/npm/v/@stratal/framework)](https://www.npmjs.com/package/@stratal/framework) | Auth (Better Auth), database ORM (ZenStack), RBAC (Casbin), guards, factories |\n### AI Agent Skills\n\nStratal provides [Agent Skills](https://agentskills.io) for AI coding assistants like Claude Code and Cursor. Install to give your AI agent knowledge of Stratal patterns, conventions, and APIs:\n\n```bash\nnpx skills add strataljs/stratal\n```\n\n| Skill | Description |\n|---|---|\n| `stratal` | Build Cloudflare Workers apps with the Stratal framework — modules, DI, controllers, routing, OpenAPI, queues, cron, events, seeders, CLI, auth, database, RBAC, testing, and more |\n\n## Quick Start\n\nDefine a module with a controller and wire it up as a Cloudflare Worker:\n\n```typescript\nimport 'reflect-metadata'\nimport { Stratal } from 'stratal'\nimport { Module } from 'stratal/module'\nimport { Controller, Route, type RouterContext } from 'stratal/router'\nimport { z } from 'stratal/validation'\n\n// Define a controller\n@Controller('/api/greetings')\nclass GreetingsController {\n  @Route({\n    summary: 'Say hello',\n    response: z.object({ message: z.string() }),\n  })\n  async index(ctx: RouterContext) {\n    return ctx.json({ message: 'Hello from Stratal!' })\n  }\n}\n\n// Create the root module\n@Module({\n  controllers: [GreetingsController],\n})\nclass AppModule {}\n\n// Worker entry point\nexport default new Stratal({ module: AppModule })\n```\n\n## Documentation\n\nFull guides and examples are available at **[stratal.dev](https://stratal.dev)**. API reference lives at **[api-reference.stratal.dev](https://api-reference.stratal.dev)**.\n\n## Benchmarks\n\n### Request / Response (e2e)\n\nFull request lifecycle: DI resolution → middleware → routing → validation → response serialization.\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| simple GET - 200 | 99,191 | ±0.73% | 10.1 µs | 17.8 µs |\n| GET with route params - 200 | 80,096 | ±0.74% | 12.5 µs | 19.5 µs |\n| POST with JSON body - 201 | 49,954 | ±0.74% | 20.0 µs | 31.9 µs |\n| POST invalid body - validation error | 23,587 | ±3.19% | 42.4 µs | 71.8 µs |\n| GET unknown route - 404 | 43,228 | ±0.69% | 23.1 µs | 34.8 µs |\n\n### DI Container - Registration\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| register class provider | 5,396,472 | ±0.91% | 0.20 µs | 0.30 µs |\n| registerSingleton | 5,061,380 | ±0.63% | 0.20 µs | 0.30 µs |\n| registerValue | 5,264,393 | ±0.58% | 0.20 µs | 0.30 µs |\n| registerFactory | 4,966,905 | ±0.67% | 0.20 µs | 0.30 µs |\n\n### DI Container - Resolution\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| resolve class token | 2,259,399 | ±0.73% | 0.40 µs | 0.60 µs |\n| resolve symbol token | 2,085,313 | ±0.88% | 0.50 µs | 0.70 µs |\n| resolve value token | 2,252,901 | ±0.45% | 0.40 µs | 0.60 µs |\n| resolve singleton token | 2,180,625 | ±0.53% | 0.50 µs | 0.60 µs |\n| isRegistered check | 2,786,645 | ±0.51% | 0.40 µs | 0.50 µs |\n\n### DI Container - Conditional Binding\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| when().use().give().otherwise() | 1,545,062 | ±3.07% | 0.50 µs | 1.10 µs |\n| when() with cached predicate | 1,630,576 | ±2.65% | 0.50 µs | 1.00 µs |\n\n### Module Registry - Registration\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| register single module | 2,155,261 | ±0.95% | 0.50 µs | 0.60 µs |\n| register 3-level module tree | 1,028,422 | ±0.41% | 1.00 µs | 1.30 µs |\n| register dynamic module (forRoot) | 2,107,991 | ±1.60% | 0.50 µs | 1.00 µs |\n\n### Module Registry - Initialization\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| initialize with lifecycle hooks | 1,657,987 | ±0.12% | 0.60 µs | 0.80 µs |\n\n### Module Registry - Collection\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| getAllControllers | 983,234 | ±0.72% | 1.00 µs | 2.30 µs |\n| getAllConsumers | 1,000,669 | ±0.46% | 1.00 µs | 1.30 µs |\n| getAllJobs | 1,003,687 | ±0.46% | 1.00 µs | 1.30 µs |\n\n### Route Registration\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| controller with 5 OpenAPI routes | 42,263 | ±4.73% | 21.9 µs | 42.2 µs |\n| single-route controller | 215,349 | ±3.33% | 4.60 µs | 8.00 µs |\n| register multiple controllers | 38,840 | ±3.69% | 19.8 µs | 51.8 µs |\n\n### Application\n\n| Benchmark | ops/sec | ±% | Median | P99 |\n|---|--:|--:|--:|--:|\n| constructor only | 312,943 | ±1.69% | 2.70 µs | 7.70 µs |\n| full initialize() | 48,051 | ±4.92% | 16.3 µs | 43.1 µs |\n| resolve service after bootstrap | 45,913 | ±5.33% | 16.2 µs | 42.7 µs |\n\n\u003e Benchmarks ran on: Apple M3 Max (16-core), 48 GB RAM, macOS 26.2, Node.js v22.12.0\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrataljs%2Fstratal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrataljs%2Fstratal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrataljs%2Fstratal/lists"}