{"id":51189163,"url":"https://github.com/tinyland-inc/tinyland-auth-redis","last_synced_at":"2026-06-27T13:03:53.557Z","repository":{"id":346442281,"uuid":"1189011341","full_name":"tinyland-inc/tinyland-auth-redis","owner":"tinyland-inc","description":"Redis storage adapter for @tummycrypt/tinyland-auth (Upstash)","archived":false,"fork":false,"pushed_at":"2026-05-27T15:08:31.000Z","size":94,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T15:18:11.138Z","etag":null,"topics":["auth","bazel-module","persistence","pulse-live-authority","redis"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinyland-inc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-22T21:53:05.000Z","updated_at":"2026-05-27T15:08:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tinyland-inc/tinyland-auth-redis","commit_stats":null,"previous_names":["tinyland-inc/tinyland-auth-redis"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/tinyland-inc/tinyland-auth-redis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyland-inc%2Ftinyland-auth-redis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyland-inc%2Ftinyland-auth-redis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyland-inc%2Ftinyland-auth-redis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyland-inc%2Ftinyland-auth-redis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinyland-inc","download_url":"https://codeload.github.com/tinyland-inc/tinyland-auth-redis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyland-inc%2Ftinyland-auth-redis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34854226,"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-27T02:00:06.362Z","response_time":126,"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":["auth","bazel-module","persistence","pulse-live-authority","redis"],"created_at":"2026-06-27T13:03:52.960Z","updated_at":"2026-06-27T13:03:53.552Z","avatar_url":"https://github.com/tinyland-inc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @tummycrypt/tinyland-auth-redis\n\nRedis storage adapter for [@tummycrypt/tinyland-auth](https://www.npmjs.com/package/@tummycrypt/tinyland-auth), backed by [Upstash Redis](https://upstash.com/) (`@upstash/redis`).\n\nImplements the full `IStorageAdapter` interface: users, sessions, TOTP secrets, backup codes, invitations, and audit events.\n\n## Installation\n\nCurrent Bazel-first release authority is the GitHub release/tag, GitHub\nPackages artifact, and Tinyland Bazel registry module. The npmjs\n`@tummycrypt/tinyland-auth-redis` package remains a legacy compatibility surface\nand may lag the current release.\n\n```bash\nnpm install @tummycrypt/tinyland-auth-redis\n# or\npnpm add @tummycrypt/tinyland-auth-redis\n```\n\nPeer dependency:\n\n```bash\nnpm install @tummycrypt/tinyland-auth\n```\n\n`@tummycrypt/tinyland-auth-redis` accepts `@tummycrypt/tinyland-auth`\n`^0.2.0 || ^0.3.0`. The package test/build lane uses the latest 0.3 line so the\nRedis adapter stays compatible with the current auth contract.\n\n## Quick Start\n\n```typescript\nimport { createRedisStorageAdapter } from '@tummycrypt/tinyland-auth-redis';\n\nconst storage = createRedisStorageAdapter({\n  url: process.env.KV_REST_API_URL,\n  token: process.env.KV_REST_API_TOKEN,\n  prefix: 'auth',           // optional, default: 'auth'\n  sessionMaxAge: 7 * 24 * 60 * 60 * 1000, // optional, default: 7 days\n});\n\nawait storage.init(); // verifies connectivity with PING\n```\n\n### Using an Existing Redis Instance\n\n```typescript\nimport { Redis } from '@upstash/redis';\nimport { createRedisStorageAdapter } from '@tummycrypt/tinyland-auth-redis';\n\nconst redis = new Redis({\n  url: process.env.KV_REST_API_URL!,\n  token: process.env.KV_REST_API_TOKEN!,\n});\n\nconst storage = createRedisStorageAdapter({ redis });\n```\n\n## Graceful Fallback\n\nWhen Redis is unavailable (e.g., local development without Upstash credentials), fall back to an in-memory Map:\n\n```typescript\nimport { createRedisStorageAdapter } from '@tummycrypt/tinyland-auth-redis';\n\nconst createStorage = () =\u003e {\n  const url = process.env.KV_REST_API_URL;\n  const token = process.env.KV_REST_API_TOKEN;\n\n  if (url \u0026\u0026 token) {\n    return createRedisStorageAdapter({ url, token });\n  }\n\n  console.warn('Redis not configured, using in-memory fallback');\n  // Use your own in-memory adapter or the one from tinyland-auth\n  return createInMemoryAdapter();\n};\n```\n\n## Key Namespacing\n\nAll keys are namespaced under a configurable prefix (default: `auth`). This allows multiple applications to share a single Redis instance without collisions.\n\n| Pattern | Example | Purpose |\n|---------|---------|---------|\n| `{prefix}:user:{id}` | `auth:user:abc-123` | User entity |\n| `{prefix}:user:handle:{handle}` | `auth:user:handle:jen` | Handle lookup index |\n| `{prefix}:user:email:{email}` | `auth:user:email:jen@example.com` | Email lookup index |\n| `{prefix}:users:all` | `auth:users:all` | Set of all user IDs |\n| `{prefix}:session:{id}` | `auth:session:sess-1` | Session entity |\n| `{prefix}:sessions:user:{userId}` | `auth:sessions:user:abc-123` | Sorted set of session IDs by expiry |\n| `{prefix}:totp:{handle}` | `auth:totp:jen` | Encrypted TOTP secret |\n| `{prefix}:backup:{userId}` | `auth:backup:abc-123` | Backup codes |\n| `{prefix}:invite:{token}` | `auth:invite:tok-abc` | Invitation entity |\n| `{prefix}:invite:id:{id}` | `auth:invite:id:inv-1` | Invitation ID to token index |\n| `{prefix}:invites:all` | `auth:invites:all` | Set of all invitation tokens |\n| `{prefix}:invites:pending` | `auth:invites:pending` | Set of pending invitation tokens |\n| `{prefix}:audit:{id}` | `auth:audit:evt_123_abc` | Audit event entity |\n| `{prefix}:audit:log` | `auth:audit:log` | Sorted set of audit event IDs by timestamp |\n\n## API Reference\n\n### `createRedisStorageAdapter(config: RedisStorageConfig): RedisStorageAdapter`\n\nFactory function. Accepts:\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `redis` | `Redis` | - | Existing Upstash Redis instance |\n| `url` | `string` | - | Upstash REST URL (used if `redis` not provided) |\n| `token` | `string` | - | Upstash REST token (used if `redis` not provided) |\n| `prefix` | `string` | `'auth'` | Key namespace prefix |\n| `sessionMaxAge` | `number` | `604800000` | Session TTL in milliseconds (7 days) |\n\n### `RedisStorageAdapter` (implements `IStorageAdapter`)\n\n**Lifecycle:**\n- `init()` - Verify Redis connectivity (PING)\n- `close()` - No-op (Upstash uses HTTP, no persistent connection)\n\n**Users:** `getUser`, `getUserByHandle`, `getUserByEmail`, `getAllUsers`, `createUser`, `updateUser`, `deleteUser`, `hasUsers`\n\n**Sessions:** `getSession`, `getSessionsByUser`, `getAllSessions`, `createSession`, `updateSession`, `deleteSession`, `deleteUserSessions`, `cleanupExpiredSessions`\n\n**TOTP:** `getTOTPSecret`, `saveTOTPSecret`, `deleteTOTPSecret`\n\n**Backup Codes:** `getBackupCodes`, `saveBackupCodes`, `deleteBackupCodes`\n\n**Invitations:** `getInvitation`, `getInvitationById`, `getAllInvitations`, `getPendingInvitations`, `createInvitation`, `updateInvitation`, `deleteInvitation`, `cleanupExpiredInvitations`\n\n**Audit:** `logAuditEvent`, `getAuditEvents`, `getRecentAuditEvents`\n\n### Serialization Utilities\n\nExported for advanced use cases:\n\n```typescript\nimport { serialize, deserialize, toHashFields, fromHashFields } from '@tummycrypt/tinyland-auth-redis';\n```\n\n- `serialize\u003cT\u003e(value: T): string` - Safe JSON.stringify wrapper\n- `deserialize\u003cT\u003e(value: string | null): T | null` - Safe JSON.parse with null handling\n- `toHashFields(obj: Record\u003cstring, unknown\u003e): Record\u003cstring, string\u003e` - Convert to Redis HSET-compatible flat map\n- `fromHashFields\u003cT\u003e(hash: Record\u003cstring, string\u003e | null): T | null` - Parse Redis HGETALL result back to typed object\n\n### Key Generators\n\n```typescript\nimport { createKeys } from '@tummycrypt/tinyland-auth-redis';\n\nconst keys = createKeys('myapp');\nkeys.user('abc-123');      // 'myapp:user:abc-123'\nkeys.session('sess-1');    // 'myapp:session:sess-1'\nkeys.auditLog();           // 'myapp:audit:log'\n```\n\n## Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `KV_REST_API_URL` | Yes | Upstash Redis REST URL |\n| `KV_REST_API_TOKEN` | Yes | Upstash Redis REST token |\n\nThese are the standard environment variable names used by Vercel KV (Upstash integration).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyland-inc%2Ftinyland-auth-redis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinyland-inc%2Ftinyland-auth-redis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyland-inc%2Ftinyland-auth-redis/lists"}