{"id":49100161,"url":"https://github.com/kvnpetit/tynd","last_synced_at":"2026-04-20T23:03:07.780Z","repository":{"id":352552535,"uuid":"1212232095","full_name":"kvnpetit/tynd","owner":"kvnpetit","description":"Desktop apps in TypeScript. Small native binaries, zero-codegen typed RPC, no bridge language to learn.","archived":false,"fork":false,"pushed_at":"2026-04-20T04:30:37.000Z","size":1632,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T06:29:08.919Z","etag":null,"topics":["bun","cross-platform","desktop","desktop-app","electron-alternative","framework","rust","tauri-alternative","typescript","wails-alternative","webview"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@tynd/cli","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/kvnpetit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-16T07:25:14.000Z","updated_at":"2026-04-20T04:56:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kvnpetit/tynd","commit_stats":null,"previous_names":["kvnpetit/tynd"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/kvnpetit/tynd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvnpetit%2Ftynd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvnpetit%2Ftynd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvnpetit%2Ftynd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvnpetit%2Ftynd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kvnpetit","download_url":"https://codeload.github.com/kvnpetit/tynd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvnpetit%2Ftynd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32069440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T21:26:33.338Z","status":"ssl_error","status_checked_at":"2026-04-20T21:26:22.081Z","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":["bun","cross-platform","desktop","desktop-app","electron-alternative","framework","rust","tauri-alternative","typescript","wails-alternative","webview"],"created_at":"2026-04-20T23:03:03.336Z","updated_at":"2026-04-20T23:03:07.758Z","avatar_url":"https://github.com/kvnpetit.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n\n# **Tynd**\n\n### Desktop apps in TypeScript. One language, native binary, no glue code.\n\n[![CI](https://github.com/kvnpetit/tynd/actions/workflows/ci.yml/badge.svg)](https://github.com/kvnpetit/tynd/actions/workflows/ci.yml)\n[![License](https://img.shields.io/github/license/kvnpetit/tynd?color=blue)](./LICENSE)\n[![npm @tynd/cli](https://img.shields.io/npm/v/@tynd/cli?label=%40tynd%2Fcli\u0026color=06b6d4)](https://www.npmjs.com/package/@tynd/cli)\n[![npm @tynd/core](https://img.shields.io/npm/v/@tynd/core?label=%40tynd%2Fcore\u0026color=06b6d4)](https://www.npmjs.com/package/@tynd/core)\n[![npm downloads](https://img.shields.io/npm/dw/@tynd/cli?label=downloads\u0026color=10b981)](https://www.npmjs.com/package/@tynd/cli)\n[![GitHub stars](https://img.shields.io/github/stars/kvnpetit/tynd?style=flat\u0026color=yellow)](https://github.com/kvnpetit/tynd/stargazers)\n\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org)\n[![Bun](https://img.shields.io/badge/Bun-runtime-fbf0df?logo=bun\u0026logoColor=000)](https://bun.sh)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](./CONTRIBUTING.md)\n[![Last commit](https://img.shields.io/github/last-commit/kvnpetit/tynd)](https://github.com/kvnpetit/tynd/commits/main)\n[![Open issues](https://img.shields.io/github/issues/kvnpetit/tynd?color=d93f0b)](https://github.com/kvnpetit/tynd/issues)\n\n**Native window. Zero network. TypeScript end-to-end.**\nWrite your backend and frontend in TypeScript, ship a small native binary — no extra language to learn, no codegen step.\n\n```bash\nbunx @tynd/cli create my-app\n```\n\n**-\u003e [Getting Started in 5 minutes](./GETTING_STARTED.md)**\n\n\u003c/div\u003e\n\n---\n\n## ✨ At a glance\n\n- 🟦 **TypeScript top to bottom.** Backend, frontend, IPC, config — same language, no codegen.\n- 🧬 **Two runtime modes, one API.** Start with `lite` (~6.5 MB native binary, no extra runtime needed). Switch to `full` with one config line when you need Bun's JIT or native-binding npm packages.\n- 🔒 **Native window, zero network.** No HTTP server, no loopback TCP port, no firewall prompt. Frontend and IPC ride a native custom scheme.\n- 🧰 **27 OS APIs, identical in both modes** — `fs` (+ watcher), `sql` (embedded SQLite), `http`, `websocket`, `terminal` (real PTY), `compute` (blake3/sha/CSPRNG), `dialog`, `tray`, `menu` (accelerators + checkbox/radio), `notification`, `clipboard` (image + HTML), `shell`, `process`, `sidecar`, `singleInstance` (with argv forwarding + deep links), `shortcuts` (system-wide hotkeys), `keyring` (OS-encrypted secrets), `autolaunch` (start at boot), `store`, `updater` (signed auto-update with Ed25519), `workers`, `app` (name/version/exit/relaunch), `os` / `path`, `tyndWindow` (multi-window + events), plus typed emitters and streaming RPC.\n- ⚡ **Zero-copy binary IPC.** Multi-MB payloads (`fs.readBinary`, `compute.hash`, …) skip JSON/base64 entirely — roughly **5-10× faster** than the usual webview-framework binary path.\n- 📦 **First-class installers.** `tynd build --bundle` emits `.app` / `.dmg` / `.deb` / `.rpm` / `.AppImage` / NSIS `.exe` / `.msi`. Installer tools auto-download on first build — no manual setup. Built-in code signing (`signtool` on Windows, `codesign` + optional notarization on macOS).\n- 🛡️ **Security defaults.** Auto-injected CSP on every HTML response, OS-backed secret storage via `keyring`, Ed25519-signed auto-updater so tampered binaries are rejected.\n- 🌊 **Streaming RPC that doesn't flinch.** Async-generator backend handlers stream to the frontend with per-chunk flow control + batched DOM updates — 10k+ yields/sec without freezing the UI.\n- 🎨 **Framework-agnostic.** React, Vue, Svelte, Solid, Preact, Lit, Angular — anything that outputs a pure SPA.\n\n---\n\n## 🧭 Why Tynd\n\n- **TypeScript backend, no codegen.** The frontend types backend calls from `typeof backend` — no `.d.ts` generation, no IDL, no schema file.\n- **Native OS webview.** The final binary doesn't ship a browser — it uses WebView2 / WKWebView / WebKitGTK, so you inherit the OS's paint loop, font stack, and accessibility for free.\n- **Two modes, one API.** `lite` for the smallest binary (~6.5 MB, embedded JS engine). `full` when you need Bun's JIT or native-binding npm packages. Switch via one config line — every OS API works the same in both.\n- **Zero network IPC.** RPC and assets never touch TCP — no loopback port, no firewall prompt on first launch.\n\nSee [COMPARISON.md](./COMPARISON.md) for the full Tynd vs Tauri / Wails / Electron matrix (39 categories, 500+ rows).\n\n---\n\n## 🧪 How it works\n\n```\nTypeScript backend                         Native OS window\n──────────────────────────                 ─────────────────────────\n  export async function greet()  ◄── IPC ─ await api.greet(\"Alice\")\n  events.emit(\"ready\", payload)  ─── push ─► api.on(\"ready\", handler)\n         │\n         ▼\n  tynd-full  — your TypeScript runs on Bun, wrapped in a native host\n  tynd-lite  — your TypeScript runs inside the native host, no extra runtime\n```\n\n**Zero network.** Frontend assets and IPC ride a native custom scheme — no HTTP server, no loopback port, no firewall prompt. Multi-MB binary payloads (`fs.readBinary`, `fs.writeBinary`, `compute.hash`, …) skip JSON entirely via a dedicated binary channel.\n\n### Two runtime modes\n\n| | `lite` | `full` |\n|---|---|---|\n| JS runtime | embedded interpreter — ships inside the native binary | Bun, packed into the native binary |\n| Hot JS speed | interpreter — fine for IPC glue, slower on tight loops | **Bun JIT — often 10-100× faster on CPU-bound JS** |\n| IPC overhead | in-process, no serialization hop | one serialization hop (OS pipe) |\n| `fs` / `http` / `websocket` / `sql` / `compute` / `terminal` / … | ✓ same API | ✓ same API |\n| JS-level `fetch` / `Bun.file` / `bun:sqlite` | ✗ (use the Tynd API) | ✓ |\n| Pure-JS npm packages | ✓ (bundled) | ✓ |\n| npm with native bindings | ✗ | ✓ |\n| Binary size | smaller (~6.5 MB) | larger (~44 MB, Bun compressed) |\n| Startup | faster (everything in-process) | slower (spawns Bun) |\n\n-\u003e See [`RUNTIMES.md`](RUNTIMES.md) for the full comparison (APIs, performance, detection, examples).\n\n---\n\n## 📋 Requirements\n\n**[Bun](https://bun.sh) is required for app developers.** Tynd is a Bun-first framework — the CLI, the dev server, and the full runtime all run on Bun. Node.js is not supported as a replacement.\n\n```bash\n# macOS / Linux / WSL\ncurl -fsSL https://bun.sh/install | bash\n\n# Windows (PowerShell)\npowershell -c \"irm bun.sh/install.ps1 | iex\"\n```\n\n**End users of your built app need nothing** — whichever runtime mode you picked is already packed into the distributed binary.\n\n---\n\n## 🚀 Quick start\n\n```bash\nbunx tynd create my-app\ncd my-app\nbun run dev\n```\n\nWith a specific framework / runtime:\n\n```bash\nbunx tynd create my-app --framework react --runtime full\nbunx tynd create my-app --framework vue   --runtime lite\n```\n\n---\n\n## 🛠️ CLI\n\n```bash\ntynd create [name]           # scaffold a new project (interactive if no args)\n  --framework react|vue|svelte|solid|preact|lit|angular\n  --runtime   full|lite\n\ntynd dev                     # start app in development mode (HMR)\ntynd start                   # classic JS build (frontend + backend) then run (no HMR)\ntynd build                   # bundle backend + frontend -\u003e single binary\n  --bundle [targets]         # + installers: app, dmg, deb, rpm, appimage, nsis, msi (or \"all\")\ntynd init                    # add tynd to an existing project\ntynd clean                   # remove build artifacts (.tynd/cache, release/)\ntynd validate                # check config and project structure\ntynd upgrade                 # upgrade @tynd/cli and @tynd/core to latest\ntynd info                    # show environment info (Bun version, WebView, paths)\ntynd keygen                  # generate an Ed25519 keypair for the auto-updater\ntynd sign \u003cfile\u003e             # sign a file with an updater private key\n```\n\n---\n\n## 🎨 Supported frameworks\n\n| Framework | Scaffold | Build | Fast Refresh (HMR) |\n|---|---|---|---|\n| React                 | ✅ Vite `react-ts`  | ✅ | ⚠ OK; breaks if React Compiler is enabled |\n| Vue / Svelte / Solid / Preact | ✅ Vite `\u003cname\u003e-ts` | ✅ | ✅ |\n| Lit                   | ✅ Vite `lit-ts`    | ✅ | ♻ Full reload only — Web Components by design |\n| Angular               | ✅ Angular CLI      | ✅ | ♻ Full reload by default (opt-in HMR via `ng serve --hmr`) |\n\n`tynd init` also detects existing **Vite**, **CRA**, **Angular CLI**, **Parcel**, **Rsbuild**, and **Webpack** setups.\n\n**Blocked (SSR):** Next.js, Nuxt, SvelteKit, Remix, Gatsby, Blitz.js, RedwoodJS, SolidStart, Angular Universal, Analog, Qwik City, Astro, TanStack Start, Vike. Use the SPA variant instead (plain Svelte vs SvelteKit, plain Solid vs SolidStart, …).\n\nSee [`FRAMEWORKS.md`](FRAMEWORKS.md) for the full matrix, per-framework notes, output-dir rules, and the React Compiler workaround.\n\n---\n\n## 📁 Project structure\n\n```\nmy-app/\n├── tynd.config.ts            ← project config\n├── package.json\n├── backend/\n│   └── main.ts               ← backend entry — app.start() here\n└── src/                      ← frontend source (React / Vue / Svelte…)\n    └── main.tsx\n```\n\n---\n\n## 🧩 API\n\nTynd exposes three surfaces — backend module, typed frontend RPC, and direct OS APIs:\n\n| Surface | Import | Purpose |\n|---|---|---|\n| **Backend** | `@tynd/core` | `app.start`, `app.onReady`, `app.onClose`, `createEmitter` |\n| **Frontend RPC** | `@tynd/core/client` | `createBackend\u003ctypeof backend\u003e()` — typed proxy |\n| **OS APIs** | `@tynd/core/client` | `app`, `dialog`, `tyndWindow`, `monitors`, `menu`, `clipboard`, `shell`, `notification`, `tray`, `process`, `fs`, `shortcuts`, `keyring`, `autolaunch`, `store`, `updater`, `os`, `path`, `http`, `websocket`, `sql`, `sidecar`, `terminal`, `compute`, `workers`, `singleInstance` |\n| **Web APIs** | `@tynd/core/client` | `fetch`, `WebSocket`, `EventSource`, `crypto`, `URL`, `Blob`, `FormData`, `AbortController`, `TextEncoder`, … (re-exports for `import * as tynd`) |\n\nShort example:\n\n```typescript\n// backend/main.ts\nimport { app, createEmitter } from \"@tynd/core\"\n\nexport const events = createEmitter\u003c{ ready: { message: string } }\u003e()\nexport async function greet(name: string): Promise\u003cstring\u003e { return `Hello, ${name}!` }\n\napp.start({\n  frontendDir: import.meta.dir + \"/../dist\",\n  window: { title: \"My App\", width: 1200, height: 800, center: true },\n})\n```\n\n```typescript\n// src/App.tsx\nimport { createBackend, fs, process, terminal } from \"@tynd/core/client\"\nimport type * as backend from \"../backend/main\"\n\nconst api = createBackend\u003ctypeof backend\u003e()\nconst msg = await api.greet(\"Alice\")   // string ✅\n\nawait fs.writeText(\"data.json\", JSON.stringify(state))\nconst { stdout } = await process.exec(\"git\", { args: [\"status\"] })\n```\n\n**Full reference:** [API.md](./API.md) — every method, signature, and example.\n\n---\n\n## ⚙️ tynd.config.ts\n\n```typescript\nimport type { TyndConfig } from \"@tynd/cli\"\n\nexport default {\n  runtime:     \"full\",              // \"full\" | \"lite\"\n  backend:     \"backend/main.ts\",   // backend entry file\n  frontendDir: \"dist\",              // built frontend assets (relative to project root)\n  icon:        \"public/favicon.svg\", // optional — auto-detected; SVG recommended\n  window: {\n    title:  \"My App\",\n    width:  1200,\n    height: 800,\n    center: true,\n  },\n} satisfies TyndConfig\n```\n\n### `TyndConfig` fields\n\n| Field | Default | Description |\n|---|---|---|\n| `runtime` | `\"full\"` | `\"full\"` or `\"lite\"` — see [RUNTIMES.md](RUNTIMES.md) |\n| `backend` | `\"backend/main.ts\"` | Backend entry file |\n| `frontendDir` | `\"frontend\"` | Built frontend output directory |\n| `frontendEntry` | — | Simple TS/JS entry (no framework) — auto-bundled by tynd |\n| `devUrl` | auto | Dev server URL override |\n| `devCommand` | auto | Dev server start command override |\n| `icon` | auto | App icon path — auto-detected from `public/favicon.{ico,png,svg}` |\n| `binaryArgs` | — | Extra args passed to the `tynd-full` / `tynd-lite` binary |\n| `window` | — | Default window options (title, width, height, center) |\n\n**Icon auto-detection order** (SVG first — single source of truth renders pixel-perfect at every size):\n`public/{favicon,icon,logo}.svg` -\u003e `public/{favicon,icon,logo}.{ico,png}` -\u003e `assets/icon.{svg,png,ico}` -\u003e `icon.{svg,png,ico}`. One source feeds every output — each build produces a multi-size ICO (16/32/48/256) for Windows, a multi-entry ICNS (32/128/256/512/1024) for macOS `.app`, and a full hicolor PNG tree (16..512) for `.deb` / `.rpm` / `.AppImage`. PNG sources degrade to single-size; `.ico` sources pass through to Windows bundles and are skipped (with a warning) for macOS/Linux. Set `icon` explicitly to override.\n\n---\n\n## 🪟 WebView runtime\n\n| OS | WebView | Pre-installed? |\n|---|---|---|\n| Windows 10/11 | WebView2 (Edge Chromium) | ✅ |\n| macOS | WKWebView | ✅ |\n| Linux | WebKitGTK 4.1 | ⚠️ `sudo apt install libwebkit2gtk-4.1-0` |\n\n---\n\n## 🏗️ Building from source (contributors only)\n\nApp authors don't need this section — `@tynd/host`'s postinstall downloads pre-built binaries automatically. If you want to build the native host yourself:\n\n```bash\n# Requirements\nrustup install stable\n\n# Linux only\nsudo apt install libgtk-3-dev libwebkit2gtk-4.1-dev \\\n  libjavascriptcoregtk-4.1-dev libsoup-3.0-dev \\\n  libxdo-dev\n\n# Build\ncargo build --release -p tynd-full\ncargo build --release -p tynd-lite\n```\n\n### Repo layout\n\n```\npackages/\n├── host-rs/     ← native host library (window + IPC + OS APIs)\n├── full/        ← tynd-full binary (packs Bun inside the host)\n├── lite/        ← tynd-lite binary (embeds a lightweight JS engine)\n├── host/        ← @tynd/host (npm: postinstall downloads pre-built binaries)\n├── core/        ← @tynd/core (TypeScript: app, createEmitter, client API)\n└── cli/         ← @tynd/cli  (TypeScript: tynd create/dev/build/info)\n```\n\n---\n\n## 📚 Documentation\n\n**-\u003e [tynd.kvnpetit.com/docs](https://tynd.kvnpetit.com/docs)** — live versioned docs site.\n\n| Doc | When to read it |\n|---|---|\n| [GETTING_STARTED.md](./GETTING_STARTED.md) | First project — scaffold, dev, build, ship in 5 min |\n| [API.md](./API.md) | Every backend / frontend / OS API with signatures + examples |\n| [RUNTIMES.md](./RUNTIMES.md) | `lite` vs `full` — what each exposes, when to pick which |\n| [FRAMEWORKS.md](./FRAMEWORKS.md) | Per-framework matrix (React, Vue, Svelte, Solid, Angular, Preact, Lit) |\n| [COMPARISON.md](./COMPARISON.md) | Tynd vs Tauri / Wails / Electron across 39 categories |\n| [SIGNING.md](./SIGNING.md) | Code signing + notarization workflows per OS |\n| [TROUBLESHOOTING.md](./TROUBLESHOOTING.md) | Common errors: missing binary, WebView2, GTK deps, Gatekeeper, etc. |\n| [CONTRIBUTING.md](./CONTRIBUTING.md) | Dev loop, commit style, PR process |\n| Per-package READMEs | [@tynd/core](./packages/core/README.md) · [@tynd/cli](./packages/cli/README.md) · [@tynd/host](./packages/host/README.md) |\n| Working examples | [playground/full](./playground/full/README.md) (LLM chatbot, full runtime) · [playground/example](./playground/example/README.md) (minimal demo, lite runtime) |\n| [docs/](./docs/README.md) | Next.js 16 + Nextra 4 docs site (landing + versioned docs). Static export, deploys to Cloudflare Pages. `bun --cwd docs run dev` |\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvnpetit%2Ftynd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkvnpetit%2Ftynd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvnpetit%2Ftynd/lists"}