jitsu-cli 1.10.4 → 1.11.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.
Files changed (61) hide show
  1. package/bin/jitsu +3 -0
  2. package/build.mts +39 -0
  3. package/compiled/package.json +27 -29
  4. package/compiled/src/commands/build.js +43 -55
  5. package/compiled/src/commands/config/handlers.js +292 -0
  6. package/compiled/src/commands/config/index.js +148 -0
  7. package/compiled/src/commands/config/resources.js +88 -0
  8. package/compiled/src/commands/default-workspace.js +39 -0
  9. package/compiled/src/commands/deploy.js +127 -78
  10. package/compiled/src/commands/init.js +17 -21
  11. package/compiled/src/commands/login.js +24 -27
  12. package/compiled/src/commands/shared.js +12 -17
  13. package/compiled/src/commands/spec.js +31 -0
  14. package/compiled/src/commands/test.js +7 -10
  15. package/compiled/src/commands/whoami.js +8 -12
  16. package/compiled/src/index.js +40 -24
  17. package/compiled/src/lib/api-client.js +52 -0
  18. package/compiled/src/lib/auth-file.js +67 -0
  19. package/compiled/src/lib/body-builder.js +53 -0
  20. package/compiled/src/lib/body-fields.js +47 -0
  21. package/compiled/src/lib/chalk-code-highlight.js +15 -20
  22. package/compiled/src/lib/compiled-function.js +27 -29
  23. package/compiled/src/lib/dotted.js +34 -0
  24. package/compiled/src/lib/indent.js +3 -8
  25. package/compiled/src/lib/project-config.js +20 -0
  26. package/compiled/src/lib/renderer.js +33 -0
  27. package/compiled/src/lib/spec.js +11 -0
  28. package/compiled/src/lib/template.js +7 -11
  29. package/compiled/src/lib/version.js +13 -20
  30. package/compiled/src/templates/functions.js +13 -18
  31. package/dist/main.js +45496 -86270
  32. package/dist/main.js.map +7 -1
  33. package/package.json +27 -29
  34. package/src/commands/build.ts +22 -27
  35. package/src/commands/config/handlers.ts +339 -0
  36. package/src/commands/config/index.ts +171 -0
  37. package/src/commands/config/resources.ts +110 -0
  38. package/src/commands/default-workspace.ts +44 -0
  39. package/src/commands/deploy.ts +145 -44
  40. package/src/commands/login.ts +3 -1
  41. package/src/commands/spec.ts +32 -0
  42. package/src/index.ts +36 -19
  43. package/src/lib/api-client.ts +64 -0
  44. package/src/lib/auth-file.ts +83 -0
  45. package/src/lib/body-builder.ts +68 -0
  46. package/src/lib/body-fields.ts +61 -0
  47. package/src/lib/compiled-function.ts +30 -23
  48. package/src/lib/dotted.ts +43 -0
  49. package/src/lib/project-config.ts +32 -0
  50. package/src/lib/renderer.ts +44 -0
  51. package/src/lib/spec.ts +32 -0
  52. package/tsconfig.json +2 -19
  53. package/.turbo/turbo-build.log +0 -28
  54. package/.turbo/turbo-clean.log +0 -5
  55. package/babel.config.cjs +0 -4
  56. package/dist/140.js +0 -452
  57. package/dist/140.js.map +0 -1
  58. package/dist/233.js +0 -4890
  59. package/dist/233.js.map +0 -1
  60. package/dist/445e7f36f8a19c2bf682.js +0 -900
  61. package/webpack.config.js +0 -49
package/bin/jitsu ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("../dist/main.js");
package/build.mts ADDED
@@ -0,0 +1,39 @@
1
+ import * as esbuild from "esbuild";
2
+ import { mkdirSync } from "fs";
3
+
4
+ // Ensure dist directory exists
5
+ mkdirSync("./dist", { recursive: true });
6
+
7
+ // External modules that should not be bundled
8
+ // These are either native modules or need to be loaded at runtime
9
+ const externalModules = [
10
+ // Native/binary modules
11
+ "figlet", // ASCII art library with data files
12
+ "fsevents", // macOS-only native file system events
13
+ "esbuild", // esbuild has native binaries, used at runtime to build user functions
14
+
15
+ // Large runtime dependencies
16
+ "typescript", // TypeScript compiler (large, used at runtime)
17
+ "jest-cli", // Jest test runner
18
+ ];
19
+
20
+ // Bundle the CLI
21
+ esbuild
22
+ .build({
23
+ entryPoints: ["./src/index.ts"],
24
+ bundle: true,
25
+ platform: "node",
26
+ target: "node20",
27
+ format: "cjs",
28
+ outfile: "./dist/main.js",
29
+ sourcemap: true,
30
+ minify: false,
31
+ external: externalModules,
32
+ logLevel: "info",
33
+ loader: {
34
+ ".json": "json",
35
+ },
36
+ })
37
+ .then(() => {
38
+ console.log("\nBuild complete!");
39
+ });
@@ -1,18 +1,27 @@
1
1
  {
2
2
  "name": "jitsu-cli",
3
- "version": "0.0.0",
3
+ "version": "1.11.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/jitsucom/jitsu",
7
+ "directory": "cli/jitsu-cli"
8
+ },
4
9
  "description": "",
5
10
  "author": "Jitsu Dev Team <dev@jitsu.com>",
6
11
  "publishConfig": {
7
12
  "access": "public"
8
13
  },
9
- "bin": "./bin/jitsu-cli",
14
+ "bin": {
15
+ "jitsu-cli": "./bin/jitsu-cli",
16
+ "jitsu": "./bin/jitsu"
17
+ },
10
18
  "license": "MIT",
11
19
  "private": false,
12
20
  "scripts": {
13
- "clean": "rm -rf ./dist",
14
- "compile": "tsc -p . ",
15
- "build": "pnpm compile && webpack",
21
+ "clean": "rm -rf ./dist ./compiled",
22
+ "typecheck": "tsc --noEmit",
23
+ "build": "tsc && tsx build.mts",
24
+ "cli": "tsx src/index.ts",
16
25
  "run": "pnpm build && node dist/main.js",
17
26
  "login": "pnpm build && node dist/main.js login",
18
27
  "init child": "pnpm build && node dist/main.js init",
@@ -22,31 +31,23 @@
22
31
  "deploy child": "pnpm build && node dist/main.js deploy"
23
32
  },
24
33
  "dependencies": {
34
+ "esbuild": "catalog:",
25
35
  "figlet": "^1.6.0",
26
36
  "jest-cli": "^29.7.0",
27
- "tslib": "^2.6.3",
28
- "typescript": "^5.6.3"
37
+ "tslib": "catalog:",
38
+ "typescript": "catalog:"
29
39
  },
30
40
  "devDependencies": {
31
- "@babel/preset-env": "^7.23.2",
32
- "@babel/preset-typescript": "^7.23.2",
41
+ "@jitsu/common-config": "workspace:*",
33
42
  "@jitsu/functions-lib": "workspace:*",
34
43
  "@jitsu/protocols": "workspace:*",
35
- "@rollup/plugin-commonjs": "^28.0.2",
36
- "@rollup/plugin-json": "^6.0.0",
37
- "@rollup/plugin-node-resolve": "^16.0.0",
38
- "@rollup/plugin-terser": "^0.4.3",
39
- "@rollup/plugin-typescript": "^11.1.3",
40
44
  "@types/chalk": "^2.2.0",
41
45
  "@types/commander": "^2.12.2",
42
46
  "@types/express": "^4.17.21",
43
47
  "@types/inquirer": "^9.0.3",
44
- "@types/jest": "^29.5.5",
45
- "@types/lodash": "^4.14.198",
46
- "@types/node": "^18.15.3",
47
- "@types/webpack": "^5.28.5",
48
- "@webpack-cli/generators": "^3.0.7",
49
- "babel-loader": "^9.1.3",
48
+ "@types/lodash": "catalog:",
49
+ "@types/node": "catalog:",
50
+ "@vitest/ui": "catalog:",
50
51
  "chalk": "^5.3.0",
51
52
  "commander": "^11.0.0",
52
53
  "cross-fetch": "^4.0.0",
@@ -54,18 +55,15 @@
54
55
  "etag": "^1.8.1",
55
56
  "inquirer": "^9.2.11",
56
57
  "jest": "^29.7.0",
58
+ "js-yaml": "^4.2.0",
59
+ "@types/js-yaml": "^4.0.9",
57
60
  "json5": "^2.2.3",
58
61
  "juava": "workspace:*",
59
- "lodash": "^4.17.21",
60
- "node-fetch": "^3.3.2",
61
- "node-loader": "^2.0.0",
62
+ "lodash": "catalog:",
62
63
  "prismjs": "^1.30.0",
63
- "rollup": "^3.29.5",
64
64
  "semver": "^7.5.4",
65
- "ts-jest": "^29.1.1",
66
- "ts-loader": "^9.5.1",
67
- "ts-node": "^10.9.2",
68
- "webpack": "^5.99.5",
69
- "webpack-cli": "^6.0.1"
65
+ "tsx": "catalog:",
66
+ "vitest": "catalog:",
67
+ "vite": "^6.4.3"
70
68
  }
71
69
  }
@@ -1,22 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.build = build;
4
- const tslib_1 = require("tslib");
5
- const path_1 = tslib_1.__importDefault(require("path"));
6
- const fs_1 = require("fs");
7
- const plugin_typescript_1 = tslib_1.__importDefault(require("@rollup/plugin-typescript"));
8
- const plugin_node_resolve_1 = tslib_1.__importDefault(require("@rollup/plugin-node-resolve"));
9
- const plugin_commonjs_1 = tslib_1.__importDefault(require("@rollup/plugin-commonjs"));
10
- const plugin_json_1 = tslib_1.__importDefault(require("@rollup/plugin-json"));
11
- const rollup_1 = require("rollup");
12
- const child_process_1 = require("child_process");
13
- const shared_1 = require("./shared");
14
- const chalk_code_highlight_1 = require("../lib/chalk-code-highlight");
15
- const compiled_function_1 = require("../lib/compiled-function");
16
- const ts = tslib_1.__importStar(require("typescript"));
17
- async function build({ dir }) {
18
- const { packageJson, projectDir } = await (0, shared_1.loadPackageJson)(dir || process.cwd());
19
- console.log(`Building ${(0, chalk_code_highlight_1.b)(packageJson.name)} project`);
1
+ import path from "path";
2
+ import { mkdirSync, readdirSync, existsSync, lstatSync } from "fs";
3
+ import * as esbuild from "esbuild";
4
+ import { exec } from "child_process";
5
+ import { loadPackageJson } from "./shared";
6
+ import { b, green, red } from "../lib/chalk-code-highlight";
7
+ import { getFunctionFromFilePath } from "../lib/compiled-function";
8
+ import * as ts from "typescript";
9
+ export async function build({ dir }) {
10
+ const { packageJson, projectDir } = await loadPackageJson(dir || process.cwd());
11
+ console.log(`Building ${b(packageJson.name)} project`);
20
12
  const errors = checkTypescript(projectDir);
21
13
  if (errors) {
22
14
  console.error(`Found ${errors.length} errors in functions files. Exiting`);
@@ -29,10 +21,10 @@ async function build({ dir }) {
29
21
  catch (e) {
30
22
  throw new Error(`Some of the functions failed to compile. See details above. Last error: ${e.message || "unknown"}`);
31
23
  }
32
- console.log(`${(0, chalk_code_highlight_1.b)("Build finished.")}`);
24
+ console.log(`${b("Build finished.")}`);
33
25
  }
34
26
  const run = async (cmd) => {
35
- const child = (0, child_process_1.exec)(cmd, err => {
27
+ const child = exec(cmd, err => {
36
28
  if (err) {
37
29
  console.error(err);
38
30
  return;
@@ -44,20 +36,20 @@ const run = async (cmd) => {
44
36
  };
45
37
  async function buildFiles(projectDir, dir = "") {
46
38
  let lastError = undefined;
47
- const srcDir = path_1.default.resolve(projectDir, "src", dir);
48
- if (!(0, fs_1.existsSync)(srcDir)) {
49
- console.info(`${(0, chalk_code_highlight_1.b)(dir)} directory not found in ${(0, chalk_code_highlight_1.b)(path_1.default.resolve(projectDir, "src"))}`);
39
+ const srcDir = path.resolve(projectDir, "src", dir);
40
+ if (!existsSync(srcDir)) {
41
+ console.info(`${b(dir)} directory not found in ${b(path.resolve(projectDir, "src"))}`);
50
42
  return;
51
43
  }
52
- const files = (0, fs_1.readdirSync)(srcDir);
44
+ const files = readdirSync(srcDir);
53
45
  if (files.length === 0) {
54
- console.warn(`No functions found in ${(0, chalk_code_highlight_1.b)(srcDir)} directory`);
46
+ console.warn(`No functions found in ${b(srcDir)} directory`);
55
47
  return;
56
48
  }
57
49
  for (const file of files) {
58
- if ((0, fs_1.lstatSync)(path_1.default.resolve(srcDir, file)).isDirectory()) {
50
+ if (lstatSync(path.resolve(srcDir, file)).isDirectory()) {
59
51
  try {
60
- await buildFiles(projectDir, path_1.default.join(dir, file));
52
+ await buildFiles(projectDir, path.join(dir, file));
61
53
  }
62
54
  catch (e) {
63
55
  lastError = e;
@@ -69,7 +61,7 @@ async function buildFiles(projectDir, dir = "") {
69
61
  }
70
62
  catch (e) {
71
63
  console.error([
72
- `${(0, chalk_code_highlight_1.red)(`⚠`)} Function ${(0, chalk_code_highlight_1.b)(file)} failed to compile: ${(0, chalk_code_highlight_1.red)(e?.message)}. See details below`,
64
+ `${red(`⚠`)} Function ${b(file)} failed to compile: ${red(e?.message)}. See details below`,
73
65
  ...(e?.stack?.split("\n") || []).map(s => ` ${s}`),
74
66
  ]
75
67
  .filter(Boolean)
@@ -82,55 +74,51 @@ async function buildFiles(projectDir, dir = "") {
82
74
  }
83
75
  }
84
76
  async function buildFile(projectDir, dir, fileName) {
85
- const funcFile = path_1.default.resolve(projectDir, "src", path_1.default.join(dir, fileName));
77
+ const funcFile = path.resolve(projectDir, "src", path.join(dir, fileName));
86
78
  process.chdir(projectDir);
87
- const rollupPlugins = [
88
- (0, plugin_typescript_1.default)(),
89
- (0, plugin_node_resolve_1.default)({ preferBuiltins: false }),
90
- (0, plugin_commonjs_1.default)(),
91
- (0, plugin_json_1.default)(),
92
- ];
93
- const bundle = await (0, rollup_1.rollup)({
94
- input: [funcFile],
95
- plugins: rollupPlugins,
79
+ mkdirSync(path.resolve(projectDir, "dist/" + dir), { recursive: true });
80
+ const compiledFunctionPath = `dist/${dir}/${fileName.replace(".ts", ".js")}`;
81
+ await esbuild.build({
82
+ entryPoints: [funcFile],
83
+ absWorkingDir: projectDir,
84
+ bundle: true,
85
+ platform: "neutral",
86
+ format: "esm",
87
+ outfile: path.resolve(projectDir, compiledFunctionPath),
96
88
  external: ["@jitsu/functions-lib"],
97
89
  logLevel: "silent",
90
+ loader: {
91
+ ".json": "json",
92
+ },
93
+ nodePaths: [path.resolve(projectDir, "node_modules")],
98
94
  });
99
- let format = "es";
100
- let output = await bundle.generate({
101
- dir: projectDir,
102
- format: format,
103
- });
104
- (0, fs_1.mkdirSync)(path_1.default.resolve(projectDir, "dist/" + dir), { recursive: true });
105
- const compiledFunctionPath = `dist/${dir}/${fileName.replace(".ts", ".js")}`;
106
- (0, fs_1.writeFileSync)(path_1.default.resolve(projectDir, compiledFunctionPath), output.output[0].code);
107
- const compiledFunction = await (0, compiled_function_1.getFunctionFromFilePath)(path_1.default.resolve(projectDir, compiledFunctionPath), "function");
108
- console.log([`${(0, chalk_code_highlight_1.green)(`✓`)} Function ${(0, chalk_code_highlight_1.b)(fileName)} compiled successfully`, ` slug = ${(0, chalk_code_highlight_1.b)(compiledFunction.meta.slug)}`]
95
+ const compiledFunction = await getFunctionFromFilePath(projectDir, path.resolve(projectDir, compiledFunctionPath), "function");
96
+ console.log([`${green(`✓`)} Function ${b(fileName)} compiled successfully`, ` slug = ${b(compiledFunction.meta.slug)}`]
109
97
  .filter(Boolean)
110
98
  .join("\n"));
111
99
  }
112
100
  function checkTypescript(projectDir) {
113
- const tsconfigPath = path_1.default.resolve(projectDir, "tsconfig.json");
114
- if (!(0, fs_1.existsSync)(tsconfigPath)) {
115
- console.info(`No ${(0, chalk_code_highlight_1.b)("tsconfig.json")} file found in ${(0, chalk_code_highlight_1.b)(projectDir)}. Assuming JavaScript project`);
101
+ const tsconfigPath = path.resolve(projectDir, "tsconfig.json");
102
+ if (!existsSync(tsconfigPath)) {
103
+ console.info(`No ${b("tsconfig.json")} file found in ${b(projectDir)}. Assuming JavaScript project`);
116
104
  return;
117
105
  }
118
- console.log(`Checking TypeScript files in ${(0, chalk_code_highlight_1.b)(projectDir)}`);
119
106
  let compilerOptions = {};
120
107
  let filenames = [];
121
108
  const tsconfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
122
109
  tsconfig.config.compilerOptions = {
123
110
  ...tsconfig.config.compilerOptions,
124
- typeRoots: [path_1.default.resolve(projectDir, "node_modules", "@types")],
111
+ typeRoots: [path.resolve(projectDir, "node_modules", "@types")],
125
112
  checkJs: true,
126
113
  allowJs: true,
114
+ skipLibCheck: true,
127
115
  noEmit: true,
128
116
  esModuleInterop: typeof compilerOptions.esModuleInterop !== "undefined" ? compilerOptions.esModuleInterop : true,
129
117
  moduleResolution: typeof compilerOptions.moduleResolution !== "undefined" ? compilerOptions.moduleResolution : "node",
130
118
  target: "esnext",
131
119
  module: "esnext",
132
120
  };
133
- const parsed = ts.parseJsonConfigFileContent(tsconfig.config, ts.sys, path_1.default.dirname(tsconfigPath));
121
+ const parsed = ts.parseJsonConfigFileContent(tsconfig.config, ts.sys, path.dirname(tsconfigPath));
134
122
  filenames = parsed.fileNames;
135
123
  compilerOptions = parsed.options;
136
124
  let program = ts.createProgram(filenames, compilerOptions);
@@ -0,0 +1,292 @@
1
+ import { ApiClient, ApiError } from "../../lib/api-client";
2
+ import { readDefaultWorkspace, resolveAuth } from "../../lib/auth-file";
3
+ import { buildBody } from "../../lib/body-builder";
4
+ import { consumeBodyFields } from "../../lib/body-fields";
5
+ import { print } from "../../lib/renderer";
6
+ async function resolveWorkspaceId(client, idOrSlug) {
7
+ try {
8
+ const ws = await client.request({
9
+ method: "GET",
10
+ path: `/api/workspace/${encodeURIComponent(idOrSlug)}`,
11
+ });
12
+ return ws.id;
13
+ }
14
+ catch (e) {
15
+ if (e instanceof ApiError && e.status === 404) {
16
+ throw new Error(`Workspace '${idOrSlug}' not found (or you don't have access)`);
17
+ }
18
+ throw e;
19
+ }
20
+ }
21
+ function gatherBody(opts) {
22
+ const fields = consumeBodyFields();
23
+ return buildBody({ file: opts.file, json: opts.json, fields });
24
+ }
25
+ function requireWorkspace(opts) {
26
+ if (opts.workspace)
27
+ return opts.workspace;
28
+ const fallback = readDefaultWorkspace();
29
+ if (fallback)
30
+ return fallback;
31
+ throw new Error("--workspace / -w is required (or set a default via `jitsu set-default-workspace <id-or-slug>`)");
32
+ }
33
+ async function requireResolvedWorkspaceId(opts, client) {
34
+ return resolveWorkspaceId(client, requireWorkspace(opts));
35
+ }
36
+ export async function runList(resource, opts) {
37
+ const auth = resolveAuth(opts);
38
+ const client = new ApiClient(auth);
39
+ switch (resource.kind) {
40
+ case "workspace": {
41
+ const data = await client.request({ method: "GET", path: "/api/workspace" });
42
+ print(data, opts.output);
43
+ return;
44
+ }
45
+ case "configObject": {
46
+ const ws = await requireResolvedWorkspaceId(opts, client);
47
+ const data = await client.request({
48
+ method: "GET",
49
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}`,
50
+ });
51
+ print(data.objects ?? data, opts.output);
52
+ return;
53
+ }
54
+ case "link": {
55
+ const ws = await requireResolvedWorkspaceId(opts, client);
56
+ const data = await client.request({
57
+ method: "GET",
58
+ path: `/api/${encodeURIComponent(ws)}/config/link`,
59
+ });
60
+ print(data.links ?? data, opts.output);
61
+ return;
62
+ }
63
+ case "profile-builder": {
64
+ const ws = await requireResolvedWorkspaceId(opts, client);
65
+ const data = await client.request({
66
+ method: "GET",
67
+ path: `/api/${encodeURIComponent(ws)}/config/profile-builder`,
68
+ });
69
+ print(data.profileBuilders ?? data, opts.output);
70
+ return;
71
+ }
72
+ }
73
+ }
74
+ export async function runGet(resource, id, opts) {
75
+ const auth = resolveAuth(opts);
76
+ const client = new ApiClient(auth);
77
+ switch (resource.kind) {
78
+ case "workspace": {
79
+ const data = await client.request({ method: "GET", path: `/api/workspace/${encodeURIComponent(id)}` });
80
+ print(data, opts.output);
81
+ return;
82
+ }
83
+ case "configObject": {
84
+ const ws = await requireResolvedWorkspaceId(opts, client);
85
+ const data = await client.request({
86
+ method: "GET",
87
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}/${encodeURIComponent(id)}`,
88
+ });
89
+ print(data, opts.output);
90
+ return;
91
+ }
92
+ default:
93
+ throw new Error(`get is not supported for ${resource.noun}`);
94
+ }
95
+ }
96
+ export async function runCreate(resource, opts) {
97
+ const auth = resolveAuth(opts);
98
+ const client = new ApiClient(auth);
99
+ const body = gatherBody(opts) ?? {};
100
+ switch (resource.kind) {
101
+ case "workspace": {
102
+ const data = await client.request({ method: "POST", path: "/api/workspace", body });
103
+ print(data, opts.output);
104
+ return;
105
+ }
106
+ case "configObject": {
107
+ const ws = await requireResolvedWorkspaceId(opts, client);
108
+ const data = await client.request({
109
+ method: "POST",
110
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}`,
111
+ body,
112
+ });
113
+ print(data, opts.output);
114
+ return;
115
+ }
116
+ case "link": {
117
+ const ws = await requireResolvedWorkspaceId(opts, client);
118
+ const data = await client.request({
119
+ method: "POST",
120
+ path: `/api/${encodeURIComponent(ws)}/config/link`,
121
+ body,
122
+ });
123
+ print(data, opts.output);
124
+ return;
125
+ }
126
+ case "profile-builder": {
127
+ const ws = await requireResolvedWorkspaceId(opts, client);
128
+ const data = await client.request({
129
+ method: "POST",
130
+ path: `/api/${encodeURIComponent(ws)}/config/profile-builder`,
131
+ body,
132
+ });
133
+ print(data, opts.output);
134
+ return;
135
+ }
136
+ }
137
+ }
138
+ export async function runUpdate(resource, id, opts) {
139
+ const auth = resolveAuth(opts);
140
+ const client = new ApiClient(auth);
141
+ const body = gatherBody(opts);
142
+ if (body === undefined) {
143
+ throw new Error("update requires at least one of -f, --json, or --field.path=value flags");
144
+ }
145
+ switch (resource.kind) {
146
+ case "workspace": {
147
+ if (!id)
148
+ throw new Error("workspace id or slug is required");
149
+ const data = await client.request({
150
+ method: "PUT",
151
+ path: `/api/workspace/${encodeURIComponent(id)}`,
152
+ body,
153
+ });
154
+ print(data, opts.output);
155
+ return;
156
+ }
157
+ case "configObject": {
158
+ const ws = await requireResolvedWorkspaceId(opts, client);
159
+ if (!id)
160
+ throw new Error("id is required");
161
+ const data = await client.request({
162
+ method: "PUT",
163
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}/${encodeURIComponent(id)}`,
164
+ body,
165
+ });
166
+ print(data ?? { ok: true }, opts.output);
167
+ return;
168
+ }
169
+ case "link": {
170
+ const ws = await requireResolvedWorkspaceId(opts, client);
171
+ const finalBody = mergePositionalId(body, id, "id");
172
+ const data = await client.request({
173
+ method: "PUT",
174
+ path: `/api/${encodeURIComponent(ws)}/config/link`,
175
+ body: finalBody,
176
+ });
177
+ print(data, opts.output);
178
+ return;
179
+ }
180
+ case "profile-builder": {
181
+ const ws = await requireResolvedWorkspaceId(opts, client);
182
+ if (!id)
183
+ throw new Error("id is required");
184
+ const finalBody = mergeNestedPositionalId(body, id, "profileBuilder", "id");
185
+ const data = await client.request({
186
+ method: "PUT",
187
+ path: `/api/${encodeURIComponent(ws)}/config/profile-builder`,
188
+ body: finalBody,
189
+ });
190
+ print(data, opts.output);
191
+ return;
192
+ }
193
+ }
194
+ }
195
+ function mergePositionalId(body, id, key) {
196
+ if (id === undefined)
197
+ return body;
198
+ if (body && typeof body === "object" && body[key] !== undefined && body[key] !== id) {
199
+ throw new Error(`positional id '${id}' conflicts with body.${key} '${body[key]}'`);
200
+ }
201
+ return { ...(body && typeof body === "object" ? body : {}), [key]: id };
202
+ }
203
+ function mergeNestedPositionalId(body, id, outer, inner) {
204
+ const base = body && typeof body === "object" ? body : {};
205
+ const nested = base[outer] && typeof base[outer] === "object" ? base[outer] : {};
206
+ if (nested[inner] !== undefined && nested[inner] !== id) {
207
+ throw new Error(`positional id '${id}' conflicts with body.${outer}.${inner} '${nested[inner]}'`);
208
+ }
209
+ return { ...base, [outer]: { ...nested, [inner]: id } };
210
+ }
211
+ export async function runDelete(resource, id, opts) {
212
+ const auth = resolveAuth(opts);
213
+ const client = new ApiClient(auth);
214
+ switch (resource.kind) {
215
+ case "workspace": {
216
+ if (!id)
217
+ throw new Error("workspace id is required");
218
+ const data = await client.request({
219
+ method: "DELETE",
220
+ path: "/api/workspace",
221
+ body: { workspaceId: id },
222
+ });
223
+ print(data, opts.output);
224
+ return;
225
+ }
226
+ case "configObject": {
227
+ const ws = await requireResolvedWorkspaceId(opts, client);
228
+ if (!id)
229
+ throw new Error("id is required");
230
+ const query = {};
231
+ if (opts.cascade)
232
+ query.cascade = "true";
233
+ if (opts.strict)
234
+ query.strict = "true";
235
+ const data = await client.request({
236
+ method: "DELETE",
237
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}/${encodeURIComponent(id)}`,
238
+ query,
239
+ });
240
+ print(data ?? { ok: true }, opts.output);
241
+ return;
242
+ }
243
+ case "link": {
244
+ const ws = await requireResolvedWorkspaceId(opts, client);
245
+ const query = {};
246
+ if (id) {
247
+ query.id = id;
248
+ }
249
+ else if (opts.from && opts.to) {
250
+ query.fromId = opts.from;
251
+ query.toId = opts.to;
252
+ }
253
+ else {
254
+ throw new Error("connection delete requires either <id> or both --from and --to");
255
+ }
256
+ const data = await client.request({
257
+ method: "DELETE",
258
+ path: `/api/${encodeURIComponent(ws)}/config/link`,
259
+ query,
260
+ });
261
+ print(data ?? { ok: true }, opts.output);
262
+ return;
263
+ }
264
+ case "profile-builder": {
265
+ const ws = await requireResolvedWorkspaceId(opts, client);
266
+ if (!id)
267
+ throw new Error("id is required");
268
+ const data = await client.request({
269
+ method: "DELETE",
270
+ path: `/api/${encodeURIComponent(ws)}/config/profile-builder`,
271
+ query: { id },
272
+ });
273
+ print(data ?? { ok: true }, opts.output);
274
+ return;
275
+ }
276
+ }
277
+ }
278
+ export async function runTest(resource, opts) {
279
+ if (resource.kind !== "configObject" || !resource.supportsTest) {
280
+ throw new Error(`test is not supported for ${resource.noun}`);
281
+ }
282
+ const auth = resolveAuth(opts);
283
+ const client = new ApiClient(auth);
284
+ const ws = await requireResolvedWorkspaceId(opts, client);
285
+ const body = gatherBody(opts) ?? {};
286
+ const data = await client.request({
287
+ method: "POST",
288
+ path: `/api/${encodeURIComponent(ws)}/config/${resource.type}/test`,
289
+ body,
290
+ });
291
+ print(data, opts.output);
292
+ }