@homenshum/convex-mcp-nodebench 0.1.0
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/README.md +137 -0
- package/dist/__tests__/tools.test.d.ts +1 -0
- package/dist/__tests__/tools.test.js +267 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +125 -0
- package/dist/db.js.map +1 -0
- package/dist/gotchaSeed.d.ts +126 -0
- package/dist/gotchaSeed.js +147 -0
- package/dist/gotchaSeed.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/componentTools.d.ts +2 -0
- package/dist/tools/componentTools.js +131 -0
- package/dist/tools/componentTools.js.map +1 -0
- package/dist/tools/cronTools.d.ts +2 -0
- package/dist/tools/cronTools.js +142 -0
- package/dist/tools/cronTools.js.map +1 -0
- package/dist/tools/deploymentTools.d.ts +2 -0
- package/dist/tools/deploymentTools.js +222 -0
- package/dist/tools/deploymentTools.js.map +1 -0
- package/dist/tools/functionTools.d.ts +2 -0
- package/dist/tools/functionTools.js +293 -0
- package/dist/tools/functionTools.js.map +1 -0
- package/dist/tools/integrationBridgeTools.d.ts +2 -0
- package/dist/tools/integrationBridgeTools.js +294 -0
- package/dist/tools/integrationBridgeTools.js.map +1 -0
- package/dist/tools/learningTools.d.ts +2 -0
- package/dist/tools/learningTools.js +155 -0
- package/dist/tools/learningTools.js.map +1 -0
- package/dist/tools/methodologyTools.d.ts +2 -0
- package/dist/tools/methodologyTools.js +163 -0
- package/dist/tools/methodologyTools.js.map +1 -0
- package/dist/tools/schemaTools.d.ts +2 -0
- package/dist/tools/schemaTools.js +346 -0
- package/dist/tools/schemaTools.js.map +1 -0
- package/dist/tools/toolRegistry.d.ts +5 -0
- package/dist/tools/toolRegistry.js +308 -0
- package/dist/tools/toolRegistry.js.map +1 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { getQuickRef } from "./toolRegistry.js";
|
|
4
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
5
|
+
function findConvexDir(projectDir) {
|
|
6
|
+
const candidates = [join(projectDir, "convex"), join(projectDir, "src", "convex")];
|
|
7
|
+
for (const c of candidates) {
|
|
8
|
+
if (existsSync(c))
|
|
9
|
+
return c;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function parseCrons(content) {
|
|
14
|
+
const entries = [];
|
|
15
|
+
const lines = content.split("\n");
|
|
16
|
+
// Match crons.interval(...), crons.daily(...), crons.weekly(...), crons.monthly(...)
|
|
17
|
+
const cronPattern = /crons\.(interval|daily|weekly|monthly|cron)\s*\(/g;
|
|
18
|
+
let match;
|
|
19
|
+
while ((match = cronPattern.exec(content)) !== null) {
|
|
20
|
+
const type = match[1];
|
|
21
|
+
const startIdx = match.index;
|
|
22
|
+
const lineNumber = content.substring(0, startIdx).split("\n").length;
|
|
23
|
+
// Extract the full call (find matching paren)
|
|
24
|
+
let depth = 0;
|
|
25
|
+
let i = startIdx + match[0].length - 1; // start at the opening paren
|
|
26
|
+
const start = i;
|
|
27
|
+
for (; i < content.length; i++) {
|
|
28
|
+
if (content[i] === "(")
|
|
29
|
+
depth++;
|
|
30
|
+
else if (content[i] === ")") {
|
|
31
|
+
depth--;
|
|
32
|
+
if (depth === 0)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const callBody = content.substring(start, i + 1);
|
|
37
|
+
// Extract name (first string argument)
|
|
38
|
+
const nameMatch = callBody.match(/["'`]([^"'`]+)["'`]/);
|
|
39
|
+
const name = nameMatch ? nameMatch[1] : "unnamed";
|
|
40
|
+
// Extract schedule object
|
|
41
|
+
const scheduleMatch = callBody.match(/\{\s*([\w\s:,]+)\s*\}/);
|
|
42
|
+
const schedule = scheduleMatch ? scheduleMatch[0].trim() : "unknown";
|
|
43
|
+
// Extract handler reference
|
|
44
|
+
const handlerMatch = callBody.match(/internal\.[.\w]+/);
|
|
45
|
+
const handler = handlerMatch ? handlerMatch[0] : "unknown";
|
|
46
|
+
// Extract args
|
|
47
|
+
const argsMatches = [...callBody.matchAll(/\{\s*[\w\s:,]+\s*\}/g)];
|
|
48
|
+
const args = argsMatches.length > 2
|
|
49
|
+
? argsMatches[argsMatches.length - 1][0].trim()
|
|
50
|
+
: "{}";
|
|
51
|
+
// Check for issues
|
|
52
|
+
const issues = [];
|
|
53
|
+
// Issue: missing internal. prefix (public function as cron handler)
|
|
54
|
+
if (handler === "unknown" && callBody.includes("api.")) {
|
|
55
|
+
issues.push("CRITICAL: Cron handler uses public api. instead of internal. — crons should only call internal functions");
|
|
56
|
+
}
|
|
57
|
+
// Issue: very frequent interval
|
|
58
|
+
if (type === "interval") {
|
|
59
|
+
const minutesMatch = schedule.match(/minutes:\s*(\d+)/);
|
|
60
|
+
if (minutesMatch && parseInt(minutesMatch[1]) < 5) {
|
|
61
|
+
issues.push(`WARNING: Interval of ${minutesMatch[1]} minutes is very frequent — consider if this rate is necessary`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Issue: duplicate name detection (done after collecting all)
|
|
65
|
+
entries.push({ name, type, schedule, handler, args, line: lineNumber, issues });
|
|
66
|
+
}
|
|
67
|
+
// Check for duplicate names
|
|
68
|
+
const nameCount = new Map();
|
|
69
|
+
for (const e of entries) {
|
|
70
|
+
nameCount.set(e.name, (nameCount.get(e.name) || 0) + 1);
|
|
71
|
+
}
|
|
72
|
+
for (const e of entries) {
|
|
73
|
+
if ((nameCount.get(e.name) || 0) > 1) {
|
|
74
|
+
e.issues.push(`CRITICAL: Duplicate cron name "${e.name}" — each cron must have a unique name`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return entries;
|
|
78
|
+
}
|
|
79
|
+
// ── Tool Definitions ────────────────────────────────────────────────
|
|
80
|
+
export const cronTools = [
|
|
81
|
+
{
|
|
82
|
+
name: "convex_check_crons",
|
|
83
|
+
description: "Validate cron job definitions in convex/crons.ts. Checks: handler references use internal (not api), no duplicate names, schedule validity, frequency analysis. Returns cron inventory with issues.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
projectDir: {
|
|
88
|
+
type: "string",
|
|
89
|
+
description: "Absolute path to the project root",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
required: ["projectDir"],
|
|
93
|
+
},
|
|
94
|
+
handler: async (args) => {
|
|
95
|
+
const projectDir = resolve(args.projectDir);
|
|
96
|
+
const convexDir = findConvexDir(projectDir);
|
|
97
|
+
if (!convexDir)
|
|
98
|
+
return { error: "No convex/ directory found" };
|
|
99
|
+
const cronsPath = join(convexDir, "crons.ts");
|
|
100
|
+
if (!existsSync(cronsPath)) {
|
|
101
|
+
return {
|
|
102
|
+
hasCrons: false,
|
|
103
|
+
message: "No crons.ts file found — project has no scheduled jobs",
|
|
104
|
+
quickRef: getQuickRef("convex_get_methodology"),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const content = readFileSync(cronsPath, "utf-8");
|
|
108
|
+
const entries = parseCrons(content);
|
|
109
|
+
const allIssues = entries.flatMap((e) => e.issues.map((i) => ({ cron: e.name, issue: i })));
|
|
110
|
+
const criticalCount = allIssues.filter((i) => i.issue.startsWith("CRITICAL")).length;
|
|
111
|
+
const warningCount = allIssues.filter((i) => i.issue.startsWith("WARNING")).length;
|
|
112
|
+
// Frequency analysis
|
|
113
|
+
const byType = {
|
|
114
|
+
interval: entries.filter((e) => e.type === "interval").length,
|
|
115
|
+
daily: entries.filter((e) => e.type === "daily").length,
|
|
116
|
+
weekly: entries.filter((e) => e.type === "weekly").length,
|
|
117
|
+
monthly: entries.filter((e) => e.type === "monthly").length,
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
hasCrons: true,
|
|
121
|
+
totalCrons: entries.length,
|
|
122
|
+
byType,
|
|
123
|
+
issues: {
|
|
124
|
+
total: allIssues.length,
|
|
125
|
+
critical: criticalCount,
|
|
126
|
+
warnings: warningCount,
|
|
127
|
+
details: allIssues,
|
|
128
|
+
},
|
|
129
|
+
crons: entries.map((e) => ({
|
|
130
|
+
name: e.name,
|
|
131
|
+
type: e.type,
|
|
132
|
+
schedule: e.schedule,
|
|
133
|
+
handler: e.handler,
|
|
134
|
+
line: e.line,
|
|
135
|
+
issueCount: e.issues.length,
|
|
136
|
+
})),
|
|
137
|
+
quickRef: getQuickRef("convex_pre_deploy_gate"),
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
//# sourceMappingURL=cronTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cronTools.js","sourceRoot":"","sources":["../../src/tools/cronTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { getDb, genId } from "../db.js";
|
|
4
|
+
import { getQuickRef } from "./toolRegistry.js";
|
|
5
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
6
|
+
function findConvexDir(projectDir) {
|
|
7
|
+
const candidates = [join(projectDir, "convex"), join(projectDir, "src", "convex")];
|
|
8
|
+
for (const c of candidates) {
|
|
9
|
+
if (existsSync(c))
|
|
10
|
+
return c;
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// ── Pre-Deploy Gate ─────────────────────────────────────────────────
|
|
15
|
+
function runPreDeployChecks(projectDir) {
|
|
16
|
+
const checks = [];
|
|
17
|
+
const blockers = [];
|
|
18
|
+
// Check 1: convex/ directory exists
|
|
19
|
+
const convexDir = findConvexDir(projectDir);
|
|
20
|
+
if (!convexDir) {
|
|
21
|
+
checks.push({ name: "convex_dir_exists", passed: false, message: "No convex/ directory found" });
|
|
22
|
+
blockers.push("No convex/ directory found");
|
|
23
|
+
return { passed: false, checks, blockers };
|
|
24
|
+
}
|
|
25
|
+
checks.push({ name: "convex_dir_exists", passed: true, message: `Found at ${convexDir}` });
|
|
26
|
+
// Check 2: schema.ts exists
|
|
27
|
+
const schemaPath = join(convexDir, "schema.ts");
|
|
28
|
+
if (existsSync(schemaPath)) {
|
|
29
|
+
checks.push({ name: "schema_exists", passed: true, message: "schema.ts found" });
|
|
30
|
+
// Check 2b: schema.ts has export default
|
|
31
|
+
const schemaContent = readFileSync(schemaPath, "utf-8");
|
|
32
|
+
if (/export\s+default\s+defineSchema/.test(schemaContent)) {
|
|
33
|
+
checks.push({ name: "schema_exports_default", passed: true, message: "schema.ts exports default defineSchema" });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
checks.push({ name: "schema_exports_default", passed: false, message: "schema.ts missing 'export default defineSchema(...)'" });
|
|
37
|
+
blockers.push("schema.ts must export default defineSchema(...)");
|
|
38
|
+
}
|
|
39
|
+
// Check 2c: no deprecated validators
|
|
40
|
+
if (/v\.bigint\s*\(/.test(schemaContent)) {
|
|
41
|
+
checks.push({ name: "no_deprecated_validators", passed: false, message: "schema.ts uses deprecated v.bigint() - use v.int64()" });
|
|
42
|
+
blockers.push("Replace v.bigint() with v.int64() in schema.ts");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
checks.push({ name: "no_deprecated_validators", passed: true, message: "No deprecated validators found" });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
checks.push({ name: "schema_exists", passed: false, message: "No schema.ts found - Convex will use inferred schema" });
|
|
50
|
+
// Not a blocker, just a warning
|
|
51
|
+
}
|
|
52
|
+
// Check 3: auth.config.ts exists (if auth.ts exists)
|
|
53
|
+
const authPath = join(convexDir, "auth.ts");
|
|
54
|
+
const authConfigPath = join(convexDir, "auth.config.ts");
|
|
55
|
+
if (existsSync(authPath)) {
|
|
56
|
+
if (existsSync(authConfigPath)) {
|
|
57
|
+
checks.push({ name: "auth_config_exists", passed: true, message: "auth.config.ts found alongside auth.ts" });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
checks.push({ name: "auth_config_exists", passed: false, message: "auth.ts exists but auth.config.ts is missing" });
|
|
61
|
+
blockers.push("Create auth.config.ts to configure authentication providers");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Check 4: convex.config.ts exists (for Convex components)
|
|
65
|
+
const convexConfigPath = join(convexDir, "convex.config.ts");
|
|
66
|
+
if (existsSync(convexConfigPath)) {
|
|
67
|
+
checks.push({ name: "convex_config_exists", passed: true, message: "convex.config.ts found" });
|
|
68
|
+
}
|
|
69
|
+
// Check 5: No TypeScript errors in recent audit
|
|
70
|
+
const db = getDb();
|
|
71
|
+
const latestAudit = db.prepare("SELECT * FROM audit_results WHERE project_dir = ? ORDER BY audited_at DESC LIMIT 1").get(projectDir);
|
|
72
|
+
if (latestAudit) {
|
|
73
|
+
if (latestAudit.issue_count === 0) {
|
|
74
|
+
checks.push({ name: "recent_audit_clean", passed: true, message: `Last audit (${latestAudit.audit_type}) found 0 issues` });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
checks.push({ name: "recent_audit_clean", passed: false, message: `Last audit (${latestAudit.audit_type}) found ${latestAudit.issue_count} issues` });
|
|
78
|
+
// Only block on critical issues
|
|
79
|
+
try {
|
|
80
|
+
const issues = JSON.parse(latestAudit.issues_json);
|
|
81
|
+
const criticals = Array.isArray(issues)
|
|
82
|
+
? issues.filter((i) => i.severity === "critical")
|
|
83
|
+
: [];
|
|
84
|
+
if (criticals.length > 0) {
|
|
85
|
+
blockers.push(`${criticals.length} critical issues from last audit need fixing`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch { /* ignore parse errors */ }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
checks.push({ name: "recent_audit_clean", passed: false, message: "No recent audit found. Run convex_audit_schema and convex_audit_functions first." });
|
|
93
|
+
}
|
|
94
|
+
// Check 6: _generated directory exists (project has been initialized)
|
|
95
|
+
const generatedDir = join(convexDir, "_generated");
|
|
96
|
+
if (existsSync(generatedDir)) {
|
|
97
|
+
checks.push({ name: "generated_dir_exists", passed: true, message: "_generated/ directory exists (project initialized)" });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
checks.push({ name: "generated_dir_exists", passed: false, message: "_generated/ not found - run 'npx convex dev' first" });
|
|
101
|
+
blockers.push("Run 'npx convex dev' to initialize the project before deploying");
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
passed: blockers.length === 0,
|
|
105
|
+
checks,
|
|
106
|
+
blockers,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function checkEnvVars(projectDir) {
|
|
110
|
+
const result = {
|
|
111
|
+
envFilesFound: [],
|
|
112
|
+
envVarsInCode: [],
|
|
113
|
+
envVarsInEnvFile: [],
|
|
114
|
+
missingInEnvFile: [],
|
|
115
|
+
suggestions: [],
|
|
116
|
+
};
|
|
117
|
+
// Find .env files
|
|
118
|
+
const envFiles = [".env", ".env.local", ".env.example", ".env.production"];
|
|
119
|
+
for (const f of envFiles) {
|
|
120
|
+
const p = join(projectDir, f);
|
|
121
|
+
if (existsSync(p)) {
|
|
122
|
+
result.envFilesFound.push(f);
|
|
123
|
+
const content = readFileSync(p, "utf-8");
|
|
124
|
+
const vars = content.match(/^([A-Z_][A-Z0-9_]*)=/gm) || [];
|
|
125
|
+
result.envVarsInEnvFile.push(...vars.map((v) => v.replace("=", "")));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Scan convex/ for process.env references
|
|
129
|
+
const convexDir = findConvexDir(projectDir);
|
|
130
|
+
if (convexDir) {
|
|
131
|
+
const files = collectTsFilesFlat(convexDir);
|
|
132
|
+
const envPattern = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
|
|
133
|
+
const codeEnvVars = new Set();
|
|
134
|
+
for (const filePath of files) {
|
|
135
|
+
const content = readFileSync(filePath, "utf-8");
|
|
136
|
+
let m;
|
|
137
|
+
while ((m = envPattern.exec(content)) !== null) {
|
|
138
|
+
codeEnvVars.add(m[1]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
result.envVarsInCode = [...codeEnvVars];
|
|
142
|
+
}
|
|
143
|
+
// Find missing vars
|
|
144
|
+
const envFileSet = new Set(result.envVarsInEnvFile);
|
|
145
|
+
result.missingInEnvFile = result.envVarsInCode.filter((v) => !envFileSet.has(v));
|
|
146
|
+
// Suggestions
|
|
147
|
+
if (result.missingInEnvFile.length > 0) {
|
|
148
|
+
result.suggestions.push(`Set these env vars in your Convex dashboard or .env.local: ${result.missingInEnvFile.join(", ")}`);
|
|
149
|
+
}
|
|
150
|
+
if (result.envFilesFound.length === 0) {
|
|
151
|
+
result.suggestions.push("No .env files found. Create .env.local for local development.");
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
function collectTsFilesFlat(dir) {
|
|
156
|
+
const results = [];
|
|
157
|
+
if (!existsSync(dir))
|
|
158
|
+
return results;
|
|
159
|
+
const { readdirSync } = require("node:fs");
|
|
160
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
161
|
+
for (const entry of entries) {
|
|
162
|
+
const full = join(dir, entry.name);
|
|
163
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "_generated") {
|
|
164
|
+
results.push(...collectTsFilesFlat(full));
|
|
165
|
+
}
|
|
166
|
+
else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
167
|
+
results.push(full);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
172
|
+
// ── Tool Definitions ────────────────────────────────────────────────
|
|
173
|
+
export const deploymentTools = [
|
|
174
|
+
{
|
|
175
|
+
name: "convex_pre_deploy_gate",
|
|
176
|
+
description: "Run a comprehensive pre-deployment quality gate. Checks: convex/ directory structure, schema.ts validity, deprecated validator usage, auth configuration, recent audit results, and project initialization status. Returns pass/fail with specific blockers.",
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties: {
|
|
180
|
+
projectDir: {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "Absolute path to the project root containing a convex/ directory",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
required: ["projectDir"],
|
|
186
|
+
},
|
|
187
|
+
handler: async (args) => {
|
|
188
|
+
const projectDir = resolve(args.projectDir);
|
|
189
|
+
const result = runPreDeployChecks(projectDir);
|
|
190
|
+
// Store deploy check
|
|
191
|
+
const db = getDb();
|
|
192
|
+
db.prepare("INSERT INTO deploy_checks (id, project_dir, check_type, passed, findings) VALUES (?, ?, ?, ?, ?)").run(genId("deploy"), projectDir, "pre_deploy_gate", result.passed ? 1 : 0, JSON.stringify(result));
|
|
193
|
+
return {
|
|
194
|
+
...result,
|
|
195
|
+
quickRef: getQuickRef("convex_pre_deploy_gate"),
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "convex_check_env_vars",
|
|
201
|
+
description: "Check that all environment variables referenced in Convex code (process.env.*) are defined in .env files. Identifies missing vars and suggests where to set them.",
|
|
202
|
+
inputSchema: {
|
|
203
|
+
type: "object",
|
|
204
|
+
properties: {
|
|
205
|
+
projectDir: {
|
|
206
|
+
type: "string",
|
|
207
|
+
description: "Absolute path to the project root",
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
required: ["projectDir"],
|
|
211
|
+
},
|
|
212
|
+
handler: async (args) => {
|
|
213
|
+
const projectDir = resolve(args.projectDir);
|
|
214
|
+
const result = checkEnvVars(projectDir);
|
|
215
|
+
return {
|
|
216
|
+
...result,
|
|
217
|
+
quickRef: getQuickRef("convex_check_env_vars"),
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
//# sourceMappingURL=deploymentTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploymentTools.js","sourceRoot":"","sources":["../../src/tools/deploymentTools.ts"],"names":[],"mappings":"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"}
|