@waynesutton/convex-skills 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -1
- package/README.md +25 -5
- package/bin/cli.js +63 -19
- package/index.js +0 -1
- package/package.json +3 -3
- package/skills/convex-best-practices/SKILL.md +21 -3
- package/skills/convex-functions/SKILL.md +1 -1
- package/skills/convex-eslint/SKILL.md +0 -145
package/AGENTS.md
CHANGED
|
@@ -40,7 +40,6 @@ This repository provides two complementary approaches for AI coding agents:
|
|
|
40
40
|
| Skill | Description |
|
|
41
41
|
| ------------------------------------------------------------------------ | ----------------------------------------------------- |
|
|
42
42
|
| [convex-best-practices](skills/convex-best-practices/SKILL.md) | Guidelines for building production-ready Convex apps |
|
|
43
|
-
| [convex-eslint](skills/convex-eslint/SKILL.md) | Write linter-compliant Convex code |
|
|
44
43
|
| [convex-functions](skills/convex-functions/SKILL.md) | Writing queries, mutations, actions, and HTTP actions |
|
|
45
44
|
| [convex-realtime](skills/convex-realtime/SKILL.md) | Patterns for building reactive applications |
|
|
46
45
|
| [convex-schema-validator](skills/convex-schema-validator/SKILL.md) | Database schema definition and validation |
|
package/README.md
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
# Convex
|
|
1
|
+
# For official Convex Skills use Convex Agent Plugins
|
|
2
|
+
|
|
3
|
+
Official Convex plugins for AI coding agents, providing development tools for building reactive backends with TypeScript.
|
|
4
|
+
|
|
5
|
+
https://github.com/get-convex/convex-agent-plugins
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Convex (unofficial) Skills
|
|
2
9
|
|
|
3
10
|
[](https://www.npmjs.com/package/@waynesutton/convex-skills)
|
|
4
11
|
[](LICENSE)
|
|
@@ -16,7 +23,7 @@ All skills are designed to produce code that passes @convex-dev/eslint-plugin by
|
|
|
16
23
|
- **Skills** prevent mistakes at generation time
|
|
17
24
|
- **ESLint** catches anything that slips through at build time
|
|
18
25
|
|
|
19
|
-
See the [convex-
|
|
26
|
+
See the Code Quality section in [convex-best-practices](/skills/convex-best-practices/SKILL.md) for setup instructions.
|
|
20
27
|
|
|
21
28
|
## Installation
|
|
22
29
|
|
|
@@ -35,6 +42,12 @@ convex-skills install convex-best-practices
|
|
|
35
42
|
# Install all skills
|
|
36
43
|
convex-skills install-all
|
|
37
44
|
|
|
45
|
+
# Install all skills to .agents/skills
|
|
46
|
+
convex-skills install-all --target agents
|
|
47
|
+
|
|
48
|
+
# Symlink SKILL.md files instead of copying
|
|
49
|
+
convex-skills install-all --target agents --link
|
|
50
|
+
|
|
38
51
|
# Install templates (CLAUDE.md + skill templates)
|
|
39
52
|
convex-skills install-templates
|
|
40
53
|
```
|
|
@@ -84,6 +97,15 @@ Codex will auto-discover `SKILL.md` files in that directory on the next start.
|
|
|
84
97
|
|
|
85
98
|
If you are working from a repo clone, Codex also auto-discovers skills from `.codex/skills` at the repo root. You can symlink this repo’s `skills/*` into `.codex/skills` so updates flow through without copying.
|
|
86
99
|
|
|
100
|
+
### Standard Agent Skills Path
|
|
101
|
+
|
|
102
|
+
Some tools are standardizing on `.agents/skills` for discovery. This repo supports that layout via the CLI:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
convex-skills install-all --target agents
|
|
106
|
+
convex-skills install-all --target agents --link
|
|
107
|
+
```
|
|
108
|
+
|
|
87
109
|
### OpenCode
|
|
88
110
|
|
|
89
111
|
OpenCode discovers skills from `~/.claude/skills/<name>/SKILL.md` automatically. See OpenCode Skills docs for more details.
|
|
@@ -113,7 +135,6 @@ Copy the desired skill's `SKILL.md` file to your project's `.claude/skills/` dir
|
|
|
113
135
|
| Skill | Description |
|
|
114
136
|
| ------------------------------------------------------------------------ | ----------------------------------------------------- |
|
|
115
137
|
| [convex-best-practices](skills/convex-best-practices/SKILL.md) | Guidelines for building production-ready Convex apps |
|
|
116
|
-
| [convex-eslint](skills/convex-eslint/SKILL.md) | Write linter-compliant Convex code |
|
|
117
138
|
| [convex-functions](skills/convex-functions/SKILL.md) | Writing queries, mutations, actions, and HTTP actions |
|
|
118
139
|
| [convex-realtime](skills/convex-realtime/SKILL.md) | Patterns for building reactive applications |
|
|
119
140
|
| [convex-schema-validator](skills/convex-schema-validator/SKILL.md) | Database schema definition and validation |
|
|
@@ -133,8 +154,6 @@ convex-skills/
|
|
|
133
154
|
├── skills/ # Core Convex skills for AI agents
|
|
134
155
|
│ ├── convex-best-practices/
|
|
135
156
|
│ │ └── SKILL.md
|
|
136
|
-
│ ├── convex-eslint/
|
|
137
|
-
│ │ └── SKILL.md
|
|
138
157
|
│ ├── convex-functions/
|
|
139
158
|
│ │ └── SKILL.md
|
|
140
159
|
│ ├── convex-cron-jobs/
|
|
@@ -142,6 +161,7 @@ convex-skills/
|
|
|
142
161
|
│ └── ...
|
|
143
162
|
├── .codex/ # Codex integration (symlink skills here)
|
|
144
163
|
│ └── README.md # Codex setup instructions
|
|
164
|
+
├── .agents/ # Standard agent skills path
|
|
145
165
|
├── command/ # Slash command definitions (OpenCode)
|
|
146
166
|
│ └── convex.md # /convex command entrypoint
|
|
147
167
|
├── templates/ # Templates for forking developers
|
package/bin/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
existsSync,
|
|
10
10
|
copyFileSync,
|
|
11
11
|
readdirSync,
|
|
12
|
+
symlinkSync,
|
|
12
13
|
} from "fs";
|
|
13
14
|
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -18,7 +19,6 @@ const packageRoot = join(__dirname, "..");
|
|
|
18
19
|
const SKILLS = {
|
|
19
20
|
"convex-best-practices":
|
|
20
21
|
"Guidelines for building production-ready Convex apps",
|
|
21
|
-
"convex-eslint": "Write linter-compliant Convex code",
|
|
22
22
|
"convex-functions": "Writing queries, mutations, actions, and HTTP actions",
|
|
23
23
|
"convex-realtime": "Patterns for building reactive applications",
|
|
24
24
|
"convex-schema-validator": "Database schema definition and validation",
|
|
@@ -32,6 +32,12 @@ const SKILLS = {
|
|
|
32
32
|
"convex-component-authoring": "Creating reusable Convex components",
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
const TARGET_ALIASES = new Map([
|
|
36
|
+
["claude", ".claude/skills"],
|
|
37
|
+
["codex", ".codex/skills"],
|
|
38
|
+
["agents", ".agents/skills"],
|
|
39
|
+
]);
|
|
40
|
+
|
|
35
41
|
function printHelp() {
|
|
36
42
|
console.log(`
|
|
37
43
|
convex-skills - Agent skills for building Convex applications
|
|
@@ -49,12 +55,17 @@ COMMANDS:
|
|
|
49
55
|
|
|
50
56
|
OPTIONS:
|
|
51
57
|
--dir <path> Target directory (default: current directory)
|
|
58
|
+
--target <name|path> Install target: claude, codex, agents, or a path
|
|
59
|
+
--link Symlink SKILL.md instead of copying
|
|
52
60
|
--help, -h Show this help message
|
|
53
61
|
|
|
54
62
|
EXAMPLES:
|
|
55
63
|
convex-skills list
|
|
56
64
|
convex-skills install convex-best-practices
|
|
57
65
|
convex-skills install-all
|
|
66
|
+
convex-skills install-all --target agents
|
|
67
|
+
convex-skills install convex-functions --target .agents/skills
|
|
68
|
+
convex-skills install convex-best-practices --target codex --link
|
|
58
69
|
convex-skills install-templates
|
|
59
70
|
convex-skills show convex-functions
|
|
60
71
|
|
|
@@ -73,7 +84,27 @@ function listSkills() {
|
|
|
73
84
|
console.log("");
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
function
|
|
87
|
+
function ensureDir(dirPath) {
|
|
88
|
+
if (!existsSync(dirPath)) {
|
|
89
|
+
mkdirSync(dirPath, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function resolveTargetSkillsDir(targetDir, target) {
|
|
94
|
+
if (!target) {
|
|
95
|
+
return join(targetDir, ".claude", "skills");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const alias = TARGET_ALIASES.get(target);
|
|
99
|
+
if (alias) {
|
|
100
|
+
return join(targetDir, alias);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const resolved = resolve(targetDir, target);
|
|
104
|
+
return resolved.endsWith("skills") ? resolved : join(resolved, "skills");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function installSkill(skillName, targetSkillsDir, useSymlink) {
|
|
77
108
|
const skillsPath = join(packageRoot, "skills", skillName, "SKILL.md");
|
|
78
109
|
|
|
79
110
|
if (!existsSync(skillsPath)) {
|
|
@@ -82,24 +113,24 @@ function installSkill(skillName, targetDir) {
|
|
|
82
113
|
process.exit(1);
|
|
83
114
|
}
|
|
84
115
|
|
|
85
|
-
const targetPath = join(
|
|
86
|
-
targetDir,
|
|
87
|
-
".claude",
|
|
88
|
-
"skills",
|
|
89
|
-
skillName,
|
|
90
|
-
"SKILL.md",
|
|
91
|
-
);
|
|
116
|
+
const targetPath = join(targetSkillsDir, skillName, "SKILL.md");
|
|
92
117
|
const targetSkillDir = dirname(targetPath);
|
|
93
118
|
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
ensureDir(targetSkillDir);
|
|
120
|
+
|
|
121
|
+
if (useSymlink) {
|
|
122
|
+
if (!existsSync(targetPath)) {
|
|
123
|
+
symlinkSync(skillsPath, targetPath);
|
|
124
|
+
}
|
|
125
|
+
console.log(`Linked ${skillName} to ${targetPath}`);
|
|
126
|
+
return;
|
|
96
127
|
}
|
|
97
128
|
|
|
98
129
|
copyFileSync(skillsPath, targetPath);
|
|
99
130
|
console.log(`Installed ${skillName} to ${targetPath}`);
|
|
100
131
|
}
|
|
101
132
|
|
|
102
|
-
function installAllSkills(
|
|
133
|
+
function installAllSkills(targetSkillsDir, useSymlink) {
|
|
103
134
|
const skillsDir = join(packageRoot, "skills");
|
|
104
135
|
const skills = readdirSync(skillsDir, { withFileTypes: true })
|
|
105
136
|
.filter((dirent) => dirent.isDirectory())
|
|
@@ -108,11 +139,11 @@ function installAllSkills(targetDir) {
|
|
|
108
139
|
console.log(`Installing ${skills.length} skills...\n`);
|
|
109
140
|
|
|
110
141
|
skills.forEach((skillName) => {
|
|
111
|
-
installSkill(skillName,
|
|
142
|
+
installSkill(skillName, targetSkillsDir, useSymlink);
|
|
112
143
|
});
|
|
113
144
|
|
|
114
145
|
console.log(
|
|
115
|
-
`\nDone! Installed ${skills.length} skills to ${
|
|
146
|
+
`\nDone! Installed ${skills.length} skills to ${targetSkillsDir}`,
|
|
116
147
|
);
|
|
117
148
|
}
|
|
118
149
|
|
|
@@ -139,9 +170,7 @@ function installTemplates(targetDir) {
|
|
|
139
170
|
);
|
|
140
171
|
const targetSkillsDir = join(targetDir, ".claude", "skills");
|
|
141
172
|
|
|
142
|
-
|
|
143
|
-
mkdirSync(targetSkillsDir, { recursive: true });
|
|
144
|
-
}
|
|
173
|
+
ensureDir(targetSkillsDir);
|
|
145
174
|
|
|
146
175
|
templates.forEach((template) => {
|
|
147
176
|
const src = join(skillTemplatesDir, template);
|
|
@@ -184,6 +213,8 @@ function printSkillPath(skillName) {
|
|
|
184
213
|
// Parse arguments
|
|
185
214
|
const args = process.argv.slice(2);
|
|
186
215
|
let targetDir = process.cwd();
|
|
216
|
+
let target = null;
|
|
217
|
+
let useSymlink = false;
|
|
187
218
|
|
|
188
219
|
// Check for --dir flag
|
|
189
220
|
const dirIndex = args.indexOf("--dir");
|
|
@@ -192,8 +223,21 @@ if (dirIndex !== -1 && args[dirIndex + 1]) {
|
|
|
192
223
|
args.splice(dirIndex, 2);
|
|
193
224
|
}
|
|
194
225
|
|
|
226
|
+
const targetIndex = args.indexOf("--target");
|
|
227
|
+
if (targetIndex !== -1 && args[targetIndex + 1]) {
|
|
228
|
+
target = args[targetIndex + 1];
|
|
229
|
+
args.splice(targetIndex, 2);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const linkIndex = args.indexOf("--link");
|
|
233
|
+
if (linkIndex !== -1) {
|
|
234
|
+
useSymlink = true;
|
|
235
|
+
args.splice(linkIndex, 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
195
238
|
const command = args[0];
|
|
196
239
|
const arg = args[1];
|
|
240
|
+
const targetSkillsDir = resolveTargetSkillsDir(targetDir, target);
|
|
197
241
|
|
|
198
242
|
switch (command) {
|
|
199
243
|
case "list":
|
|
@@ -205,10 +249,10 @@ switch (command) {
|
|
|
205
249
|
console.log("Run 'convex-skills list' to see available skills.");
|
|
206
250
|
process.exit(1);
|
|
207
251
|
}
|
|
208
|
-
installSkill(arg,
|
|
252
|
+
installSkill(arg, targetSkillsDir, useSymlink);
|
|
209
253
|
break;
|
|
210
254
|
case "install-all":
|
|
211
|
-
installAllSkills(
|
|
255
|
+
installAllSkills(targetSkillsDir, useSymlink);
|
|
212
256
|
break;
|
|
213
257
|
case "install-templates":
|
|
214
258
|
installTemplates(targetDir);
|
package/index.js
CHANGED
|
@@ -54,7 +54,6 @@ export function getSkillPath(skillName) {
|
|
|
54
54
|
export const SKILLS = {
|
|
55
55
|
"convex-best-practices":
|
|
56
56
|
"Guidelines for building production-ready Convex apps",
|
|
57
|
-
"convex-eslint": "Write linter-compliant Convex code",
|
|
58
57
|
"convex-functions": "Writing queries, mutations, actions, and HTTP actions",
|
|
59
58
|
"convex-realtime": "Patterns for building reactive applications",
|
|
60
59
|
"convex-schema-validator": "Database schema definition and validation",
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waynesutton/convex-skills",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"author": "Wayne Sutton",
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"description": "For official Convex Skills use Convex Agent Plugins at https://github.com/get-convex/convex-agent-plugins. This package provides unofficial agent skills for building production-ready Convex applications.",
|
|
5
|
+
"author": "Wayne Sutton - @waynesutton",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -9,14 +9,32 @@ Build production-ready Convex applications by following established patterns for
|
|
|
9
9
|
|
|
10
10
|
## Code Quality
|
|
11
11
|
|
|
12
|
-
All patterns in this skill comply with
|
|
13
|
-
Install the linter for build-time validation:
|
|
12
|
+
All patterns in this skill comply with `@convex-dev/eslint-plugin`. Install it for build-time validation:
|
|
14
13
|
|
|
15
14
|
```bash
|
|
16
15
|
npm i @convex-dev/eslint-plugin --save-dev
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
```js
|
|
19
|
+
// eslint.config.js
|
|
20
|
+
import { defineConfig } from "eslint/config";
|
|
21
|
+
import convexPlugin from "@convex-dev/eslint-plugin";
|
|
22
|
+
|
|
23
|
+
export default defineConfig([
|
|
24
|
+
...convexPlugin.configs.recommended,
|
|
25
|
+
]);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The plugin enforces four rules:
|
|
29
|
+
|
|
30
|
+
| Rule | What it enforces |
|
|
31
|
+
| ----------------------------------- | --------------------------------- |
|
|
32
|
+
| `no-old-registered-function-syntax` | Object syntax with `handler` |
|
|
33
|
+
| `require-argument-validators` | `args: {}` on all functions |
|
|
34
|
+
| `explicit-table-ids` | Table name in db operations |
|
|
35
|
+
| `import-wrong-runtime` | No Node imports in Convex runtime |
|
|
36
|
+
|
|
37
|
+
Docs: https://docs.convex.dev/eslint
|
|
20
38
|
|
|
21
39
|
## Documentation Sources
|
|
22
40
|
|
|
@@ -19,7 +19,7 @@ All examples in this skill comply with @convex-dev/eslint-plugin rules:
|
|
|
19
19
|
- Argument validators on all functions
|
|
20
20
|
- Explicit table names in database operations
|
|
21
21
|
|
|
22
|
-
See [convex-
|
|
22
|
+
See the Code Quality section in [convex-best-practices](../convex-best-practices/SKILL.md) for linting setup.
|
|
23
23
|
|
|
24
24
|
## Documentation Sources
|
|
25
25
|
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: convex-eslint
|
|
3
|
-
description: Write Convex code that passes @convex-dev/eslint-plugin rules by default
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
author: Convex
|
|
6
|
-
tags: [convex, eslint, linting, code-quality, validation]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Convex ESLint Compliance
|
|
10
|
-
|
|
11
|
-
Write all Convex functions to pass @convex-dev/eslint-plugin. These rules prevent common bugs, security issues, and ensure code quality.
|
|
12
|
-
|
|
13
|
-
## Documentation Sources
|
|
14
|
-
|
|
15
|
-
- https://docs.convex.dev/eslint
|
|
16
|
-
- https://www.npmjs.com/package/@convex-dev/eslint-plugin
|
|
17
|
-
|
|
18
|
-
## Setup
|
|
19
|
-
|
|
20
|
-
Install the plugin:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm i @convex-dev/eslint-plugin --save-dev
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Configure `eslint.config.js`:
|
|
27
|
-
|
|
28
|
-
```javascript
|
|
29
|
-
import { defineConfig } from "eslint/config";
|
|
30
|
-
import convexPlugin from "@convex-dev/eslint-plugin";
|
|
31
|
-
|
|
32
|
-
export default defineConfig([...convexPlugin.configs.recommended]);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Rules
|
|
36
|
-
|
|
37
|
-
### 1. no-old-registered-function-syntax
|
|
38
|
-
|
|
39
|
-
Always use object syntax with a `handler` property.
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// Correct
|
|
43
|
-
export const list = query({
|
|
44
|
-
args: {},
|
|
45
|
-
handler: async (ctx) => {
|
|
46
|
-
return await ctx.db.query("messages").collect();
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Wrong - bare function syntax
|
|
51
|
-
export const list = query(async (ctx) => {
|
|
52
|
-
return await ctx.db.query("messages").collect();
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 2. require-argument-validators
|
|
57
|
-
|
|
58
|
-
Always include `args` object, even when empty.
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
// Correct - with arguments
|
|
62
|
-
export const get = query({
|
|
63
|
-
args: { id: v.id("messages") },
|
|
64
|
-
handler: async (ctx, { id }) => {
|
|
65
|
-
return await ctx.db.get("messages", id);
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Correct - no arguments
|
|
70
|
-
export const listAll = query({
|
|
71
|
-
args: {},
|
|
72
|
-
handler: async (ctx) => {
|
|
73
|
-
return await ctx.db.query("messages").collect();
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Wrong - missing args
|
|
78
|
-
export const get = query({
|
|
79
|
-
handler: async (ctx, { id }: { id: Id<"messages"> }) => {
|
|
80
|
-
return await ctx.db.get("messages", id);
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 3. explicit-table-ids
|
|
86
|
-
|
|
87
|
-
Use explicit table names in all database operations (Convex 1.31.0+).
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
// Correct
|
|
91
|
-
const message = await ctx.db.get("messages", messageId);
|
|
92
|
-
await ctx.db.patch("messages", messageId, { text: "updated" });
|
|
93
|
-
await ctx.db.replace("messages", messageId, {
|
|
94
|
-
text: "replaced",
|
|
95
|
-
author: "Alice",
|
|
96
|
-
});
|
|
97
|
-
await ctx.db.delete("messages", messageId);
|
|
98
|
-
|
|
99
|
-
// Wrong - implicit table from ID type
|
|
100
|
-
const message = await ctx.db.get(messageId);
|
|
101
|
-
await ctx.db.patch(messageId, { text: "updated" });
|
|
102
|
-
await ctx.db.replace(messageId, { text: "replaced", author: "Alice" });
|
|
103
|
-
await ctx.db.delete(messageId);
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Migration codemod available:
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
npx @convex-dev/codemod@latest explicit-ids
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 4. import-wrong-runtime
|
|
113
|
-
|
|
114
|
-
Never import Node.js runtime files into Convex runtime files.
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
// convex/queries.ts (no "use node" directive)
|
|
118
|
-
|
|
119
|
-
// Correct - importing from Convex runtime file
|
|
120
|
-
import { helper } from "./utils"; // utils.ts has no "use node"
|
|
121
|
-
|
|
122
|
-
// Wrong - importing from Node runtime file
|
|
123
|
-
import { nodeHelper } from "./nodeUtils"; // nodeUtils.ts has "use node"
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Best Practices
|
|
127
|
-
|
|
128
|
-
1. Run ESLint before committing: `npx eslint convex/`
|
|
129
|
-
2. Use auto-fix for quick migrations: `npx eslint convex/ --fix`
|
|
130
|
-
3. Add to CI pipeline to catch violations early
|
|
131
|
-
4. Configure your editor for real-time feedback
|
|
132
|
-
|
|
133
|
-
## Quick Reference
|
|
134
|
-
|
|
135
|
-
| Rule | What it enforces |
|
|
136
|
-
| ----------------------------------- | --------------------------------- |
|
|
137
|
-
| `no-old-registered-function-syntax` | Object syntax with `handler` |
|
|
138
|
-
| `require-argument-validators` | `args: {}` on all functions |
|
|
139
|
-
| `explicit-table-ids` | Table name in db operations |
|
|
140
|
-
| `import-wrong-runtime` | No Node imports in Convex runtime |
|
|
141
|
-
|
|
142
|
-
## References
|
|
143
|
-
|
|
144
|
-
- [ESLint Plugin Docs](https://docs.convex.dev/eslint)
|
|
145
|
-
- [Explicit IDs Announcement](https://news.convex.dev/db-table-name/)
|