[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81632":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":12,"subscribersCount":12,"size":12,"stars1d":12,"stars7d":12,"stars30d":12,"stars90d":12,"forks30d":12,"starsTrendScore":12,"compositeScore":14,"rankGlobal":9,"rankLanguage":9,"license":15,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":18,"hasPages":16,"topics":19,"createdAt":9,"pushedAt":9,"updatedAt":20,"readmeContent":21,"aiSummary":22,"trendingCount":12,"starSnapshotCount":12,"syncStatus":23,"lastSyncTime":24,"discoverSource":25},81632,"redis","PerryTS\u002Fredis","PerryTS","Pure-TypeScript Redis \u002F Valkey wire-protocol driver. Runs unchanged on Node.js + Bun, AOT-compiles to a native binary via Perry (LLVM).",null,"TypeScript",21,0,22,40,"MIT License",false,"main",true,[],"2026-06-12 04:01:34","# @perryts\u002Fredis\n\nA pure-TypeScript Redis \u002F Valkey driver that speaks the wire protocol\ndirectly — no native addons, no `hiredis`, no FFI shims. It runs\nunchanged on **Node.js**, **Bun**, and\n[**Perry**](https:\u002F\u002Fgithub.com\u002FPerryTS\u002Fperry), where the same source\nis **ahead-of-time compiled to a native binary via LLVM** — giving you\na real standalone executable that talks to Redis with no JS runtime\nattached.\n\n> Perry is a TypeScript-to-native compiler: it lowers a strict subset\n> of TS through LLVM into a statically-linked binary. `@perryts\u002Fredis`\n> is the third reference driver in the family (after\n> [`@perryts\u002Fpostgres`](..\u002Fpostgres) and [`@perryts\u002Fmysql`](..\u002Fmysql)),\n> showcasing Perry's ability to host real systems code: every socket\n> read, TLS handshake, and crypto op goes through perry-stdlib.\n\n```bash\nbun add @perryts\u002Fredis\nnpm install @perryts\u002Fredis\npnpm add @perryts\u002Fredis\n```\n\n```ts\nimport { connect } from '@perryts\u002Fredis';\n\nconst conn = await connect({ host: '127.0.0.1', port: 6379 });\n\nawait conn.command('SET', 'greeting', 'hello from perry');\nconst got = await conn.command\u003CBuffer>('GET', 'greeting');\nconsole.log(got.value?.toString('utf8'));   \u002F\u002F → 'hello from perry'\n\nawait conn.close();\n```\n\n## Why another Redis driver?\n\nMost Node Redis clients (`ioredis`, `node-redis`) work great on V8 but\nmake assumptions a strict TypeScript-to-native compiler can't honor:\nruntime-mutable prototypes, dynamic method dispatch, `process.nextTick`,\nEventEmitter inheritance, `require('hiredis')` for parsing speed. None\nof those translate cleanly to a Perry binary.\n\n`@perryts\u002Fredis` was designed against the Perry AOT constraint set from\nday one: module-level state maps instead of `this.method` closures,\nexplicit branching instead of `?.` \u002F `??`, no for-of on arrays, no\ndynamic key access. The same source compiles to a native binary AND\nruns unchanged on Node.js \u002F Bun.\n\n## Features\n\n- **RESP2 + RESP3** — both parsers ship from day one. `HELLO 3` is\n  tried by default; on `-NOPROTO` we fall back to RESP2 + legacy AUTH\n  transparently.\n- **Authentication** — legacy `requirepass`, ACL (`HELLO 3 AUTH user pass`),\n  pluggable via `registerAuthPlugin`.\n- **TLS** — full TLS-from-SYN via `rediss:\u002F\u002F` (no mid-stream upgrade).\n- **Pipelining** — `client.pipeline().add(...).add(...).exec()` writes\n  N commands in one syscall; per-command errors don't fail the batch.\n- **Pub\u002FSub** — `client.subscribe(chan, cb)` works against both RESP2\n  array messages and RESP3 push frames; the callback shape is uniform.\n- **Transactions** — `client.multi()` builder; WATCH-abort returns\n  `{ aborted: true }` cleanly.\n- **Scripts** — `client.eval` \u002F `client.evalsha` with automatic\n  `-NOSCRIPT` retry via cached source.\n- **Client-side caching** — `client.tracking.enable({...})` +\n  `tracking.on('invalidate', cb)` for RESP3 invalidation pushes.\n- **Blocking commands** — `client.blockingCommand(args, timeoutMs)`\n  sets a pool-visible busy flag so BLPOP \u002F WAIT \u002F XREAD BLOCK don't\n  break pooling.\n- **Cluster** — CRC16 slot routing, MOVED\u002FASK redirection, per-node\n  pools, hashtag co-location.\n- **Pool** — idle set + waiting queue + RESET-on-release.\n- **Cancel** — second-connection `CLIENT KILL ID \u003Cid>`.\n- **URLs and env vars** — `redis:\u002F\u002F`, `rediss:\u002F\u002F`, `unix:\u002F\u002F`,\n  `REDIS_URL`, `REDIS_HOST`, `REDIS_PORT`, `REDIS_USERNAME`,\n  `REDIS_PASSWORD`, `REDIS_DB`, `REDIS_TLS`, `REDIS_NAME`.\n- **Zero native dependencies**. Pure TypeScript over `Buffer`,\n  `node:net`, `node:tls`, `node:crypto`. Nothing to rebuild per platform.\n- **GUI-shaped result surface**. `CommandReply` carries the decoded\n  value, the RESP type tag, and the raw `RespValue` for byte-exact\n  round-trip in tools like Tusk.\n\n## Runtime targets\n\n| Runtime          | Status   | Notes                                                                             |\n| ---------------- | -------- | --------------------------------------------------------------------------------- |\n| **Perry** (AOT → native) | supported | Same source, compiled via LLVM. No JS runtime at execution time.        |\n| **Node.js ≥ 22** | supported | Uses `node:net`, `node:tls`, `node:crypto`, `Buffer`.                              |\n| **Bun ≥ 1.3**    | supported | Fully works; TLS-from-SYN bypasses Bun's known mid-stream upgrade quirk.           |\n\n## Quickstart\n\n### Connecting\n\n```ts\n\u002F\u002F Object form\nconst conn = await connect({\n  host: '127.0.0.1', port: 6379,\n  username: 'alice', password: 'acltestpw',  \u002F\u002F ACL — both required\n  database: 0,\n  name: 'tusk-client-1',                    \u002F\u002F CLIENT SETNAME via HELLO\n});\n\n\u002F\u002F URL form (via `resolveConnectOptions`)\nimport { resolveConnectOptions } from '@perryts\u002Fredis';\nconst conn = await connect(resolveConnectOptions({\n  url: 'redis:\u002F\u002Falice:acltestpw@db.internal:6379\u002F0?name=tusk-client-1',\n}));\n\n\u002F\u002F TLS\nconst conn = await connect(resolveConnectOptions({\n  url: 'rediss:\u002F\u002Fdb.internal:6380?tls=verify-full',\n}));\n```\n\n### Pool\n\n```ts\nimport { Pool } from '@perryts\u002Fredis';\nconst pool = new Pool({ host: '127.0.0.1', port: 6379, max: 10 });\n\n\u002F\u002F Acquire + run + release in one call:\nconst r = await pool.command('GET', 'key');\n\n\u002F\u002F Or manually:\nawait pool.withConnection(async (conn) => {\n  await conn.command('MULTI');\n  await conn.command('SET', 'a', '1');\n  await conn.command('EXEC');\n});\n\nawait pool.close();\n```\n\n### Pipelining\n\n```ts\nconst p = conn.pipeline();\nfor (let i = 0; i \u003C 1000; i++) p.add('SET', 'k' + i, String(i));\nconst replies = await p.exec();\n\u002F\u002F replies[i] = { ok: true, value: CommandReply } | { ok: false, error: RedisError }\n```\n\n### Pub\u002FSub\n\n```ts\nawait conn.subscribe('news', (msg) => {\n  console.log(msg.channel, msg.payload.toString('utf8'));\n});\n```\n\n### Transactions\n\n```ts\nconst m = conn.multi();\nm.add('SET', 'a', '1');\nm.add('SET', 'b', '2');\nconst out = await m.exec();\n\u002F\u002F out[i] = { ok: true, value: CommandReply } | { ok: false, error } | { aborted: true }\n```\n\n### Scripts\n\n```ts\nimport { evalScript, evalShaScript, sha1Hex } from '@perryts\u002Fredis';\nconst sha1 = sha1Hex(\"return tonumber(ARGV[1]) * 2\");\nawait evalScript(conn, \"return tonumber(ARGV[1]) * 2\", [], ['21']);\nawait evalShaScript(conn, sha1, [], ['21']);  \u002F\u002F auto-retries on -NOSCRIPT\n```\n\n### Cluster\n\n```ts\nimport { ClusterClient } from '@perryts\u002Fredis';\nconst cluster = new ClusterClient({\n  nodes: [\n    { host: 'cluster1', port: 7001 },\n    { host: 'cluster2', port: 7002 },\n    { host: 'cluster3', port: 7003 },\n  ],\n  password: 'secret',\n});\nawait cluster.command('SET', 'user:{1000}.profile', JSON.stringify({...}));\n```\n\n## Development\n\n```bash\nbun install\nbun test                    # unit + mock-server integration tests\nbun run typecheck           # tsc --noEmit\nbun run build               # tsc → dist\u002F\n\n# Live-server tests (requires a running Redis):\nredis-server --port 36379 --daemonize yes\nREDIS_HOST=127.0.0.1 REDIS_PORT=36379 bun test tests\u002Fintegration\u002Freal-server.test.ts\n```\n\n## License\n\nMIT — see [LICENSE](.\u002FLICENSE).\n","@perryts\u002Fredis 是一个纯 TypeScript 编写的 Redis 和 Valkey 通信协议驱动程序，无需任何本地插件或 FFI 转接层。该项目的核心功能包括支持 RESP2 和 RESP3 协议解析、认证机制、TLS 加密连接、管道操作、发布\u002F订阅模式、事务处理、脚本执行、客户端缓存及阻塞命令等。特别之处在于其能够通过 Perry（基于 LLVM 的 TypeScript 到原生代码编译器）将同一源码提前编译为独立的原生二进制文件，同时保持在 Node.js 和 Bun 环境中的兼容性。适用于需要高性能且对运行时环境依赖较小的 Redis 客户端开发场景。",2,"2026-06-11 04:05:46","CREATED_QUERY"]