{"id":49093592,"url":"https://github.com/yowainwright/tqs","last_synced_at":"2026-04-20T19:34:35.363Z","repository":{"id":350182985,"uuid":"1180470043","full_name":"yowainwright/tqs","owner":"yowainwright","description":"quick scripts for typescript","archived":false,"fork":false,"pushed_at":"2026-04-09T07:25:56.000Z","size":631,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T09:24:07.719Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/yowainwright.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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":null,"dco":null,"cla":null}},"created_at":"2026-03-13T04:28:03.000Z","updated_at":"2026-04-09T07:26:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yowainwright/tqs","commit_stats":null,"previous_names":["yowainwright/tqs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/yowainwright/tqs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yowainwright%2Ftqs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yowainwright%2Ftqs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yowainwright%2Ftqs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yowainwright%2Ftqs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yowainwright","download_url":"https://codeload.github.com/yowainwright/tqs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yowainwright%2Ftqs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32062694,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"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":[],"created_at":"2026-04-20T19:34:34.224Z","updated_at":"2026-04-20T19:34:35.357Z","avatar_url":"https://github.com/yowainwright.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tqs\n\n[![CI](https://github.com/yowainwright/tqs/actions/workflows/ci.yml/badge.svg)](https://github.com/yowainwright/tqs/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\u003e Compile TypeScript to very fast and very small standalone native binaries via QuickJS.\n\n```bash\ntqs my-script.ts   # outputs ./my-script — a standalone native binary\n```\n\nWrite TypeScript. Get a tiny self-contained binary with [QuickJS-NG](https://github.com/quickjs-ng/quickjs) embedded and `maybefetch()` for HTTP. No Node.js, no V8, no runtime dependencies.\n\n## Why tqs?\n\nGreat for typed, tested scripts that start fast and run fast — think LLM hooks.\n\n- **Native binaries**: `tqs my-script.ts` compiles to a standalone executable — ship it anywhere\n- **Built-in HTTP**: `maybefetch()` provides fetch with retry, backoff, and timeout — zero dependencies; synchronous but fast\n- **Small by default**: ~1MB binary with no build flags or tuning — smaller than a stripped Go or Rust binary with HTTP\n- **Fast startup**: \u003c1ms cold start vs ~40ms for Node.js\n- **Type-safe**: Full TypeScript support with types for `qjs:std`, `qjs:os`, and `maybefetch`\n\n## Installation\n\n**macOS**\n```bash\nbrew install yowainwright/tap/tqs\n```\n\n**Linux**\n```bash\napt install libcurl4 cmake\ngit clone https://github.com/yowainwright/tqs.git\ncd tqs \u0026\u0026 bun install \u0026\u0026 bun run build\n```\n\nRequires `libcurl` (`apt install libcurl4` on Linux, pre-installed on macOS).\n\n## Quick Start\n\n```typescript\n// @tqs-script\nimport * as std from 'qjs:std';\nimport * as os from 'qjs:os';\nimport { maybeFetch } from 'tqs';\n\nconst cwd = os.getcwd();\nstd.out.puts(`Running from: ${cwd}\\n`);\n\nconst data = maybeFetch('https://httpbin.org/json');\nif (data) {\n  std.out.puts(`Response: ${data}\\n`);\n}\n\nstd.exit(0);\n```\n\nCompile and run:\n\n```bash\ntqs my-script.ts   # creates ./my-script\n./my-script\n```\n\n## How it works\n\n```\nmy-script.ts\n  → bun build (bundles TypeScript to self-contained JS)\n  → qjsc (compiles JS + QuickJS runtime + maybefetch into a native binary)\n  → ./my-script\n```\n\nThe output binary embeds the QuickJS runtime and all JavaScript source inline — no external files needed at runtime.\n\n## CLI\n\n```bash\ntqs \u003cscript\u003e        # Compile TypeScript or JavaScript to a native binary\ntqs --help          # Show help\ntqs --version       # Show version\n```\n\nSupported inputs: `.tqs`, `.js`. For `.ts` files, add `// @tqs-script` at the top to mark them as QuickJS scripts:\n\n```typescript\n// @tqs-script\nimport * as std from 'qjs:std';\n// ...\n```\n\n## TypeScript Types\n\nAdd this import to get types for `qjs:std`, `qjs:os`, `maybefetch`, and QuickJS globals in your scripts:\n\n```typescript\n// @tqs-script\nimport 'tqs/quickjs';\nimport * as std from 'qjs:std';\nimport * as os from 'qjs:os';\n```\n\n## CLI Arguments\n\nScripts receive arguments via `scriptArgs`. The first element is the script path:\n\n```typescript\n// @tqs-script\nimport 'tqs/quickjs';\n\nconst [, , url] = scriptArgs;\n```\n\n```bash\ntqs my-script.ts https://example.com/api\n```\n\n## QuickJS Modules\n\nUse `qjs:std` and `qjs:os` in your scripts. These are available at runtime inside the compiled binary.\n\n### `qjs:std`\n\n| Method | Signature | Description |\n|--------|-----------|-------------|\n| `exit` | `(code: number) =\u003e void` | Exit with status code |\n| `getenv` | `(name: string) =\u003e string \\| null` | Read environment variable |\n| `evalScript` | `(source: string) =\u003e unknown` | Evaluate JavaScript |\n| `loadScript` | `(filename: string) =\u003e unknown` | Load and evaluate file |\n| `printf` | `(format: string, ...args) =\u003e void` | Formatted print to stdout |\n| `sprintf` | `(format: string, ...args) =\u003e string` | Formatted string |\n| `in.getline` | `() =\u003e string \\| null` | Read line from stdin |\n| `out.puts` | `(str: string) =\u003e void` | Write to stdout |\n| `err.puts` | `(str: string) =\u003e void` | Write to stderr |\n\n### `qjs:os`\n\n| Method | Signature | Description |\n|--------|-----------|-------------|\n| `getcwd` | `() =\u003e string` | Current working directory |\n| `chdir` | `(path: string) =\u003e number` | Change directory |\n| `mkdir` | `(path: string, mode?) =\u003e number` | Create directory |\n| `readdir` | `(path: string) =\u003e string[]` | List directory contents |\n| `realpath` | `(path: string) =\u003e string` | Resolve path |\n| `stat` | `(path: string) =\u003e StatResult` | File information |\n| `exec` | `(args: string[], options?) =\u003e number` | Execute command |\n| `unlink` | `(path: string) =\u003e number` | Delete file |\n| `rename` | `(old: string, new: string) =\u003e number` | Rename file |\n| `open` | `(filename: string, flags: string, mode?) =\u003e number` | Open file descriptor |\n| `read` | `(fd, buffer, offset, length) =\u003e number` | Read from fd |\n| `write` | `(fd, buffer, offset, length) =\u003e number` | Write to fd |\n| `close` | `(fd: number) =\u003e number` | Close file descriptor |\n| `sleep` | `(ms: number) =\u003e void` | Sleep milliseconds |\n| `platform` | `string` | Current platform |\n\n## maybefetch\n\nSynchronous HTTP GET with exponential backoff retry. Available as a global in all compiled scripts — not async, blocks until complete or all retries are exhausted.\n\n```typescript\nimport { maybeFetch } from 'tqs';\n\nconst body = maybeFetch('https://example.com/api');\n\nif (body) {\n  std.out.puts(body);\n}\n```\n\nOverride specific defaults with `defaultConfig`:\n\n```typescript\nimport { maybeFetch, defaultConfig } from 'tqs';\n\nconst body = maybeFetch('https://example.com/api', { ...defaultConfig, maxRetries: 5 });\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `url` | `string` | URL to fetch |\n| `maxRetries` | `number` | Maximum retry attempts |\n| `initialDelayMs` | `number` | Delay before first retry (ms) |\n| `maxDelayMs` | `number` | Maximum delay between retries (ms) |\n| `backoffFactor` | `number` | Multiplier applied to delay each retry |\n| `timeoutMs` | `number` | Request timeout (ms) |\n\nReturns `string` on success (2xx response body), `null` on failure after all retries.\n\n## TypeScript API\n\n`tqs` exports typed wrappers around the `maybefetch` global for use in compiled scripts:\n\n```typescript\nimport { maybeFetch, defaultConfig } from 'tqs';\nimport type { FetchConfig } from 'tqs';\n```\n\n### `defaultConfig`\n\n| Property | Value |\n|----------|-------|\n| `maxRetries` | `3` |\n| `initialDelayMs` | `1000` |\n| `maxDelayMs` | `30000` |\n| `backoffFactor` | `2.0` |\n| `timeoutMs` | `10000` |\n\n### `maybeFetch(url, config?): string | null`\n\nTyped wrapper around the `maybefetch` global. Only available in compiled QuickJS binaries.\n\n## Resource Usage\n\n| Metric | tqs | Node.js 25 |\n|--------|-----|------------|\n| Startup | \u003c1ms | ~40ms |\n| Memory (hello world) | ~2MB | ~15MB |\n| Memory (HTTP fetch) | ~4.5MB | ~27.5MB |\n| Binary size | ~1MB | ~60MB |\n\n*Measured on Apple M4, macOS 15.*\n\n## Development\n\n```bash\nbun install\nbun run build:quickjs   # Build QuickJS-NG + maybefetch + tqs binary\nbun run build:ts        # Build TypeScript\nbun run lint            # Lint\nbun run typecheck       # Type check\nbun test                # Run tests\n```\n\n## Comparison\n\n### vs JS/TS runtimes\n\n| Tool | Binary Size | Startup | Approach |\n|---|---|---|---|\n| **tqs** | ~1 MB | \u003c1ms | QuickJS native bytecode |\n| Bun compile | ~21–36 MB | ~5–10ms | JSC runtime embedded |\n| Deno compile | ~60–100 MB | ~30–60ms | V8 runtime embedded |\n| Node.js SEA | ~60 MB | ~40ms | V8 (Node) embedded |\n\n### vs compiled languages\n\n| Tool | Binary Size | Startup | Language |\n|---|---|---|---|\n| **tqs** | ~1 MB | \u003c1ms | TypeScript |\n| Rust (stripped, with HTTP) | ~2–3 MB | \u003c1ms | Rust |\n| Go (stripped, with HTTP) | ~5–7 MB | \u003c1ms | Go |\n\ntqs is competitive on binary size and startup with native compiled languages — the tradeoff is no async, no npm ecosystem, and a subset of JS APIs.\n\n### Honest tradeoffs\n\n**tqs is the right tool when:**\n- Binary size and cold-start matter (LLM hooks, git hooks, CI steps, edge deployments)\n- Your script is a synchronous pipeline: read input, call an API, write output\n- You want fast compile times and a small distributable without tuning a Go or Rust build\n- You want to write TypeScript, not Go or Rust\n\n**tqs is not the right tool when:**\n- You need multi-threading or concurrency\n- You need the npm ecosystem or async I/O\n- Your script uses Node.js built-ins (`fs`, `path`, `http`, etc.)\n- You need error handling beyond synchronous retries\n\n---\n\n## License\n\nMIT — See [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyowainwright%2Ftqs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyowainwright%2Ftqs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyowainwright%2Ftqs/lists"}