{"_id":"@douglance/stdb-eslint-plugin","name":"@douglance/stdb-eslint-plugin","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@douglance/stdb-eslint-plugin","version":"1.0.0","description":"ESLint rules for SpacetimeDB V8 runtime pitfalls - catch serialization bugs at IDE level","main":"index.js","keywords":["eslint","eslintplugin","spacetimedb","v8","serialization"],"author":{"name":"SpacetimeDB Community"},"license":"MIT","peerDependencies":{"eslint":">=8.0.0"},"devDependencies":{"eslint":"^8.57.0","@eslint/eslintrc":"^2.1.4"},"scripts":{"test":"node tests/runner.js"},"engines":{"node":">=16.0.0"},"_id":"@douglance/stdb-eslint-plugin@1.0.0","gitHead":"d95209c60e55e862b01f3a505241d5059eacf573","_nodeVersion":"23.10.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-HV+AUPkoymaLrqKoY1jcEQOZSHma2c8ZsY4OeBA94eg2+LZISHfDOpoCrB6L3m34DG85I7mfBx2pp2rBEhXJNA==","shasum":"fcbc98f06a008c2f7bab2a8fbb2a50a9fbb8acfb","tarball":"https://registry.npmjs.org/@douglance/stdb-eslint-plugin/-/stdb-eslint-plugin-1.0.0.tgz","fileCount":8,"unpackedSize":12041,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDFOoPHYKQeUkrWJbsK2I8wkqCvymQZiDSAbWjMnXGcAAIgbYCM0qoLSEFPI1GriAa0rSYXbsaxRSOEoxQB2hkc81w="}]},"_npmUser":{"name":"douglance","email":"douglance@gmail.com"},"directories":{},"maintainers":[{"name":"douglance","email":"douglance@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/stdb-eslint-plugin_1.0.0_1761473568224_0.4811035723669308"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-26T10:12:48.140Z","1.0.0":"2025-10-26T10:12:48.428Z","modified":"2025-10-26T10:12:48.729Z"},"maintainers":[{"name":"douglance","email":"douglance@gmail.com"}],"description":"ESLint rules for SpacetimeDB V8 runtime pitfalls - catch serialization bugs at IDE level","keywords":["eslint","eslintplugin","spacetimedb","v8","serialization"],"author":{"name":"SpacetimeDB Community"},"license":"MIT","readme":"# @spacetimedb/eslint-plugin\n\nESLint plugin that catches SpacetimeDB V8 runtime serialization bugs at IDE level, preventing runtime crashes before they reach production.\n\n## Installation\n\n```bash\nnpm install --save-dev @spacetimedb/eslint-plugin\n```\n\n## Usage\n\nAdd to your `.eslintrc.js`:\n\n```javascript\nmodule.exports = {\n  plugins: ['@spacetimedb'],\n  extends: ['plugin:@spacetimedb/recommended'],\n};\n```\n\nOr configure rules individually:\n\n```javascript\nmodule.exports = {\n  plugins: ['@spacetimedb'],\n  rules: {\n    '@spacetimedb/no-template-literals-in-reducer': 'error',\n    '@spacetimedb/no-foreach-in-reducer': 'error',\n    '@spacetimedb/no-filter-on-table-iter': 'warn',\n    '@spacetimedb/no-insert-id-in-lifecycle-hooks': 'error',\n  },\n};\n```\n\n## Rules\n\n### `no-template-literals-in-reducer` (error)\n\n**Problem:** Template literals cause `TypeError: r.charCodeAt is not a function` due to V8 serialization bugs.\n\n**Before:**\n```typescript\ngameSchema.reducer('join_game', {}, (ctx) => {\n  console.log(`Player ${ctx.sender} joined`); // ❌ RUNTIME CRASH\n});\n```\n\n**After:**\n```typescript\ngameSchema.reducer('join_game', {}, (ctx) => {\n  const sender = String(ctx.sender);\n  console.log(\"Player \" + sender + \" joined\"); // ✅ WORKS\n});\n```\n\n---\n\n### `no-foreach-in-reducer` (error)\n\n**Problem:** `forEach` with closures causes silent serialization failures that break table operations.\n\n**Before:**\n```typescript\ngameSchema.reducer('update_all', {}, (ctx) => {\n  lobbies.forEach(lobby => { // ❌ SERIALIZATION FAILURE\n    ctx.db.Lobby.update(lobby);\n  });\n});\n```\n\n**After:**\n```typescript\ngameSchema.reducer('update_all', {}, (ctx) => {\n  for (let i = 0; i < lobbies.length; i++) { // ✅ WORKS\n    const lobby = lobbies[i];\n    ctx.db.Lobby.update(lobby);\n  }\n});\n```\n\n---\n\n### `no-filter-on-table-iter` (warning)\n\n**Problem:** Calling `.filter()` on table iterators or indexed accessors causes runtime crashes.\n\n**Before:**\n```typescript\nconst members = ctx.db.LobbyMembership.byLobby.filter([lobbyId]); // ❌ CRASH\n```\n\n**After:**\n```typescript\nconst members = [];\nfor (const m of ctx.db.LobbyMembership.iter()) {\n  if (m.lobbyId === lobbyId) members.push(m); // ✅ WORKS\n}\n```\n\n---\n\n### `no-insert-id-in-lifecycle-hooks` (error)\n\n**Problem:** Using `Entity.insert().id` in `clientConnected`/`clientDisconnected` causes `TypeError: Cannot read properties of undefined (reading '__identity__')`.\n\n**Before:**\n```typescript\ngameSchema.clientConnected((ctx) => {\n  const entityId = ctx.db.Entity.insert({}).id; // ❌ CRASH\n  ctx.db.Position.insert({ entity_id: entityId });\n});\n```\n\n**After (Option 1: Separate reducer):**\n```typescript\ngameSchema.clientConnected((ctx) => {\n  // Don't spawn entities here\n});\n\ngameSchema.reducer('spawn_entity', {}, (ctx) => {\n  const entityId = ctx.db.Entity.insert({}).id; // ✅ WORKS\n  ctx.db.Position.insert({ entity_id: entityId });\n});\n```\n\n**After (Option 2: Scheduled reducer):**\n```typescript\ngameSchema.reducer('game_tick', ScheduledTickArgs, (ctx) => {\n  const entityId = ctx.db.Entity.insert({}).id; // ✅ WORKS\n  ctx.db.Position.insert({ entity_id: entityId });\n});\n```\n\n---\n\n## Why This Plugin Exists\n\nSpacetimeDB runs reducer code in a V8 JavaScript runtime with custom serialization. Certain JavaScript patterns that work perfectly in Node.js or browsers trigger serialization bugs in SpacetimeDB's runtime, causing:\n\n- `TypeError: r.charCodeAt is not a function`\n- `TypeError: Cannot convert [object Object] to a BigInt`\n- `TypeError: Cannot read properties of undefined`\n- Silent failures where operations appear to succeed but data never persists\n\nThese bugs are nearly impossible to debug because:\n1. Code looks correct and passes type checking\n2. Errors only occur at runtime after publishing to SpacetimeDB\n3. Error messages don't indicate the root cause\n4. No local development environment can reproduce them\n\nThis plugin brings these runtime failures into your IDE as red squiggly lines, making them impossible to commit.\n\n## Testing\n\n```bash\nnpm test\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-fbaf8ba37b3a14b46c81097888633891"}