convex 1.36.0 → 1.37.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 +50 -27
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/codegen_templates/agentsmd.js +8 -2
- package/dist/cjs/cli/codegen_templates/agentsmd.js.map +2 -2
- package/dist/cjs/cli/codegen_templates/claudemd.js +2 -0
- package/dist/cjs/cli/codegen_templates/claudemd.js.map +2 -2
- package/dist/cjs/cli/configure.js +0 -8
- package/dist/cjs/cli/configure.js.map +2 -2
- package/dist/cjs/cli/deployment.js +2 -1
- package/dist/cjs/cli/deployment.js.map +2 -2
- package/dist/cjs/cli/deploymentToken.js +30 -0
- package/dist/cjs/cli/deploymentToken.js.map +7 -0
- package/dist/cjs/cli/deploymentTokenCreate.js +109 -0
- package/dist/cjs/cli/deploymentTokenCreate.js.map +7 -0
- package/dist/cjs/cli/deploymentTokenDelete.js +87 -0
- package/dist/cjs/cli/deploymentTokenDelete.js.map +7 -0
- package/dist/cjs/cli/envDefault.js +130 -41
- package/dist/cjs/cli/envDefault.js.map +3 -3
- package/dist/cjs/cli/generatedApi.js.map +1 -1
- package/dist/cjs/cli/lib/command.js +1 -1
- package/dist/cjs/cli/lib/command.js.map +1 -1
- package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
- package/dist/cjs/cli/lib/login.js +51 -0
- package/dist/cjs/cli/lib/login.js.map +3 -3
- package/dist/cjs/cli/lib/usage.js +13 -6
- package/dist/cjs/cli/lib/usage.js.map +2 -2
- package/dist/cjs/cli/lib/workos/environmentApi.js +6 -12
- package/dist/cjs/cli/lib/workos/environmentApi.js.map +3 -3
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/client.js +40 -42
- package/dist/cjs/react/client.js.map +2 -2
- package/dist/cjs/react/index.js +1 -0
- package/dist/cjs/react/index.js.map +2 -2
- package/dist/cjs/react/use_paginated_query.js +5 -46
- package/dist/cjs/react/use_paginated_query.js.map +2 -2
- package/dist/cjs/react/use_paginated_query2.js.map +2 -2
- package/dist/cjs/server/audit_logging.js +67 -0
- package/dist/cjs/server/audit_logging.js.map +7 -0
- package/dist/cjs/server/impl/meta_impl.js +27 -3
- package/dist/cjs/server/impl/meta_impl.js.map +2 -2
- package/dist/cjs/server/impl/registration_impl.js +2 -0
- package/dist/cjs/server/impl/registration_impl.js.map +2 -2
- package/dist/cjs/server/index.js +2 -0
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/log.js +30 -0
- package/dist/cjs/server/log.js.map +7 -0
- package/dist/cjs/server/logVars.js +48 -0
- package/dist/cjs/server/logVars.js.map +7 -0
- package/dist/cjs/server/meta.js.map +1 -1
- package/dist/cjs/server/registration.js.map +1 -1
- package/dist/cjs-types/cli/codegen_templates/agentsmd.d.ts.map +1 -1
- package/dist/cjs-types/cli/codegen_templates/claudemd.d.ts.map +1 -1
- package/dist/cjs-types/cli/configure.d.ts.map +1 -1
- package/dist/cjs-types/cli/deployment.d.ts.map +1 -1
- package/dist/cjs-types/cli/deploymentToken.d.ts +3 -0
- package/dist/cjs-types/cli/deploymentToken.d.ts.map +1 -0
- package/dist/cjs-types/cli/deploymentToken.test.d.ts +2 -0
- package/dist/cjs-types/cli/deploymentToken.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/deploymentTokenCreate.d.ts +13 -0
- package/dist/cjs-types/cli/deploymentTokenCreate.d.ts.map +1 -0
- package/dist/cjs-types/cli/deploymentTokenDelete.d.ts +11 -0
- package/dist/cjs-types/cli/deploymentTokenDelete.d.ts.map +1 -0
- package/dist/cjs-types/cli/envDefault.d.ts +2 -2
- package/dist/cjs-types/cli/envDefault.d.ts.map +1 -1
- package/dist/cjs-types/cli/envDefault.test.d.ts +2 -0
- package/dist/cjs-types/cli/envDefault.test.d.ts.map +1 -0
- package/dist/cjs-types/cli/generatedApi.d.ts +1 -1
- package/dist/cjs-types/cli/generatedApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +1 -0
- package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/usage.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/workos/environmentApi.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts +2 -0
- package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts.map +1 -0
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/react/client.d.ts +52 -0
- package/dist/cjs-types/react/client.d.ts.map +1 -1
- package/dist/cjs-types/react/index.d.ts +2 -2
- package/dist/cjs-types/react/index.d.ts.map +1 -1
- package/dist/cjs-types/react/use_paginated_query.d.ts.map +1 -1
- package/dist/cjs-types/react/use_paginated_query2.d.ts +63 -1
- package/dist/cjs-types/react/use_paginated_query2.d.ts.map +1 -1
- package/dist/cjs-types/server/api.intersect.test.d.ts +2 -0
- package/dist/cjs-types/server/api.intersect.test.d.ts.map +1 -0
- package/dist/cjs-types/server/audit_logging.d.ts +19 -0
- package/dist/cjs-types/server/audit_logging.d.ts.map +1 -0
- package/dist/cjs-types/server/audit_logging.test.d.ts +2 -0
- package/dist/cjs-types/server/audit_logging.test.d.ts.map +1 -0
- package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/registration_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/log.d.ts +2 -0
- package/dist/cjs-types/server/log.d.ts.map +1 -0
- package/dist/cjs-types/server/logVars.d.ts +20 -0
- package/dist/cjs-types/server/logVars.d.ts.map +1 -0
- package/dist/cjs-types/server/meta.d.ts +40 -0
- package/dist/cjs-types/server/meta.d.ts.map +1 -1
- package/dist/cjs-types/server/registration.d.ts +5 -2
- package/dist/cjs-types/server/registration.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +362 -74
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/cli/codegen_templates/agentsmd.js +8 -2
- package/dist/esm/cli/codegen_templates/agentsmd.js.map +2 -2
- package/dist/esm/cli/codegen_templates/claudemd.js +2 -0
- package/dist/esm/cli/codegen_templates/claudemd.js.map +2 -2
- package/dist/esm/cli/configure.js +0 -8
- package/dist/esm/cli/configure.js.map +2 -2
- package/dist/esm/cli/deployment.js +2 -1
- package/dist/esm/cli/deployment.js.map +2 -2
- package/dist/esm/cli/deploymentToken.js +8 -0
- package/dist/esm/cli/deploymentToken.js.map +7 -0
- package/dist/esm/cli/deploymentTokenCreate.js +91 -0
- package/dist/esm/cli/deploymentTokenCreate.js.map +7 -0
- package/dist/esm/cli/deploymentTokenDelete.js +68 -0
- package/dist/esm/cli/deploymentTokenDelete.js.map +7 -0
- package/dist/esm/cli/envDefault.js +131 -42
- package/dist/esm/cli/envDefault.js.map +3 -3
- package/dist/esm/cli/lib/command.js +1 -1
- package/dist/esm/cli/lib/command.js.map +1 -1
- package/dist/esm/cli/lib/login.js +52 -0
- package/dist/esm/cli/lib/login.js.map +3 -3
- package/dist/esm/cli/lib/usage.js +15 -8
- package/dist/esm/cli/lib/usage.js.map +2 -2
- package/dist/esm/cli/lib/workos/environmentApi.js +6 -12
- package/dist/esm/cli/lib/workos/environmentApi.js.map +3 -3
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/client.js +38 -41
- package/dist/esm/react/client.js.map +2 -2
- package/dist/esm/react/index.js +4 -1
- package/dist/esm/react/index.js.map +2 -2
- package/dist/esm/react/use_paginated_query.js +5 -46
- package/dist/esm/react/use_paginated_query.js.map +2 -2
- package/dist/esm/react/use_paginated_query2.js.map +2 -2
- package/dist/esm/server/audit_logging.js +44 -0
- package/dist/esm/server/audit_logging.js.map +7 -0
- package/dist/esm/server/impl/meta_impl.js +27 -3
- package/dist/esm/server/impl/meta_impl.js.map +2 -2
- package/dist/esm/server/impl/registration_impl.js +2 -0
- package/dist/esm/server/impl/registration_impl.js.map +2 -2
- package/dist/esm/server/index.js +1 -0
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/server/log.js +8 -0
- package/dist/esm/server/log.js.map +7 -0
- package/dist/esm/server/logVars.js +25 -0
- package/dist/esm/server/logVars.js.map +7 -0
- package/dist/esm-types/cli/codegen_templates/agentsmd.d.ts.map +1 -1
- package/dist/esm-types/cli/codegen_templates/claudemd.d.ts.map +1 -1
- package/dist/esm-types/cli/configure.d.ts.map +1 -1
- package/dist/esm-types/cli/deployment.d.ts.map +1 -1
- package/dist/esm-types/cli/deploymentToken.d.ts +3 -0
- package/dist/esm-types/cli/deploymentToken.d.ts.map +1 -0
- package/dist/esm-types/cli/deploymentToken.test.d.ts +2 -0
- package/dist/esm-types/cli/deploymentToken.test.d.ts.map +1 -0
- package/dist/esm-types/cli/deploymentTokenCreate.d.ts +13 -0
- package/dist/esm-types/cli/deploymentTokenCreate.d.ts.map +1 -0
- package/dist/esm-types/cli/deploymentTokenDelete.d.ts +11 -0
- package/dist/esm-types/cli/deploymentTokenDelete.d.ts.map +1 -0
- package/dist/esm-types/cli/envDefault.d.ts +2 -2
- package/dist/esm-types/cli/envDefault.d.ts.map +1 -1
- package/dist/esm-types/cli/envDefault.test.d.ts +2 -0
- package/dist/esm-types/cli/envDefault.test.d.ts.map +1 -0
- package/dist/esm-types/cli/generatedApi.d.ts +1 -1
- package/dist/esm-types/cli/generatedApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +1 -0
- package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/usage.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/workos/environmentApi.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts +2 -0
- package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts.map +1 -0
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/react/client.d.ts +52 -0
- package/dist/esm-types/react/client.d.ts.map +1 -1
- package/dist/esm-types/react/index.d.ts +2 -2
- package/dist/esm-types/react/index.d.ts.map +1 -1
- package/dist/esm-types/react/use_paginated_query.d.ts.map +1 -1
- package/dist/esm-types/react/use_paginated_query2.d.ts +63 -1
- package/dist/esm-types/react/use_paginated_query2.d.ts.map +1 -1
- package/dist/esm-types/server/api.intersect.test.d.ts +2 -0
- package/dist/esm-types/server/api.intersect.test.d.ts.map +1 -0
- package/dist/esm-types/server/audit_logging.d.ts +19 -0
- package/dist/esm-types/server/audit_logging.d.ts.map +1 -0
- package/dist/esm-types/server/audit_logging.test.d.ts +2 -0
- package/dist/esm-types/server/audit_logging.test.d.ts.map +1 -0
- package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -1
- package/dist/esm-types/server/impl/registration_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/log.d.ts +2 -0
- package/dist/esm-types/server/log.d.ts.map +1 -0
- package/dist/esm-types/server/logVars.d.ts +20 -0
- package/dist/esm-types/server/logVars.d.ts.map +1 -0
- package/dist/esm-types/server/meta.d.ts +40 -0
- package/dist/esm-types/server/meta.d.ts.map +1 -1
- package/dist/esm-types/server/registration.d.ts +5 -2
- package/dist/esm-types/server/registration.d.ts.map +1 -1
- package/dist/react.bundle.js +45 -88
- package/dist/react.bundle.js.map +2 -2
- package/package.json +4 -4
- package/src/cli/codegen_templates/agentsmd.ts +8 -2
- package/src/cli/codegen_templates/claudemd.ts +2 -0
- package/src/cli/configure.ts +0 -9
- package/src/cli/deployment.ts +3 -1
- package/src/cli/deploymentToken.test.ts +372 -0
- package/src/cli/deploymentToken.ts +11 -0
- package/src/cli/deploymentTokenCreate.ts +113 -0
- package/src/cli/deploymentTokenDelete.ts +91 -0
- package/src/cli/envDefault.test.ts +495 -0
- package/src/cli/envDefault.ts +222 -107
- package/src/cli/generatedApi.ts +1 -1
- package/src/cli/lib/command.ts +1 -1
- package/src/cli/lib/generatedFunctionLogsApi.ts +1 -0
- package/src/cli/lib/login.ts +67 -0
- package/src/cli/lib/usage.ts +18 -8
- package/src/cli/lib/workos/environmentApi.test.ts +107 -0
- package/src/cli/lib/workos/environmentApi.ts +12 -19
- package/src/index.ts +1 -1
- package/src/react/client.test.tsx +10 -8
- package/src/react/client.ts +88 -96
- package/src/react/index.ts +6 -1
- package/src/react/use_paginated_query.test.tsx +215 -132
- package/src/react/use_paginated_query.ts +8 -142
- package/src/react/use_paginated_query2.ts +78 -5
- package/src/react/use_query_object_options.test.ts +8 -7
- package/src/react/use_query_result.test.ts +40 -7
- package/src/server/api.intersect.test.ts +109 -0
- package/src/server/audit_logging.test.ts +129 -0
- package/src/server/audit_logging.ts +75 -0
- package/src/server/impl/meta_impl.ts +28 -0
- package/src/server/impl/registration_impl.ts +2 -0
- package/src/server/index.ts +12 -0
- package/src/server/log.ts +16 -0
- package/src/server/logVars.ts +34 -0
- package/src/server/meta.ts +53 -1
- package/src/server/registration.ts +10 -8
package/src/cli/envDefault.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from "@commander-js/extra-typings";
|
|
1
|
+
import { Command, Option } from "@commander-js/extra-typings";
|
|
2
2
|
import {
|
|
3
3
|
envGet,
|
|
4
4
|
envList,
|
|
@@ -14,120 +14,134 @@ import {
|
|
|
14
14
|
DeploymentType,
|
|
15
15
|
fetchTeamAndProject,
|
|
16
16
|
} from "./lib/api.js";
|
|
17
|
-
import { Context } from "../bundler/context.js";
|
|
17
|
+
import { Context, oneoffContext } from "../bundler/context.js";
|
|
18
18
|
import { selectEnvDeployment } from "./env.js";
|
|
19
|
+
import { getProjectDetails } from "./lib/deploymentSelection.js";
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.description(
|
|
25
|
-
"Set default environment variables for your project's deployment type.\n\n" +
|
|
26
|
-
" npx convex env default set NAME 'value'\n" +
|
|
27
|
-
" npx convex env default set NAME # omit a value to set one interactively\n" +
|
|
28
|
-
" npx convex env default set NAME --from-file value.txt\n" +
|
|
29
|
-
" npx convex env default set --from-file .env.defaults\n" +
|
|
30
|
-
"When setting multiple values, it will refuse all changes if any " +
|
|
31
|
-
"variables are already set to different values by default. " +
|
|
32
|
-
"Pass --force to overwrite the provided values.\n" +
|
|
33
|
-
"The deployment type is determined by the current deployment (local maps to dev).\n",
|
|
34
|
-
)
|
|
35
|
-
.option(
|
|
36
|
-
"--from-file <file>",
|
|
37
|
-
"Read environment variables from a .env file. Without --force, fails if any existing variable has a different value.",
|
|
38
|
-
)
|
|
39
|
-
.option(
|
|
40
|
-
"--force",
|
|
41
|
-
"When setting multiple variables, overwrite existing environment variable values instead of failing on mismatch.",
|
|
42
|
-
)
|
|
43
|
-
.configureHelp({ showGlobalOptions: true })
|
|
44
|
-
.allowExcessArguments(false)
|
|
45
|
-
.action(async (name, value, cmdOptions, cmd) => {
|
|
46
|
-
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions;
|
|
47
|
-
const { ctx, deployment } = await selectEnvDeployment(options);
|
|
48
|
-
await ensureHasConvexDependency(ctx, "env default set");
|
|
49
|
-
const backend = await resolveDefaultEnvBackend(
|
|
50
|
-
ctx,
|
|
51
|
-
deployment.deploymentFields,
|
|
52
|
-
);
|
|
53
|
-
const didAnything = await envSet(ctx, backend, name, value, cmdOptions);
|
|
54
|
-
if (didAnything === false) {
|
|
55
|
-
cmd.outputHelp({ error: true });
|
|
56
|
-
return await ctx.crash({
|
|
57
|
-
exitCode: 1,
|
|
58
|
-
errorType: "fatal",
|
|
59
|
-
printedMessage: "error: No environment variables specified to be set.",
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
});
|
|
21
|
+
type EnvDefaultExtraOptions = {
|
|
22
|
+
type?: string;
|
|
23
|
+
project?: string;
|
|
24
|
+
};
|
|
63
25
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
deployment.deploymentFields,
|
|
80
|
-
);
|
|
81
|
-
await envGet(ctx, backend, envVarName);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const envDefaultRemove = new Command("remove")
|
|
85
|
-
.alias("rm")
|
|
86
|
-
.alias("unset")
|
|
87
|
-
.arguments("<name>")
|
|
88
|
-
.summary("Unset a default variable")
|
|
89
|
-
.description(
|
|
90
|
-
"Unset a default variable: `npx convex env default remove NAME`\n" +
|
|
91
|
-
"If the variable doesn't exist, the command doesn't do anything and succeeds.\n" +
|
|
92
|
-
"The deployment type is determined by the current deployment (local maps to dev).",
|
|
93
|
-
)
|
|
94
|
-
.configureHelp({ showGlobalOptions: true })
|
|
95
|
-
.allowExcessArguments(false)
|
|
96
|
-
.action(async (name, _options, cmd) => {
|
|
97
|
-
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions;
|
|
98
|
-
const { ctx, deployment } = await selectEnvDeployment(options);
|
|
99
|
-
await ensureHasConvexDependency(ctx, "env default remove");
|
|
100
|
-
const backend = await resolveDefaultEnvBackend(
|
|
101
|
-
ctx,
|
|
102
|
-
deployment.deploymentFields,
|
|
103
|
-
);
|
|
104
|
-
await envRemove(ctx, backend, name);
|
|
105
|
-
});
|
|
26
|
+
function addEnvDefaultOptions<T extends Command<any, any>>(cmd: T): T {
|
|
27
|
+
return cmd
|
|
28
|
+
.addOption(
|
|
29
|
+
new Option(
|
|
30
|
+
"--type <type>",
|
|
31
|
+
"Manage default env vars for the given deployment type (dev, preview, prod) instead of inferring from the current deployment.",
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
.addOption(
|
|
35
|
+
new Option(
|
|
36
|
+
"--project <project>",
|
|
37
|
+
"Select a project manually. Accepts `team-slug:project-slug` or just `project-slug` (team inferred from your current project). Requires --type.",
|
|
38
|
+
),
|
|
39
|
+
) as T;
|
|
40
|
+
}
|
|
106
41
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
|
|
42
|
+
const envDefaultSet = addEnvDefaultOptions(
|
|
43
|
+
new Command("set")
|
|
44
|
+
.usage("[options] <name> <value>")
|
|
45
|
+
.arguments("[name] [value]")
|
|
46
|
+
.summary("Set a default variable")
|
|
47
|
+
.description(
|
|
48
|
+
"Set default environment variables for your project's deployment type.\n\n" +
|
|
49
|
+
" npx convex env default set NAME 'value'\n" +
|
|
50
|
+
" npx convex env default set NAME # omit a value to set one interactively\n" +
|
|
51
|
+
" npx convex env default set NAME --from-file value.txt\n" +
|
|
52
|
+
" npx convex env default set --from-file .env.defaults\n" +
|
|
53
|
+
"When setting multiple values, it will refuse all changes if any " +
|
|
54
|
+
"variables are already set to different values by default. " +
|
|
55
|
+
"Pass --force to overwrite the provided values.\n" +
|
|
56
|
+
"The deployment type is determined by the current deployment (local maps to dev), or by --type if provided.\n",
|
|
57
|
+
)
|
|
58
|
+
.option(
|
|
59
|
+
"--from-file <file>",
|
|
60
|
+
"Read environment variables from a .env file. Without --force, fails if any existing variable has a different value.",
|
|
61
|
+
)
|
|
62
|
+
.option(
|
|
63
|
+
"--force",
|
|
64
|
+
"When setting multiple variables, overwrite existing environment variable values instead of failing on mismatch.",
|
|
65
|
+
)
|
|
66
|
+
.configureHelp({ showGlobalOptions: true })
|
|
67
|
+
.allowExcessArguments(false),
|
|
68
|
+
).action(async (name, value, cmdOptions, cmd) => {
|
|
69
|
+
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions &
|
|
70
|
+
EnvDefaultExtraOptions;
|
|
71
|
+
const { ctx, backend } = await resolveEnvDefaultBackend(options);
|
|
72
|
+
await ensureHasConvexDependency(ctx, "env default set");
|
|
73
|
+
const didAnything = await envSet(ctx, backend, name, value, cmdOptions);
|
|
74
|
+
if (didAnything === false) {
|
|
75
|
+
cmd.outputHelp({ error: true });
|
|
76
|
+
return await ctx.crash({
|
|
77
|
+
exitCode: 1,
|
|
78
|
+
errorType: "fatal",
|
|
79
|
+
printedMessage: "error: No environment variables specified to be set.",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const envDefaultGet = addEnvDefaultOptions(
|
|
85
|
+
new Command("get")
|
|
86
|
+
.arguments("<name>")
|
|
87
|
+
.summary("Print a default variable's value")
|
|
88
|
+
.description(
|
|
89
|
+
"Print a default variable's value: `npx convex env default get NAME`\n" +
|
|
90
|
+
"The deployment type is determined by the current deployment (local maps to dev), or by --type if provided.",
|
|
91
|
+
)
|
|
92
|
+
.configureHelp({ showGlobalOptions: true })
|
|
93
|
+
.allowExcessArguments(false),
|
|
94
|
+
).action(async (envVarName, _options, cmd) => {
|
|
95
|
+
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions &
|
|
96
|
+
EnvDefaultExtraOptions;
|
|
97
|
+
const { ctx, backend } = await resolveEnvDefaultBackend(options);
|
|
98
|
+
await ensureHasConvexDependency(ctx, "env default get");
|
|
99
|
+
await envGet(ctx, backend, envVarName);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const envDefaultRemove = addEnvDefaultOptions(
|
|
103
|
+
new Command("remove")
|
|
104
|
+
.alias("rm")
|
|
105
|
+
.alias("unset")
|
|
106
|
+
.arguments("<name>")
|
|
107
|
+
.summary("Unset a default variable")
|
|
108
|
+
.description(
|
|
109
|
+
"Unset a default variable: `npx convex env default remove NAME`\n" +
|
|
110
|
+
"If the variable doesn't exist, the command doesn't do anything and succeeds.\n" +
|
|
111
|
+
"The deployment type is determined by the current deployment (local maps to dev), or by --type if provided.",
|
|
112
|
+
)
|
|
113
|
+
.configureHelp({ showGlobalOptions: true })
|
|
114
|
+
.allowExcessArguments(false),
|
|
115
|
+
).action(async (name, _options, cmd) => {
|
|
116
|
+
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions &
|
|
117
|
+
EnvDefaultExtraOptions;
|
|
118
|
+
const { ctx, backend } = await resolveEnvDefaultBackend(options);
|
|
119
|
+
await ensureHasConvexDependency(ctx, "env default remove");
|
|
120
|
+
await envRemove(ctx, backend, name);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const envDefaultList = addEnvDefaultOptions(
|
|
124
|
+
new Command("list")
|
|
125
|
+
.summary("List all default variables")
|
|
126
|
+
.description(
|
|
127
|
+
"List all default variables: `npx convex env default list`\n" +
|
|
128
|
+
"The deployment type is determined by the current deployment (local maps to dev), or by --type if provided.",
|
|
129
|
+
)
|
|
130
|
+
.configureHelp({ showGlobalOptions: true })
|
|
131
|
+
.allowExcessArguments(false),
|
|
132
|
+
).action(async (_options, cmd) => {
|
|
133
|
+
const options = cmd.optsWithGlobals() as DeploymentSelectionOptions &
|
|
134
|
+
EnvDefaultExtraOptions;
|
|
135
|
+
const { ctx, backend } = await resolveEnvDefaultBackend(options);
|
|
136
|
+
await ensureHasConvexDependency(ctx, "env default list");
|
|
137
|
+
await envList(ctx, backend);
|
|
138
|
+
});
|
|
125
139
|
|
|
126
140
|
export const envDefault = new Command("default")
|
|
127
141
|
.summary("Manage project-level default environment variables")
|
|
128
142
|
.description(
|
|
129
143
|
"Manage default environment variables for your project.\n\n" +
|
|
130
|
-
"The default environment variables read and written to by this command are the ones for the deployment type of the current deployment (i.e. dev in most cases).\n\n" +
|
|
144
|
+
"The default environment variables read and written to by this command are the ones for the deployment type of the current deployment (i.e. dev in most cases), unless --type is provided.\n\n" +
|
|
131
145
|
" Set a default variable: `npx convex env default set NAME 'value'`\n" +
|
|
132
146
|
" Unset a default variable: `npx convex env default remove NAME`\n" +
|
|
133
147
|
" List all default variables: `npx convex env default list`\n" +
|
|
@@ -139,12 +153,112 @@ export const envDefault = new Command("default")
|
|
|
139
153
|
.addCommand(envDefaultList)
|
|
140
154
|
.helpCommand(false);
|
|
141
155
|
|
|
156
|
+
type ParsedProjectOption =
|
|
157
|
+
| { kind: "teamAndProject"; teamSlug: string; projectSlug: string }
|
|
158
|
+
| { kind: "projectOnly"; projectSlug: string };
|
|
159
|
+
|
|
160
|
+
async function resolveEnvDefaultBackend(
|
|
161
|
+
options: DeploymentSelectionOptions & EnvDefaultExtraOptions,
|
|
162
|
+
): Promise<{ ctx: Context; backend: EnvVarBackend }> {
|
|
163
|
+
const dtypeOverride = normalizeTypeOption(options.type);
|
|
164
|
+
|
|
165
|
+
if (options.project !== undefined) {
|
|
166
|
+
const parsedProject = parseProjectOption(options.project);
|
|
167
|
+
if (parsedProject === null) {
|
|
168
|
+
const ctx = await oneoffContext(options);
|
|
169
|
+
return await ctx.crash({
|
|
170
|
+
exitCode: 1,
|
|
171
|
+
errorType: "fatal",
|
|
172
|
+
printedMessage:
|
|
173
|
+
"error: --project must be `team-slug:project-slug` or `project-slug`.",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (dtypeOverride === undefined) {
|
|
177
|
+
const ctx = await oneoffContext(options);
|
|
178
|
+
return await ctx.crash({
|
|
179
|
+
exitCode: 1,
|
|
180
|
+
errorType: "fatal",
|
|
181
|
+
printedMessage: "error: --project requires --type to also be set.",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let ctx: Context;
|
|
186
|
+
let resolved: { teamSlug: string; projectSlug: string };
|
|
187
|
+
if (parsedProject.kind === "teamAndProject") {
|
|
188
|
+
ctx = await oneoffContext(options);
|
|
189
|
+
resolved = {
|
|
190
|
+
teamSlug: parsedProject.teamSlug,
|
|
191
|
+
projectSlug: parsedProject.projectSlug,
|
|
192
|
+
};
|
|
193
|
+
} else {
|
|
194
|
+
const selected = await selectEnvDeployment(options);
|
|
195
|
+
ctx = selected.ctx;
|
|
196
|
+
if (selected.deployment.deploymentFields === null) {
|
|
197
|
+
return await ctx.crash({
|
|
198
|
+
exitCode: 1,
|
|
199
|
+
errorType: "fatal",
|
|
200
|
+
printedMessage:
|
|
201
|
+
"error: --project <project-slug> requires a current cloud deployment to infer the team from. Use `team-slug:project-slug` to specify the team explicitly.",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const { team } = await fetchTeamAndProject(
|
|
205
|
+
ctx,
|
|
206
|
+
selected.deployment.deploymentFields.deploymentName,
|
|
207
|
+
);
|
|
208
|
+
resolved = { teamSlug: team, projectSlug: parsedProject.projectSlug };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const details = await getProjectDetails(ctx, {
|
|
212
|
+
kind: "teamAndProjectSlugs",
|
|
213
|
+
teamSlug: resolved.teamSlug,
|
|
214
|
+
projectSlug: resolved.projectSlug,
|
|
215
|
+
});
|
|
216
|
+
return {
|
|
217
|
+
ctx,
|
|
218
|
+
backend: defaultEnvBackend(ctx, details.id, dtypeOverride),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const { ctx, deployment } = await selectEnvDeployment(options);
|
|
223
|
+
const backend = await resolveDefaultEnvBackend(
|
|
224
|
+
ctx,
|
|
225
|
+
deployment.deploymentFields,
|
|
226
|
+
dtypeOverride,
|
|
227
|
+
);
|
|
228
|
+
return { ctx, backend };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function normalizeTypeOption(
|
|
232
|
+
type: string | undefined,
|
|
233
|
+
): CloudDeploymentType | undefined {
|
|
234
|
+
if (type === undefined) return undefined;
|
|
235
|
+
if (type === "development") return "dev";
|
|
236
|
+
if (type === "production") return "prod";
|
|
237
|
+
return type as CloudDeploymentType;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function parseProjectOption(value: string): ParsedProjectOption | null {
|
|
241
|
+
const parts = value.split(":");
|
|
242
|
+
if (parts.length === 1 && parts[0].length > 0) {
|
|
243
|
+
return { kind: "projectOnly", projectSlug: parts[0] };
|
|
244
|
+
}
|
|
245
|
+
if (parts.length === 2 && parts[0].length > 0 && parts[1].length > 0) {
|
|
246
|
+
return {
|
|
247
|
+
kind: "teamAndProject",
|
|
248
|
+
teamSlug: parts[0],
|
|
249
|
+
projectSlug: parts[1],
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
142
255
|
export async function resolveDefaultEnvBackend(
|
|
143
256
|
ctx: Context,
|
|
144
257
|
deploymentFields: {
|
|
145
258
|
deploymentName: string;
|
|
146
259
|
deploymentType: DeploymentType;
|
|
147
260
|
} | null,
|
|
261
|
+
dtypeOverride?: CloudDeploymentType,
|
|
148
262
|
): Promise<EnvVarBackend> {
|
|
149
263
|
if (deploymentFields === null) {
|
|
150
264
|
return await ctx.crash({
|
|
@@ -162,7 +276,8 @@ export async function resolveDefaultEnvBackend(
|
|
|
162
276
|
"Default environment variables are not available for anonymous deployments.",
|
|
163
277
|
});
|
|
164
278
|
}
|
|
165
|
-
const dtype =
|
|
279
|
+
const dtype =
|
|
280
|
+
dtypeOverride ?? resolveDefaultEnvDtype(deploymentFields.deploymentType);
|
|
166
281
|
const { projectId } = await fetchTeamAndProject(
|
|
167
282
|
ctx,
|
|
168
283
|
deploymentFields.deploymentName,
|
package/src/cli/generatedApi.ts
CHANGED
|
@@ -486,7 +486,7 @@ export interface components {
|
|
|
486
486
|
name: string;
|
|
487
487
|
};
|
|
488
488
|
/** @enum {string} */
|
|
489
|
-
WorkOSProductionState: "active" | "inactive";
|
|
489
|
+
WorkOSProductionState: "active" | "inactive" | "suspended" | "deleting";
|
|
490
490
|
WorkOSTeamHealthResponse: {
|
|
491
491
|
teamInfo?: null | components["schemas"]["WorkOSTeamInfo"];
|
|
492
492
|
/** @description Whether a WorkOS team has been provisioned for this Convex team */
|
package/src/cli/lib/command.ts
CHANGED
|
@@ -216,7 +216,7 @@ Command.prototype.addDeploymentSelectionOptions = function (
|
|
|
216
216
|
"--deployment <deployment>",
|
|
217
217
|
action +
|
|
218
218
|
" a specific deployment. Accepts:\n" +
|
|
219
|
-
"• a deployment name (e.g. joyful-capybara-123)" +
|
|
219
|
+
"• a deployment name (e.g. joyful-capybara-123)\n" +
|
|
220
220
|
"• a deployment reference (e.g. dev/james, staging)\n" +
|
|
221
221
|
"• `dev` (for your personal dev deployment)\n" +
|
|
222
222
|
"• `prod` (for your project’s default production deployment)\n" +
|
package/src/cli/lib/login.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { errors, BaseClient, custom } from "openid-client";
|
|
2
2
|
import {
|
|
3
3
|
bigBrainAPI,
|
|
4
|
+
bigBrainFetch,
|
|
4
5
|
logAndHandleFetchError,
|
|
5
6
|
throwingFetch,
|
|
6
7
|
isWebContainer,
|
|
@@ -427,6 +428,72 @@ export async function performLogin(
|
|
|
427
428
|
printedMessage: null,
|
|
428
429
|
});
|
|
429
430
|
}
|
|
431
|
+
|
|
432
|
+
if (vercel) {
|
|
433
|
+
await promptJoinVercelTeams(ctx);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
type PotentialVercelTeam = {
|
|
438
|
+
teamId: number;
|
|
439
|
+
teamName: string;
|
|
440
|
+
teamSlug: string;
|
|
441
|
+
planId: string;
|
|
442
|
+
planName: string;
|
|
443
|
+
pricingNotice: string | null;
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// After `--vercel` login, surface any Vercel-marketplace teams the user has
|
|
447
|
+
// access to but isn't yet a member of, and prompt to join each.
|
|
448
|
+
async function promptJoinVercelTeams(ctx: Context): Promise<void> {
|
|
449
|
+
const fetch = bigBrainFetch(ctx);
|
|
450
|
+
let teams: PotentialVercelTeam[];
|
|
451
|
+
try {
|
|
452
|
+
const res = await fetch(
|
|
453
|
+
new URL("vercel/potential_teams", `${provisionHost}/`),
|
|
454
|
+
);
|
|
455
|
+
if (!res.ok) {
|
|
456
|
+
logVerbose(
|
|
457
|
+
`vercel/potential_teams returned ${res.status}; skipping team-join prompt`,
|
|
458
|
+
);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
teams = await res.json();
|
|
462
|
+
} catch (err) {
|
|
463
|
+
logVerbose(`Failed to fetch potential Vercel teams: ${String(err)}`);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (teams.length === 0) return;
|
|
467
|
+
|
|
468
|
+
for (const [index, team] of teams.entries()) {
|
|
469
|
+
const displayName = team.teamName.replace(/ \(Vercel\)$/, "");
|
|
470
|
+
const counter = teams.length > 1 ? `[${index + 1}/${teams.length}] ` : "";
|
|
471
|
+
const lines = [
|
|
472
|
+
chalkStderr.bold(`${counter}You've been invited to join ${displayName}`) +
|
|
473
|
+
` (${team.planName}) through the Vercel marketplace.`,
|
|
474
|
+
];
|
|
475
|
+
if (team.pricingNotice) {
|
|
476
|
+
lines.push(chalkStderr.yellow(team.pricingNotice));
|
|
477
|
+
}
|
|
478
|
+
lines.push(`Join "${displayName}"?`);
|
|
479
|
+
const join = await promptYesNo(ctx, {
|
|
480
|
+
message: `${lines.join("\n")}`,
|
|
481
|
+
default: true,
|
|
482
|
+
});
|
|
483
|
+
if (!join) continue;
|
|
484
|
+
try {
|
|
485
|
+
await fetch(
|
|
486
|
+
new URL(
|
|
487
|
+
`vercel/potential_teams/${team.teamId}/join`,
|
|
488
|
+
`${provisionHost}/`,
|
|
489
|
+
),
|
|
490
|
+
{ method: "POST" },
|
|
491
|
+
);
|
|
492
|
+
logFinishedStep(`Joined ${displayName}`);
|
|
493
|
+
} catch (err) {
|
|
494
|
+
logFailure(`Failed to join ${displayName}: ${String(err)}`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
430
497
|
}
|
|
431
498
|
|
|
432
499
|
/// There are fields like version, but we keep them opaque
|
package/src/cli/lib/usage.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { chalkStderr } from "chalk";
|
|
2
2
|
import { Context } from "../../bundler/context.js";
|
|
3
|
-
import { logWarning } from "../../bundler/log.js";
|
|
3
|
+
import { logVerbose, logWarning } from "../../bundler/log.js";
|
|
4
4
|
import { teamDashboardUrl } from "./dashboard.js";
|
|
5
5
|
import { fetchTeamAndProject } from "./api.js";
|
|
6
6
|
import { isAnonymousDeployment } from "./deployment.js";
|
|
7
|
-
import {
|
|
7
|
+
import { bigBrainAPIMaybeThrows } from "./utils/utils.js";
|
|
8
8
|
|
|
9
9
|
async function warn(
|
|
10
10
|
ctx: Context,
|
|
@@ -19,7 +19,7 @@ async function warn(
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async function teamUsageState(ctx: Context, teamId: number) {
|
|
22
|
-
const { usageState } = (await
|
|
22
|
+
const { usageState } = (await bigBrainAPIMaybeThrows({
|
|
23
23
|
ctx,
|
|
24
24
|
method: "GET",
|
|
25
25
|
path: "dashboard/teams/" + teamId + "/usage/team_usage_state",
|
|
@@ -31,7 +31,7 @@ async function teamUsageState(ctx: Context, teamId: number) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function teamSpendingLimitsState(ctx: Context, teamId: number) {
|
|
34
|
-
const response = (await
|
|
34
|
+
const response = (await bigBrainAPIMaybeThrows({
|
|
35
35
|
ctx,
|
|
36
36
|
method: "GET",
|
|
37
37
|
path: "dashboard/teams/" + teamId + "/get_spending_limits",
|
|
@@ -59,12 +59,22 @@ export async function usageStateWarning(
|
|
|
59
59
|
) {
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
|
+
|
|
62
63
|
const { teamId, team } = await fetchTeamAndProject(ctx, targetDeployment);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
let usageState: Awaited<ReturnType<typeof teamUsageState>>;
|
|
66
|
+
let spendingLimitsState: Awaited<ReturnType<typeof teamSpendingLimitsState>>;
|
|
67
|
+
try {
|
|
68
|
+
[usageState, spendingLimitsState] = await Promise.all([
|
|
69
|
+
teamUsageState(ctx, teamId),
|
|
70
|
+
teamSpendingLimitsState(ctx, teamId),
|
|
71
|
+
]);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
// Non-fatal: usage warnings are advisory, so don't block `convex dev`
|
|
74
|
+
// if these endpoints error.
|
|
75
|
+
logVerbose("Skipping usage state warning:", err);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
68
78
|
if (spendingLimitsState === "Disabled") {
|
|
69
79
|
await warn(ctx, {
|
|
70
80
|
title:
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach, vi } from "vitest";
|
|
2
|
+
import { Context } from "../../../bundler/context.js";
|
|
3
|
+
import { createCORSOrigin, createRedirectURI } from "./environmentApi.js";
|
|
4
|
+
|
|
5
|
+
const mockFetch = vi.fn();
|
|
6
|
+
global.fetch = mockFetch;
|
|
7
|
+
|
|
8
|
+
const ctx: Context = {
|
|
9
|
+
crash: vi.fn(async (args: { printedMessage: string | null }) => {
|
|
10
|
+
throw new Error(args.printedMessage ?? "crash");
|
|
11
|
+
}),
|
|
12
|
+
} as unknown as Context;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("createRedirectURI", () => {
|
|
19
|
+
test("returns modified: true on a successful response", async () => {
|
|
20
|
+
mockFetch.mockResolvedValue(new Response(null, { status: 201 }));
|
|
21
|
+
await expect(
|
|
22
|
+
createRedirectURI(ctx, "key", "http://localhost:5173"),
|
|
23
|
+
).resolves.toEqual({ modified: true });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("returns modified: false when the URI already exists", async () => {
|
|
27
|
+
mockFetch.mockResolvedValue(
|
|
28
|
+
new Response(
|
|
29
|
+
`{"message":"Redirect URI 'http://localhost:5173' already exists.","error":"Unprocessable Entity"}`,
|
|
30
|
+
{ status: 422 },
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
await expect(
|
|
34
|
+
createRedirectURI(ctx, "key", "http://localhost:5173"),
|
|
35
|
+
).resolves.toEqual({ modified: false });
|
|
36
|
+
expect(ctx.crash).not.toHaveBeenCalled();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("crashes with the body for a non-duplicate 422", async () => {
|
|
40
|
+
const body = `{"message":"Redirect URI 'test' is invalid.","error":"Unprocessable Entity"}`;
|
|
41
|
+
mockFetch.mockResolvedValue(new Response(body, { status: 422 }));
|
|
42
|
+
await expect(createRedirectURI(ctx, "key", "test")).rejects.toThrow(
|
|
43
|
+
`Failed to create redirect URI: 422 ${body}`,
|
|
44
|
+
);
|
|
45
|
+
expect(ctx.crash).toHaveBeenCalledWith(
|
|
46
|
+
expect.objectContaining({
|
|
47
|
+
exitCode: 1,
|
|
48
|
+
errorType: "fatal",
|
|
49
|
+
printedMessage: `Failed to create redirect URI: 422 ${body}`,
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("crashes with the body for non-422 errors", async () => {
|
|
55
|
+
const body = `{"message":"Unauthorized"}`;
|
|
56
|
+
mockFetch.mockResolvedValue(new Response(body, { status: 401 }));
|
|
57
|
+
await expect(createRedirectURI(ctx, "key", "http://x")).rejects.toThrow(
|
|
58
|
+
`Failed to create redirect URI: 401 ${body}`,
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("createCORSOrigin", () => {
|
|
64
|
+
test("returns modified: true on a successful response", async () => {
|
|
65
|
+
mockFetch.mockResolvedValue(new Response(null, { status: 201 }));
|
|
66
|
+
await expect(
|
|
67
|
+
createCORSOrigin(ctx, "key", "http://localhost:5173"),
|
|
68
|
+
).resolves.toEqual({ modified: true });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("returns modified: false on duplicate_cors_origin", async () => {
|
|
72
|
+
mockFetch.mockResolvedValue(
|
|
73
|
+
new Response(`{"code":"duplicate_cors_origin","message":"..."}`, {
|
|
74
|
+
status: 409,
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
await expect(
|
|
78
|
+
createCORSOrigin(ctx, "key", "http://localhost:5173"),
|
|
79
|
+
).resolves.toEqual({ modified: false });
|
|
80
|
+
expect(ctx.crash).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("returns modified: false when the origin already exists", async () => {
|
|
84
|
+
mockFetch.mockResolvedValue(
|
|
85
|
+
new Response(`{"message":"CORS origin already exists."}`, {
|
|
86
|
+
status: 409,
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
await expect(
|
|
90
|
+
createCORSOrigin(ctx, "key", "http://localhost:5173"),
|
|
91
|
+
).resolves.toEqual({ modified: false });
|
|
92
|
+
expect(ctx.crash).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("crashes with the body for a non-duplicate 409", async () => {
|
|
96
|
+
const body = `{"message":"Some other conflict."}`;
|
|
97
|
+
mockFetch.mockResolvedValue(new Response(body, { status: 409 }));
|
|
98
|
+
await expect(createCORSOrigin(ctx, "key", "http://x")).rejects.toThrow(
|
|
99
|
+
`Failed to create CORS origin: 409 ${body}`,
|
|
100
|
+
);
|
|
101
|
+
expect(ctx.crash).toHaveBeenCalledWith(
|
|
102
|
+
expect.objectContaining({
|
|
103
|
+
printedMessage: `Failed to create CORS origin: 409 ${body}`,
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|