convex 1.47.0 → 1.48.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/CHANGELOG.md +28 -4
- package/README.md +1 -1
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/aiFiles.js +26 -4
- package/dist/cjs/cli/aiFiles.js.map +2 -2
- package/dist/cjs/cli/env.js +6 -3
- package/dist/cjs/cli/env.js.map +2 -2
- package/dist/cjs/cli/envDefault.js +5 -2
- package/dist/cjs/cli/envDefault.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js +2 -1
- package/dist/cjs/cli/lib/aiFiles/guidelinesmd.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/index.js +13 -2
- package/dist/cjs/cli/lib/aiFiles/index.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/skills.js +6 -5
- package/dist/cjs/cli/lib/aiFiles/skills.js.map +2 -2
- package/dist/cjs/cli/lib/aiFiles/state.js +1 -1
- package/dist/cjs/cli/lib/aiFiles/state.js.map +1 -1
- package/dist/cjs/cli/lib/components.js +12 -2
- package/dist/cjs/cli/lib/components.js.map +2 -2
- package/dist/cjs/cli/lib/deployApi/startPush.js +42 -1
- package/dist/cjs/cli/lib/deployApi/startPush.js.map +2 -2
- package/dist/cjs/cli/lib/env.js +9 -1
- package/dist/cjs/cli/lib/env.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/dashboard.js +11 -1
- package/dist/cjs/cli/lib/localDeployment/dashboard.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/download.js +16 -1
- package/dist/cjs/cli/lib/localDeployment/download.js.map +2 -2
- package/dist/cjs/cli/lib/localDeployment/utils.js +4 -0
- package/dist/cjs/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/cjs/cli/lib/utils/aiAgent.js +32 -0
- package/dist/cjs/cli/lib/utils/aiAgent.js.map +7 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/server/authentication.js.map +1 -1
- package/dist/cjs/server/components/index.js.map +2 -2
- package/dist/cjs/server/impl/authentication_impl.js +15 -1
- package/dist/cjs/server/impl/authentication_impl.js.map +2 -2
- package/dist/cjs/server/impl/registration_impl.js +1 -1
- package/dist/cjs/server/impl/registration_impl.js.map +2 -2
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/meta.js.map +1 -1
- package/dist/cjs/server/registration.js.map +1 -1
- package/dist/cjs/server/schema.js +0 -2
- package/dist/cjs/server/schema.js.map +2 -2
- package/dist/cjs/server/storage.js.map +1 -1
- package/dist/cjs-types/cli/aiFiles.d.ts.map +1 -1
- package/dist/cjs-types/cli/env.d.ts.map +1 -1
- package/dist/cjs-types/cli/envDefault.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts +3 -1
- package/dist/cjs-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts +11 -1
- package/dist/cjs-types/cli/lib/aiFiles/index.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts +4 -1
- package/dist/cjs-types/cli/lib/aiFiles/skills.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/components.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts +13 -0
- package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/env.d.ts +1 -0
- package/dist/cjs-types/cli/lib/env.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/dashboard.d.ts +6 -0
- package/dist/cjs-types/cli/lib/localDeployment/dashboard.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/download.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts +1 -0
- package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/utils/aiAgent.d.ts +8 -0
- package/dist/cjs-types/cli/lib/utils/aiAgent.d.ts.map +1 -0
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/server/authentication.d.ts +65 -0
- package/dist/cjs-types/server/authentication.d.ts.map +1 -1
- package/dist/cjs-types/server/components/index.d.ts +6 -0
- package/dist/cjs-types/server/components/index.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/authentication_impl.d.ts +2 -1
- package/dist/cjs-types/server/impl/authentication_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/index.d.ts +2 -2
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cjs-types/server/meta.d.ts +8 -0
- package/dist/cjs-types/server/meta.d.ts.map +1 -1
- package/dist/cjs-types/server/registration.d.ts +5 -3
- package/dist/cjs-types/server/registration.d.ts.map +1 -1
- package/dist/cjs-types/server/schema.d.ts +0 -2
- package/dist/cjs-types/server/schema.d.ts.map +1 -1
- package/dist/cjs-types/server/storage.d.ts +28 -25
- package/dist/cjs-types/server/storage.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +284 -25
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/cli/aiFiles.js +26 -4
- package/dist/esm/cli/aiFiles.js.map +2 -2
- package/dist/esm/cli/env.js +6 -3
- package/dist/esm/cli/env.js.map +2 -2
- package/dist/esm/cli/envDefault.js +5 -2
- package/dist/esm/cli/envDefault.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js +2 -1
- package/dist/esm/cli/lib/aiFiles/guidelinesmd.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/index.js +13 -2
- package/dist/esm/cli/lib/aiFiles/index.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/skills.js +6 -5
- package/dist/esm/cli/lib/aiFiles/skills.js.map +2 -2
- package/dist/esm/cli/lib/aiFiles/state.js +1 -1
- package/dist/esm/cli/lib/aiFiles/state.js.map +1 -1
- package/dist/esm/cli/lib/components.js +15 -2
- package/dist/esm/cli/lib/components.js.map +2 -2
- package/dist/esm/cli/lib/deployApi/startPush.js +39 -0
- package/dist/esm/cli/lib/deployApi/startPush.js.map +2 -2
- package/dist/esm/cli/lib/env.js +9 -1
- package/dist/esm/cli/lib/env.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/dashboard.js +9 -0
- package/dist/esm/cli/lib/localDeployment/dashboard.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/download.js +16 -1
- package/dist/esm/cli/lib/localDeployment/download.js.map +2 -2
- package/dist/esm/cli/lib/localDeployment/utils.js +3 -0
- package/dist/esm/cli/lib/localDeployment/utils.js.map +2 -2
- package/dist/esm/cli/lib/utils/aiAgent.js +10 -0
- package/dist/esm/cli/lib/utils/aiAgent.js.map +7 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server/components/index.js.map +2 -2
- package/dist/esm/server/impl/authentication_impl.js +13 -0
- package/dist/esm/server/impl/authentication_impl.js.map +2 -2
- package/dist/esm/server/impl/registration_impl.js +2 -2
- package/dist/esm/server/impl/registration_impl.js.map +2 -2
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/server/schema.js +0 -2
- package/dist/esm/server/schema.js.map +2 -2
- package/dist/esm-types/cli/aiFiles.d.ts.map +1 -1
- package/dist/esm-types/cli/env.d.ts.map +1 -1
- package/dist/esm-types/cli/envDefault.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts +3 -1
- package/dist/esm-types/cli/lib/aiFiles/guidelinesmd.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts +11 -1
- package/dist/esm-types/cli/lib/aiFiles/index.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts +4 -1
- package/dist/esm-types/cli/lib/aiFiles/skills.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/components.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/deployApi/startPush.d.ts +13 -0
- package/dist/esm-types/cli/lib/deployApi/startPush.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/env.d.ts +1 -0
- package/dist/esm-types/cli/lib/env.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/dashboard.d.ts +6 -0
- package/dist/esm-types/cli/lib/localDeployment/dashboard.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/download.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts +1 -0
- package/dist/esm-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/utils/aiAgent.d.ts +8 -0
- package/dist/esm-types/cli/lib/utils/aiAgent.d.ts.map +1 -0
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/server/authentication.d.ts +65 -0
- package/dist/esm-types/server/authentication.d.ts.map +1 -1
- package/dist/esm-types/server/components/index.d.ts +6 -0
- package/dist/esm-types/server/components/index.d.ts.map +1 -1
- package/dist/esm-types/server/impl/authentication_impl.d.ts +2 -1
- package/dist/esm-types/server/impl/authentication_impl.d.ts.map +1 -1
- package/dist/esm-types/server/index.d.ts +2 -2
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/esm-types/server/meta.d.ts +8 -0
- package/dist/esm-types/server/meta.d.ts.map +1 -1
- package/dist/esm-types/server/registration.d.ts +5 -3
- package/dist/esm-types/server/registration.d.ts.map +1 -1
- package/dist/esm-types/server/schema.d.ts +0 -2
- package/dist/esm-types/server/schema.d.ts.map +1 -1
- package/dist/esm-types/server/storage.d.ts +28 -25
- package/dist/esm-types/server/storage.d.ts.map +1 -1
- package/dist/react.bundle.js +1 -1
- package/dist/react.bundle.js.map +1 -1
- package/package.json +3 -2
- package/schemas/convex.schema.json +1 -2
- package/src/cli/aiFiles.ts +30 -4
- package/src/cli/env.ts +4 -1
- package/src/cli/envDefault.ts +4 -1
- package/src/cli/lib/aiFiles/guidelinesmd.ts +7 -2
- package/src/cli/lib/aiFiles/index.ts +23 -3
- package/src/cli/lib/aiFiles/skills.ts +11 -7
- package/src/cli/lib/aiFiles/state.ts +1 -1
- package/src/cli/lib/components.ts +18 -3
- package/src/cli/lib/deployApi/startPush.ts +64 -0
- package/src/cli/lib/env.ts +13 -2
- package/src/cli/lib/localDeployment/dashboard.ts +19 -0
- package/src/cli/lib/localDeployment/download.ts +17 -1
- package/src/cli/lib/localDeployment/utils.ts +4 -0
- package/src/cli/lib/utils/aiAgent.ts +15 -0
- package/src/index.ts +1 -1
- package/src/server/authentication.ts +79 -0
- package/src/server/components/index.ts +11 -0
- package/src/server/impl/authentication_impl.ts +15 -1
- package/src/server/impl/registration_impl.ts +2 -2
- package/src/server/index.ts +6 -0
- package/src/server/meta.ts +0 -8
- package/src/server/registration.ts +5 -2
- package/src/server/schema.ts +0 -2
- package/src/server/storage.ts +29 -42
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "convex",
|
|
3
3
|
"description": "Client for the Convex Cloud",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.48.0",
|
|
5
5
|
"author": "Convex, Inc. <no-reply@convex.dev>",
|
|
6
6
|
"homepage": "https://convex.dev",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/
|
|
9
|
+
"url": "git+https://github.com/convex/convex-backend.git",
|
|
10
10
|
"directory": "npm-packages/convex"
|
|
11
11
|
},
|
|
12
12
|
"main": "./dist/cjs/index.js",
|
|
@@ -227,6 +227,7 @@
|
|
|
227
227
|
"@types/semver": "^7.3.13",
|
|
228
228
|
"@types/serve-handler": "~6.1.4",
|
|
229
229
|
"@types/ws": "^8.5.13",
|
|
230
|
+
"@vercel/detect-agent": "^1.2.5",
|
|
230
231
|
"@vitest/eslint-plugin": "~1.6.0",
|
|
231
232
|
"adm-zip": "^0.6.1",
|
|
232
233
|
"bufferutil": "^4.0.7",
|
|
@@ -123,8 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
"nodeVersion": {
|
|
125
125
|
"type": "string",
|
|
126
|
-
"description": "The Node.js version to use for Node.js actions. The currently supported values are '
|
|
127
|
-
"default": "20"
|
|
126
|
+
"description": "The Node.js version to use for Node.js actions. The currently supported values are '22' and '24'.\n\nAfter you push a new Node.js version, your functions may keep running on the previous version for a few minutes.\n\nDocumentation: https://docs.convex.dev/config/convex.json#configuring-the-nodejs-version"
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
},
|
package/src/cli/aiFiles.ts
CHANGED
|
@@ -34,9 +34,22 @@ const aiInstall = new Command("install")
|
|
|
34
34
|
)
|
|
35
35
|
.allowExcessArguments(false)
|
|
36
36
|
.action(async () => {
|
|
37
|
-
const { projectDir, convexDir, aiFilesConfig } =
|
|
37
|
+
const { ctx, projectDir, convexDir, aiFilesConfig } =
|
|
38
38
|
await resolveProjectPaths();
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
const result = await installAiFiles({
|
|
41
|
+
projectDir,
|
|
42
|
+
convexDir,
|
|
43
|
+
aiFilesConfig,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result.kind === "error") {
|
|
47
|
+
return await ctx.crash({
|
|
48
|
+
exitCode: 1,
|
|
49
|
+
errorType: "fatal",
|
|
50
|
+
printedMessage: result.message,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
40
53
|
|
|
41
54
|
logMessage(`${chalkStderr.green("✔")} Convex AI files installed.`);
|
|
42
55
|
});
|
|
@@ -72,9 +85,22 @@ const aiUpdate = new Command("update")
|
|
|
72
85
|
)
|
|
73
86
|
.allowExcessArguments(false)
|
|
74
87
|
.action(async () => {
|
|
75
|
-
const { projectDir, convexDir, aiFilesConfig } =
|
|
88
|
+
const { ctx, projectDir, convexDir, aiFilesConfig } =
|
|
76
89
|
await resolveProjectPaths();
|
|
77
|
-
|
|
90
|
+
|
|
91
|
+
const result = await installAiFiles({
|
|
92
|
+
projectDir,
|
|
93
|
+
convexDir,
|
|
94
|
+
aiFilesConfig,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (result.kind === "error") {
|
|
98
|
+
return await ctx.crash({
|
|
99
|
+
exitCode: 1,
|
|
100
|
+
errorType: "fatal",
|
|
101
|
+
printedMessage: result.message,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
78
104
|
|
|
79
105
|
logMessage(`${chalkStderr.green("✔")} Convex AI files updated.`);
|
|
80
106
|
});
|
package/src/cli/env.ts
CHANGED
|
@@ -171,6 +171,8 @@ const envListCmd = new Command("list")
|
|
|
171
171
|
"• List all variables and their values: `npx convex env list --include-values`",
|
|
172
172
|
"• Save all variables to a file: `npx convex env list --include-values > .env.convex`",
|
|
173
173
|
"• Append to a file: `npx convex env list --include-values >> .env.convex`",
|
|
174
|
+
"",
|
|
175
|
+
"When an AI agent runs this command (detected from environment variables like AI_AGENT or CLAUDECODE), only names are listed unless --include-values is passed.",
|
|
174
176
|
].join("\n"),
|
|
175
177
|
)
|
|
176
178
|
.option(
|
|
@@ -180,7 +182,7 @@ const envListCmd = new Command("list")
|
|
|
180
182
|
.addOption(
|
|
181
183
|
new Option(
|
|
182
184
|
"--include-values",
|
|
183
|
-
"Print each variable's value alongside its name, in .env format
|
|
185
|
+
"Print each variable's value alongside its name, in .env format. This is the default unless an AI agent is detected, so pass it explicitly in scripts that rely on the values.",
|
|
184
186
|
).conflicts("namesOnly"),
|
|
185
187
|
)
|
|
186
188
|
.configureHelp({ showGlobalOptions: true })
|
|
@@ -198,6 +200,7 @@ const envListCmd = new Command("list")
|
|
|
198
200
|
const backend = deploymentEnvBackend(ctx, deployment);
|
|
199
201
|
await envList(ctx, backend, {
|
|
200
202
|
namesOnly: cmdOptions.namesOnly ?? false,
|
|
203
|
+
includeValues: cmdOptions.includeValues ?? false,
|
|
201
204
|
});
|
|
202
205
|
},
|
|
203
206
|
});
|
package/src/cli/envDefault.ts
CHANGED
|
@@ -147,6 +147,8 @@ const envDefaultList = addEnvDefaultOptions(
|
|
|
147
147
|
"• List only default variable names (no values): `npx convex env default list --names-only`",
|
|
148
148
|
"• List all default variables and their values: `npx convex env default list --include-values`",
|
|
149
149
|
"",
|
|
150
|
+
"When an AI agent runs this command (detected from environment variables like AI_AGENT or CLAUDECODE), only names are listed unless --include-values is passed.",
|
|
151
|
+
"",
|
|
150
152
|
"The deployment type is determined by the current deployment (local maps to dev), or by --type if provided.",
|
|
151
153
|
].join("\n"),
|
|
152
154
|
)
|
|
@@ -157,7 +159,7 @@ const envDefaultList = addEnvDefaultOptions(
|
|
|
157
159
|
.addOption(
|
|
158
160
|
new Option(
|
|
159
161
|
"--include-values",
|
|
160
|
-
"Print each variable's value alongside its name, in .env format
|
|
162
|
+
"Print each variable's value alongside its name, in .env format. This is the default unless an AI agent is detected, so pass it explicitly in scripts that rely on the values.",
|
|
161
163
|
).conflicts("namesOnly"),
|
|
162
164
|
)
|
|
163
165
|
.configureHelp({ showGlobalOptions: true })
|
|
@@ -169,6 +171,7 @@ const envDefaultList = addEnvDefaultOptions(
|
|
|
169
171
|
await ensureHasConvexDependency(ctx, "env default list");
|
|
170
172
|
await envList(ctx, backend, {
|
|
171
173
|
namesOnly: cmdOptions.namesOnly ?? false,
|
|
174
|
+
includeValues: cmdOptions.includeValues ?? false,
|
|
172
175
|
});
|
|
173
176
|
});
|
|
174
177
|
|
|
@@ -21,6 +21,8 @@ export async function hasGuidelinesInstalled(
|
|
|
21
21
|
* Download and write the guidelines file.
|
|
22
22
|
* Guidelines live in `_generated/` so local edits are not expected and are
|
|
23
23
|
* not preserved.
|
|
24
|
+
*
|
|
25
|
+
* Returns false if the guidelines could not be downloaded.
|
|
24
26
|
*/
|
|
25
27
|
export async function installGuidelinesFile({
|
|
26
28
|
convexDir,
|
|
@@ -28,15 +30,16 @@ export async function installGuidelinesFile({
|
|
|
28
30
|
}: {
|
|
29
31
|
convexDir: string;
|
|
30
32
|
state: AiFilesState;
|
|
31
|
-
}): Promise<
|
|
33
|
+
}): Promise<boolean> {
|
|
32
34
|
const guidelines = await downloadGuidelines();
|
|
35
|
+
|
|
33
36
|
if (guidelines === null) {
|
|
34
37
|
logMessage(
|
|
35
38
|
chalkStderr.yellow(
|
|
36
39
|
"Could not download Convex AI guidelines right now. You can retry with: npx convex ai-files install",
|
|
37
40
|
),
|
|
38
41
|
);
|
|
39
|
-
return;
|
|
42
|
+
return false;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
await fs.mkdir(aiDirForConvexDir(convexDir), { recursive: true });
|
|
@@ -46,4 +49,6 @@ export async function installGuidelinesFile({
|
|
|
46
49
|
logMessage(
|
|
47
50
|
`${chalkStderr.green("✔")} ${guidelinesPathForConvexDir(convexDir)} written`,
|
|
48
51
|
);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
49
54
|
}
|
|
@@ -44,11 +44,18 @@ async function hasExistingAiFilesArtifacts({
|
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
type InstallAiFilesResult =
|
|
48
|
+
| { kind: "success" }
|
|
49
|
+
| { kind: "error"; message: string };
|
|
50
|
+
|
|
47
51
|
/**
|
|
48
52
|
* Install or refresh all Convex AI files.
|
|
49
53
|
*
|
|
50
54
|
* Reads the existing state if present, or starts from a blank one for a
|
|
51
55
|
* fresh install.
|
|
56
|
+
*
|
|
57
|
+
* Writes everything it can even when the guidelines download or the skills
|
|
58
|
+
* install fails, and returns an error if either of them failed.
|
|
52
59
|
*/
|
|
53
60
|
export async function installAiFiles({
|
|
54
61
|
projectDir,
|
|
@@ -56,16 +63,29 @@ export async function installAiFiles({
|
|
|
56
63
|
aiFilesConfig,
|
|
57
64
|
}: AiFilesPaths & {
|
|
58
65
|
aiFilesConfig?: AiFilesProjectConfig | undefined;
|
|
59
|
-
}): Promise<
|
|
66
|
+
}): Promise<InstallAiFilesResult> {
|
|
60
67
|
const convexDirName = path.relative(projectDir, convexDir);
|
|
61
68
|
const state = await readAiStateOrDefault(convexDir);
|
|
62
69
|
|
|
63
|
-
await installGuidelinesFile({ convexDir, state });
|
|
70
|
+
const guidelinesInstalled = await installGuidelinesFile({ convexDir, state });
|
|
64
71
|
await applyAgentsMdSection({ projectDir, state, convexDirName });
|
|
65
72
|
await applyClaudeMdSection({ projectDir, state, convexDirName });
|
|
66
|
-
await installSkills({
|
|
73
|
+
const skillsInstalled = await installSkills({
|
|
74
|
+
projectDir,
|
|
75
|
+
state,
|
|
76
|
+
aiFilesConfig,
|
|
77
|
+
});
|
|
67
78
|
await removeLegacyCursorRules(projectDir);
|
|
68
79
|
await writeAiState({ state, convexDir });
|
|
80
|
+
|
|
81
|
+
if (!guidelinesInstalled || !skillsInstalled) {
|
|
82
|
+
return {
|
|
83
|
+
kind: "error",
|
|
84
|
+
message:
|
|
85
|
+
"Some Convex AI files could not be installed. See the messages above.",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return { kind: "success" };
|
|
69
89
|
}
|
|
70
90
|
|
|
71
91
|
async function attemptToInstallAiFiles(
|
|
@@ -23,11 +23,11 @@ function configuredSkillAgents(
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Runs `npx skills add
|
|
26
|
+
* Runs `npx skills add convex/agent-skills --yes --copy` in the given directory.
|
|
27
27
|
* Returns true on success, false if the process fails or cannot be started.
|
|
28
28
|
*/
|
|
29
29
|
function runSkillsAdd(cwd: string, agents: string[]): Promise<boolean> {
|
|
30
|
-
const args = ["add", "
|
|
30
|
+
const args = ["add", "convex/agent-skills", "--yes", "--copy"];
|
|
31
31
|
for (const agent of agents) {
|
|
32
32
|
args.push("--agent", agent);
|
|
33
33
|
}
|
|
@@ -116,6 +116,9 @@ async function removeSkillsLockIfEmpty({
|
|
|
116
116
|
/**
|
|
117
117
|
* Install Convex agent skills and record the SHA into the state.
|
|
118
118
|
* Handles the kill-switch check and all logging internally.
|
|
119
|
+
*
|
|
120
|
+
* Returns false if the skills CLI failed. Skipping skills because no agents
|
|
121
|
+
* are configured or the kill switch is on counts as success.
|
|
119
122
|
*/
|
|
120
123
|
export async function installSkills({
|
|
121
124
|
projectDir,
|
|
@@ -125,26 +128,27 @@ export async function installSkills({
|
|
|
125
128
|
projectDir: string;
|
|
126
129
|
state: AiFilesState;
|
|
127
130
|
aiFilesConfig?: AiFilesProjectConfig | undefined;
|
|
128
|
-
}): Promise<
|
|
131
|
+
}): Promise<boolean> {
|
|
129
132
|
const agents = configuredSkillAgents(aiFilesConfig);
|
|
130
|
-
if (agents.length === 0) return;
|
|
131
|
-
if (!(await shouldRunSkillsCli())) return;
|
|
133
|
+
if (agents.length === 0) return true;
|
|
134
|
+
if (!(await shouldRunSkillsCli())) return true;
|
|
132
135
|
|
|
133
136
|
logMessage("Installing Convex agent skills...");
|
|
134
137
|
const skillsOk = await runSkillsAdd(projectDir, agents);
|
|
135
138
|
if (!skillsOk) {
|
|
136
139
|
logMessage(
|
|
137
140
|
chalkStderr.yellow(
|
|
138
|
-
"Could not install agent skills. You can retry manually with: npx skills add
|
|
141
|
+
"Could not install agent skills. You can retry manually with: npx skills add convex/agent-skills --copy",
|
|
139
142
|
),
|
|
140
143
|
);
|
|
141
|
-
return;
|
|
144
|
+
return false;
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
const sha = await fetchAgentSkillsSha();
|
|
145
148
|
if (sha) state.agentSkillsSha = sha;
|
|
146
149
|
|
|
147
150
|
logMessage(`${chalkStderr.green("✔")} Skills installed`);
|
|
151
|
+
return true;
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
export type RemoveInstalledSkillsStatus = "unchanged" | "removed" | "failed";
|
|
@@ -11,7 +11,7 @@ export const aiFilesStateSchema = z.object({
|
|
|
11
11
|
guidelinesHash: z.string().nullable(),
|
|
12
12
|
agentsMdSectionHash: z.string().nullable(),
|
|
13
13
|
claudeMdHash: z.string().nullable(),
|
|
14
|
-
// Commit SHA from
|
|
14
|
+
// Commit SHA from convex/agent-skills that was current when skills were
|
|
15
15
|
// last installed. Used to detect when newer skills are available.
|
|
16
16
|
agentSkillsSha: z.string().nullable(),
|
|
17
17
|
});
|
|
@@ -43,7 +43,12 @@ import { typeCheckFunctionsInMode, TypeCheckMode } from "./typecheck.js";
|
|
|
43
43
|
import { withTmpDir } from "../../bundler/fs.js";
|
|
44
44
|
import { handleDebugBundlePath } from "./debugBundlePath.js";
|
|
45
45
|
import { chalkStderr } from "chalk";
|
|
46
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
startPushResponseForLogging,
|
|
48
|
+
redactEnvironmentVariableValues,
|
|
49
|
+
StartPushRequest,
|
|
50
|
+
StartPushResponse,
|
|
51
|
+
} from "./deployApi/startPush.js";
|
|
47
52
|
import { DetailedDeploymentCredentials } from "./api.js";
|
|
48
53
|
import { FinishPushDiff } from "./deployApi/finishPush.js";
|
|
49
54
|
import { Reporter, Span } from "./tracing.js";
|
|
@@ -548,7 +553,10 @@ async function startComponentsPushAndCodegen(
|
|
|
548
553
|
);
|
|
549
554
|
|
|
550
555
|
if (options.verbose) {
|
|
551
|
-
logMessage(
|
|
556
|
+
logMessage(
|
|
557
|
+
"startPush: " +
|
|
558
|
+
JSON.stringify(startPushResponseForLogging(startPushResponse), null, 2),
|
|
559
|
+
);
|
|
552
560
|
}
|
|
553
561
|
|
|
554
562
|
if (options.codegen) {
|
|
@@ -734,7 +742,14 @@ function printDiff(
|
|
|
734
742
|
opts: { verbose: boolean; dryRun: boolean; deploymentName: string | null },
|
|
735
743
|
) {
|
|
736
744
|
if (opts.verbose) {
|
|
737
|
-
const diffString = JSON.stringify(
|
|
745
|
+
const diffString = JSON.stringify(
|
|
746
|
+
redactEnvironmentVariableValues(
|
|
747
|
+
finishPushResponse,
|
|
748
|
+
startPushResponse.environmentVariables,
|
|
749
|
+
),
|
|
750
|
+
null,
|
|
751
|
+
2,
|
|
752
|
+
);
|
|
738
753
|
logMessage(diffString);
|
|
739
754
|
return;
|
|
740
755
|
}
|
|
@@ -48,6 +48,70 @@ export const startPushResponse = looseObject({
|
|
|
48
48
|
});
|
|
49
49
|
export type StartPushResponse = z.infer<typeof startPushResponse>;
|
|
50
50
|
|
|
51
|
+
// Values this short are rarely secrets, and replacing them everywhere would
|
|
52
|
+
// garble unrelated strings in the output.
|
|
53
|
+
const MIN_SCRUBBED_VALUE_LENGTH = 8;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Replaces every occurrence of an environment variable's value in `node`'s
|
|
57
|
+
* strings with `<redacted>`. Values reappear in push responses wherever the
|
|
58
|
+
* code read them, such as auth providers built from `process.env` in
|
|
59
|
+
* `auth.config.ts`.
|
|
60
|
+
*/
|
|
61
|
+
export function redactEnvironmentVariableValues<T>(
|
|
62
|
+
node: T,
|
|
63
|
+
environmentVariables: Record<string, string>,
|
|
64
|
+
): T {
|
|
65
|
+
const values = Object.values(environmentVariables)
|
|
66
|
+
.filter((value) => value.length >= MIN_SCRUBBED_VALUE_LENGTH)
|
|
67
|
+
// Strings that hold JSON, like `authDiff` entries, contain the escaped form.
|
|
68
|
+
.flatMap((value) => {
|
|
69
|
+
const escaped = JSON.stringify(value).slice(1, -1);
|
|
70
|
+
return escaped === value ? [value] : [value, escaped];
|
|
71
|
+
})
|
|
72
|
+
.sort((a, b) => b.length - a.length);
|
|
73
|
+
const scrub = (child: unknown): unknown => {
|
|
74
|
+
if (typeof child === "string") {
|
|
75
|
+
return values.reduce(
|
|
76
|
+
(scrubbed, value) => scrubbed.split(value).join("<redacted>"),
|
|
77
|
+
child,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(child)) {
|
|
81
|
+
return child.map(scrub);
|
|
82
|
+
}
|
|
83
|
+
if (child !== null && typeof child === "object") {
|
|
84
|
+
return Object.fromEntries(
|
|
85
|
+
Object.entries(child).map(([key, grandchild]) => [
|
|
86
|
+
key,
|
|
87
|
+
scrub(grandchild),
|
|
88
|
+
]),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return child;
|
|
92
|
+
};
|
|
93
|
+
return scrub(node) as T;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A copy of the response that is safe to print. `environmentVariables` holds
|
|
98
|
+
* every value on the deployment so `finish_push` can detect concurrent changes,
|
|
99
|
+
* and those values are often secrets.
|
|
100
|
+
*/
|
|
101
|
+
export function startPushResponseForLogging(
|
|
102
|
+
response: StartPushResponse,
|
|
103
|
+
): StartPushResponse {
|
|
104
|
+
return {
|
|
105
|
+
...redactEnvironmentVariableValues(response, response.environmentVariables),
|
|
106
|
+
environmentVariables: Object.fromEntries(
|
|
107
|
+
Object.keys(response.environmentVariables).map((name) => [
|
|
108
|
+
name,
|
|
109
|
+
"<redacted>",
|
|
110
|
+
]),
|
|
111
|
+
),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
51
115
|
export const evaluatePushResponse = looseObject({
|
|
52
116
|
schemaChange,
|
|
53
117
|
});
|
package/src/cli/lib/env.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { runSystemQuery } from "./run.js";
|
|
|
11
11
|
import { deploymentFetch, logAndHandleFetchError } from "./utils/utils.js";
|
|
12
12
|
import { readFromStdin } from "./utils/stdin.js";
|
|
13
13
|
import { promptSecret } from "./utils/prompts.js";
|
|
14
|
+
import { detectAiAgent } from "./utils/aiAgent.js";
|
|
14
15
|
import {
|
|
15
16
|
EXPECTED_CONVEX_URL_NAMES,
|
|
16
17
|
EXPECTED_SITE_URL_NAMES,
|
|
@@ -174,15 +175,20 @@ export async function envRemove(
|
|
|
174
175
|
export async function envList(
|
|
175
176
|
ctx: Context,
|
|
176
177
|
backend: EnvVarBackend,
|
|
177
|
-
options?: { namesOnly?: boolean },
|
|
178
|
+
options?: { namesOnly?: boolean; includeValues?: boolean },
|
|
178
179
|
) {
|
|
179
180
|
const envs = await backend.list();
|
|
180
181
|
if (envs.length === 0) {
|
|
181
182
|
logMessage(`No environment variables set${backend.notice}`);
|
|
182
183
|
return;
|
|
183
184
|
}
|
|
185
|
+
// Agents tend to run `env list` to check what is set, which copies every
|
|
186
|
+
// secret into their context. They get names unless they ask for values.
|
|
187
|
+
const agent =
|
|
188
|
+
options?.namesOnly || options?.includeValues ? null : await detectAiAgent();
|
|
189
|
+
const namesOnly = options?.namesOnly || agent !== null;
|
|
184
190
|
for (const { name, value } of envs) {
|
|
185
|
-
if (
|
|
191
|
+
if (namesOnly) {
|
|
186
192
|
logOutput(name);
|
|
187
193
|
continue;
|
|
188
194
|
}
|
|
@@ -192,6 +198,11 @@ export async function envList(
|
|
|
192
198
|
}
|
|
193
199
|
logOutput(`${name}=${formatted}`);
|
|
194
200
|
}
|
|
201
|
+
if (agent !== null) {
|
|
202
|
+
logMessage(
|
|
203
|
+
`Listed names only because an AI agent (${agent}) appears to be running this command. Pass --include-values to print the values too.`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
async function getFileContents(
|
|
@@ -57,6 +57,12 @@ export async function handleDashboard(
|
|
|
57
57
|
ctx,
|
|
58
58
|
dashboardPort,
|
|
59
59
|
async (request, response) => {
|
|
60
|
+
if (!isLoopbackHost(request.headers.host, dashboardPort)) {
|
|
61
|
+
response.statusCode = 403;
|
|
62
|
+
response.end();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
60
66
|
const pathname = new URL(
|
|
61
67
|
request.url ?? "/",
|
|
62
68
|
// We only want to extract the pathname so the base doesn’t matter
|
|
@@ -96,6 +102,19 @@ export async function handleDashboard(
|
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
|
|
105
|
+
/**
|
|
106
|
+
* The dashboard is only meant to be opened at the URL the CLI prints, so
|
|
107
|
+
* requests addressed to any other hostname are not served, even if that
|
|
108
|
+
* hostname resolves to 127.0.0.1.
|
|
109
|
+
*/
|
|
110
|
+
export function isLoopbackHost(host: string | undefined, port: number) {
|
|
111
|
+
const normalizedHost = host?.toLowerCase();
|
|
112
|
+
return (
|
|
113
|
+
normalizedHost === `127.0.0.1:${port}` ||
|
|
114
|
+
normalizedHost === `localhost:${port}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
99
118
|
async function reportSelfHostedEvent(
|
|
100
119
|
ctx: Context,
|
|
101
120
|
{
|
|
@@ -27,6 +27,7 @@ import { recursivelyDelete, recursivelyCopy } from "../fsUtils.js";
|
|
|
27
27
|
import { LocalDeploymentError } from "./errors.js";
|
|
28
28
|
import type { ProgressBarInstance } from "../../../vendor/progress/index.js";
|
|
29
29
|
import path from "path";
|
|
30
|
+
import { isValidBackendVersion } from "./utils.js";
|
|
30
31
|
|
|
31
32
|
async function makeExecutable(p: string) {
|
|
32
33
|
switch (process.platform) {
|
|
@@ -67,6 +68,7 @@ async function _ensureBackendBinaryDownloaded(
|
|
|
67
68
|
ctx: Context,
|
|
68
69
|
version: string,
|
|
69
70
|
): Promise<{ binaryPath: string; version: string }> {
|
|
71
|
+
await assertValidBackendVersion(ctx, version);
|
|
70
72
|
logVerbose(`Ensuring backend binary downloaded for version ${version}`);
|
|
71
73
|
const existingDownload = await checkForExistingDownload(ctx, version);
|
|
72
74
|
if (existingDownload !== null) {
|
|
@@ -80,6 +82,19 @@ async function _ensureBackendBinaryDownloaded(
|
|
|
80
82
|
return { version, binaryPath };
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
async function assertValidBackendVersion(ctx: Context, version: string) {
|
|
86
|
+
if (!isValidBackendVersion(version)) {
|
|
87
|
+
return await ctx.crash({
|
|
88
|
+
exitCode: 1,
|
|
89
|
+
errorType: "fatal",
|
|
90
|
+
printedMessage: "Invalid local backend version",
|
|
91
|
+
errForSentry: new LocalDeploymentError(
|
|
92
|
+
`Invalid local backend version: ${JSON.stringify(version)}`,
|
|
93
|
+
),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
let cachedLatestVersion: string | null = null;
|
|
84
99
|
|
|
85
100
|
/**
|
|
@@ -259,7 +274,7 @@ function getDownloadPath() {
|
|
|
259
274
|
}
|
|
260
275
|
|
|
261
276
|
function getGithubDownloadUrl(version: string, filename: string) {
|
|
262
|
-
return `https://github.com/
|
|
277
|
+
return `https://github.com/convex/convex-backend/releases/download/${version}/${filename}`;
|
|
263
278
|
}
|
|
264
279
|
|
|
265
280
|
async function downloadZipFile(
|
|
@@ -326,6 +341,7 @@ async function downloadZipFile(
|
|
|
326
341
|
}
|
|
327
342
|
|
|
328
343
|
export async function ensureDashboardDownloaded(ctx: Context, version: string) {
|
|
344
|
+
await assertValidBackendVersion(ctx, version);
|
|
329
345
|
const config = loadGlobalDashboardConfig(ctx);
|
|
330
346
|
if (config !== null && config.version === version) {
|
|
331
347
|
return;
|
|
@@ -98,3 +98,7 @@ export const LOCAL_BACKEND_INSTANCE_SECRET =
|
|
|
98
98
|
export function releaseDate(version: string): string | null {
|
|
99
99
|
return /^precompiled-(\d{4}-\d{2}-\d{2})-/.exec(version)?.[1] ?? null;
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
export function isValidBackendVersion(version: string): boolean {
|
|
103
|
+
return /^precompiled-\d{4}-\d{2}-\d{2}-[\w.-]+$/.test(version);
|
|
104
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { determineAgent } from "@vercel/detect-agent";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the name of the AI agent running this process, or null if none is
|
|
5
|
+
* detected. `@vercel/detect-agent` recognizes the environment variables that
|
|
6
|
+
* agents like Claude Code, Codex and Cursor set; `CONVEX_AGENT_MODE` is
|
|
7
|
+
* Convex's own.
|
|
8
|
+
*/
|
|
9
|
+
export async function detectAiAgent(): Promise<string | null> {
|
|
10
|
+
if (process.env.CONVEX_AGENT_MODE) {
|
|
11
|
+
return "CONVEX_AGENT_MODE";
|
|
12
|
+
}
|
|
13
|
+
const result = await determineAgent();
|
|
14
|
+
return result.isAgent ? result.agent.name : null;
|
|
15
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "1.
|
|
1
|
+
export const version = "1.48.0";
|
|
@@ -235,3 +235,82 @@ export interface Auth {
|
|
|
235
235
|
*/
|
|
236
236
|
getUserIdentity(): Promise<UserIdentity | null>;
|
|
237
237
|
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* {@link Auth} for mutations, which can also sign JWTs with this deployment's
|
|
241
|
+
* key.
|
|
242
|
+
*
|
|
243
|
+
* @public
|
|
244
|
+
*/
|
|
245
|
+
export interface MutationAuth extends Auth {
|
|
246
|
+
/**
|
|
247
|
+
* Sign an ES256 JWT with this deployment's key.
|
|
248
|
+
*
|
|
249
|
+
* Pass the `claims` and `expiresInSeconds` values that match your use case.
|
|
250
|
+
*
|
|
251
|
+
* Convex populates the header and sets the `iss`, `iat` and `exp` claims.
|
|
252
|
+
*
|
|
253
|
+
* The `iss` is `process.env.CONVEX_CLOUD_URL` for the app and
|
|
254
|
+
* `${process.env.CONVEX_CLOUD_URL}/components/<name>` for a component.
|
|
255
|
+
*
|
|
256
|
+
* Anyone can verify these tokens against the public keys at
|
|
257
|
+
* `${process.env.CONVEX_CLOUD_URL}/.well-known/jwks.json`.
|
|
258
|
+
*
|
|
259
|
+
* Claims are signed but not encrypted, so anyone holding the token can read
|
|
260
|
+
* them.
|
|
261
|
+
*
|
|
262
|
+
* Prefer short token lifetimes: a token can't be revoked individually, and a
|
|
263
|
+
* mutation can always sign a fresh one to reassert the claims. This API
|
|
264
|
+
* allows a token to have a max expiration of 1 hour from issuance.
|
|
265
|
+
*
|
|
266
|
+
* Claims that start with `convex` or `cvx` (case insensitive) and the `nbf`
|
|
267
|
+
* claim are reserved and may not be set.
|
|
268
|
+
*/
|
|
269
|
+
signJwt(options: SignJwtOptions): Promise<string>;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Claims that callers may not set on JWTs with {@link MutationAuth.signJwt}.
|
|
274
|
+
*/
|
|
275
|
+
export type ReservedJwtClaim = "iss" | "iat" | "exp" | "nbf";
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Every ASCII casing of `S`: `AnyCase<"cvx">` is `"cvx" | "cvX" | "cVx" | ...`.
|
|
279
|
+
*/
|
|
280
|
+
type AnyCase<S extends string> = S extends `${infer First}${infer Rest}`
|
|
281
|
+
? `${Lowercase<First> | Uppercase<First>}${AnyCase<Rest>}`
|
|
282
|
+
: S;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Claim names starting with `convex` or `cvx`, in any casing, are reserved
|
|
286
|
+
* for Convex. They may not be set on JWTs with {@link MutationAuth.signJwt}.
|
|
287
|
+
*/
|
|
288
|
+
// NOTE: only relatively short prefixes should ever be passed below. The AnyCase
|
|
289
|
+
// type produces 2^length string literals which can get out of hand for anything
|
|
290
|
+
// but short strings.
|
|
291
|
+
export type ReservedJwtClaimPrefix = AnyCase<"convex" | "cvx">;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Rejects claim names starting with a {@link ReservedJwtClaimPrefix}.
|
|
295
|
+
*/
|
|
296
|
+
// Kept as a named alias rather than inlined into SignJwtClaims: typedoc's
|
|
297
|
+
// markdown renderer mangles template-literal index signatures into invalid
|
|
298
|
+
// MDX, but renders a reference to a named type as plain text.
|
|
299
|
+
type ReservedPrefixJwtClaims = {
|
|
300
|
+
[K: `${ReservedJwtClaimPrefix}${string}`]: never;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The claims a caller passes to {@link MutationAuth.signJwt}: any JSON value,
|
|
305
|
+
* except for the {@link ReservedJwtClaim}s and names starting with a
|
|
306
|
+
* {@link ReservedJwtClaimPrefix}.
|
|
307
|
+
*/
|
|
308
|
+
export type SignJwtClaims = Record<string, JSONValue> & {
|
|
309
|
+
[K in ReservedJwtClaim]?: never;
|
|
310
|
+
} & ReservedPrefixJwtClaims;
|
|
311
|
+
|
|
312
|
+
export type SignJwtOptions = {
|
|
313
|
+
claims?: SignJwtClaims;
|
|
314
|
+
/** How long the token stays valid, at least 1 second and at most 1 hour. */
|
|
315
|
+
expiresInSeconds: number;
|
|
316
|
+
};
|
|
@@ -49,6 +49,17 @@ export type FunctionHandle<
|
|
|
49
49
|
ReturnType = any,
|
|
50
50
|
> = string & FunctionReference<Type, "internal", Args, ReturnType>;
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* A {@link FunctionHandle} with the type semantics of {@link FunctionReference_future}.
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
export type FunctionHandle_future<
|
|
58
|
+
Type extends FunctionType,
|
|
59
|
+
Args extends DefaultFunctionArgs = any,
|
|
60
|
+
ReturnType = any,
|
|
61
|
+
> = string & FunctionReference_future<Type, "internal", Args, ReturnType>;
|
|
62
|
+
|
|
52
63
|
/**
|
|
53
64
|
* Create a serializable reference to a Convex function.
|
|
54
65
|
* Passing a this reference to another component allows that component to call this
|