@zuplo/cli 6.68.9 → 6.68.15

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 (34) hide show
  1. package/dist/__tests__/integration/link.integration.test.js +80 -5
  2. package/dist/__tests__/integration/link.integration.test.js.map +1 -1
  3. package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts +2 -0
  4. package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/integration/linked-config-cascade.integration.test.js +81 -0
  6. package/dist/__tests__/integration/linked-config-cascade.integration.test.js.map +1 -0
  7. package/dist/__tests__/populate.test.js +61 -18
  8. package/dist/__tests__/populate.test.js.map +1 -1
  9. package/dist/cmds/link.d.ts.map +1 -1
  10. package/dist/cmds/link.js +2 -0
  11. package/dist/cmds/link.js.map +1 -1
  12. package/dist/common/api/lib.d.ts +1 -1
  13. package/dist/common/api/lib.d.ts.map +1 -1
  14. package/dist/common/api/lib.js.map +1 -1
  15. package/dist/common/middleware/get-account-param.d.ts.map +1 -1
  16. package/dist/common/middleware/get-account-param.js +12 -0
  17. package/dist/common/middleware/get-account-param.js.map +1 -1
  18. package/dist/common/middleware/get-environment-param.d.ts.map +1 -1
  19. package/dist/common/middleware/get-environment-param.js +28 -1
  20. package/dist/common/middleware/get-environment-param.js.map +1 -1
  21. package/dist/common/middleware/get-project-param.d.ts.map +1 -1
  22. package/dist/common/middleware/get-project-param.js +12 -0
  23. package/dist/common/middleware/get-project-param.js.map +1 -1
  24. package/dist/common/populate.js.map +1 -1
  25. package/dist/common/read-linked-config.d.ts +13 -0
  26. package/dist/common/read-linked-config.d.ts.map +1 -0
  27. package/dist/common/read-linked-config.js +56 -0
  28. package/dist/common/read-linked-config.js.map +1 -0
  29. package/dist/common/read-linked-config.test.d.ts +2 -0
  30. package/dist/common/read-linked-config.test.d.ts.map +1 -0
  31. package/dist/common/read-linked-config.test.js +238 -0
  32. package/dist/common/read-linked-config.test.js.map +1 -0
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +4 -4
@@ -0,0 +1,56 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import readline from "node:readline";
4
+ import dotenv from "dotenv";
5
+ import { ZUPLO_SYSTEM_ENV_VAR } from "./constants.js";
6
+ import { logger } from "./logger.js";
7
+ const LINKED_CONFIG_CACHE_KEY = "linkedConfig";
8
+ export const USE_LINKED_DETAILS = "useLinkedDetails";
9
+ export async function readLinkedConfig(argv) {
10
+ if (argv[LINKED_CONFIG_CACHE_KEY] !== undefined) {
11
+ return argv[LINKED_CONFIG_CACHE_KEY];
12
+ }
13
+ const dir = argv.dir ?? ".";
14
+ const envFilePath = join(resolve(dir), ZUPLO_SYSTEM_ENV_VAR);
15
+ let config;
16
+ try {
17
+ const content = await readFile(envFilePath, "utf-8");
18
+ const parsed = dotenv.parse(content);
19
+ config = {
20
+ accountName: parsed["ZUPLO_ACCOUNT_NAME"] || undefined,
21
+ projectName: parsed["ZUPLO_PROJECT_NAME"] || undefined,
22
+ };
23
+ }
24
+ catch (error) {
25
+ if (error.code !== "ENOENT") {
26
+ logger.trace(error, "Failed to read linked config from .env.zuplo");
27
+ }
28
+ config = {};
29
+ }
30
+ argv[LINKED_CONFIG_CACHE_KEY] = config;
31
+ return config;
32
+ }
33
+ export function ignoreLinkedDetails(argv) {
34
+ argv[USE_LINKED_DETAILS] = false;
35
+ }
36
+ export async function confirmLinkedValue(message) {
37
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
38
+ return true;
39
+ }
40
+ return new Promise((resolve) => {
41
+ const rl = readline.createInterface({
42
+ input: process.stdin,
43
+ output: process.stdout,
44
+ });
45
+ rl.on("SIGINT", () => {
46
+ rl.close();
47
+ process.exit(0);
48
+ });
49
+ rl.question(`${message} [Y/n] `, (answer) => {
50
+ rl.close();
51
+ const normalized = answer.trim().toLowerCase();
52
+ resolve(normalized !== "n" && normalized !== "no");
53
+ });
54
+ });
55
+ }
56
+ //# sourceMappingURL=read-linked-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-linked-config.js","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOrC,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAOrD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAEtC;IACC,IAAI,IAAI,CAAC,uBAAuB,CAAC,KAAK,SAAS,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC,uBAAuB,CAAiB,CAAC;IACvD,CAAC;IACD,MAAM,GAAG,GAAI,IAAI,CAAC,GAA0B,IAAI,GAAG,CAAC;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAC7D,IAAI,MAAoB,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,GAAG;YACP,WAAW,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,SAAS;YACtD,WAAW,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,SAAS;SACvD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,8CAA8C,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IACD,IAAI,CAAC,uBAAuB,CAAC,GAAG,MAAM,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAMD,MAAM,UAAU,mBAAmB,CAAC,IAAgC;IAClE,IAAI,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC;AACnC,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAe;IACtD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACnB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,QAAQ,CAAC,GAAG,OAAO,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YAC1C,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC/C,OAAO,CAAC,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,IAAI,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport readline from \"node:readline\";\nimport dotenv from \"dotenv\";\nimport { ZUPLO_SYSTEM_ENV_VAR } from \"./constants.js\";\nimport { logger } from \"./logger.js\";\n\nexport interface LinkedConfig {\n accountName?: string;\n projectName?: string;\n}\n\nconst LINKED_CONFIG_CACHE_KEY = \"linkedConfig\";\nexport const USE_LINKED_DETAILS = \"useLinkedDetails\";\n\n/**\n * Reads the linked project configuration from `.env.zuplo` if it exists.\n * Caches the result on argv to avoid reading the file multiple times per command.\n * Returns an empty object if the file is missing or cannot be parsed.\n */\nexport async function readLinkedConfig(argv: {\n [key: string]: unknown;\n}): Promise<LinkedConfig> {\n if (argv[LINKED_CONFIG_CACHE_KEY] !== undefined) {\n return argv[LINKED_CONFIG_CACHE_KEY] as LinkedConfig;\n }\n const dir = (argv.dir as string | undefined) ?? \".\";\n const envFilePath = join(resolve(dir), ZUPLO_SYSTEM_ENV_VAR);\n let config: LinkedConfig;\n try {\n const content = await readFile(envFilePath, \"utf-8\");\n const parsed = dotenv.parse(content);\n config = {\n accountName: parsed[\"ZUPLO_ACCOUNT_NAME\"] || undefined,\n projectName: parsed[\"ZUPLO_PROJECT_NAME\"] || undefined,\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n logger.trace(error, \"Failed to read linked config from .env.zuplo\");\n }\n config = {};\n }\n argv[LINKED_CONFIG_CACHE_KEY] = config;\n return config;\n}\n\n/**\n * Middleware that prevents downstream middlewares from using linked config values.\n * Used by commands (e.g. link) that always re-prompt from scratch.\n */\nexport function ignoreLinkedDetails(argv: { [key: string]: unknown }): void {\n argv[USE_LINKED_DETAILS] = false;\n}\n\n/**\n * Prompts the user with a Y/n question using plain readline output.\n * Avoids @inquirer/prompts cursor management which conflicts with ora spinners.\n * Defaults to true (yes) in non-interactive terminals.\n */\nexport async function confirmLinkedValue(message: string): Promise<boolean> {\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n return true;\n }\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.on(\"SIGINT\", () => {\n rl.close();\n process.exit(0);\n });\n rl.question(`${message} [Y/n] `, (answer) => {\n rl.close();\n const normalized = answer.trim().toLowerCase();\n resolve(normalized !== \"n\" && normalized !== \"no\");\n });\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=read-linked-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-linked-config.test.d.ts","sourceRoot":"","sources":["../../src/common/read-linked-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,238 @@
1
+ import assert from "node:assert";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import readline from "node:readline";
6
+ import { afterEach, beforeEach, describe, it, mock } from "node:test";
7
+ import { confirmLinkedValue, readLinkedConfig, USE_LINKED_DETAILS, } from "./read-linked-config.js";
8
+ describe("readLinkedConfig", () => {
9
+ let testDir;
10
+ beforeEach(async () => {
11
+ testDir = await mkdtemp(join(tmpdir(), "zuplo-read-linked-config-test-"));
12
+ });
13
+ afterEach(async () => {
14
+ await rm(testDir, { recursive: true, force: true });
15
+ });
16
+ it("returns empty object when .env.zuplo does not exist", async () => {
17
+ const argv = { dir: testDir };
18
+ const result = await readLinkedConfig(argv);
19
+ assert.deepStrictEqual(result, {});
20
+ });
21
+ it("returns both fields when all are present", async () => {
22
+ await writeFile(join(testDir, ".env.zuplo"), ["ZUPLO_ACCOUNT_NAME=my-account", "ZUPLO_PROJECT_NAME=my-project"].join("\n"), "utf-8");
23
+ const argv = { dir: testDir };
24
+ const result = await readLinkedConfig(argv);
25
+ assert.deepStrictEqual(result, {
26
+ accountName: "my-account",
27
+ projectName: "my-project",
28
+ });
29
+ });
30
+ it("returns undefined for fields that are missing from the file", async () => {
31
+ await writeFile(join(testDir, ".env.zuplo"), "ZUPLO_ACCOUNT_NAME=my-account\n", "utf-8");
32
+ const argv = { dir: testDir };
33
+ const result = await readLinkedConfig(argv);
34
+ assert.strictEqual(result.accountName, "my-account");
35
+ assert.strictEqual(result.projectName, undefined);
36
+ });
37
+ it("returns undefined for fields set to empty string", async () => {
38
+ await writeFile(join(testDir, ".env.zuplo"), 'ZUPLO_ACCOUNT_NAME=\nZUPLO_PROJECT_NAME=""\n', "utf-8");
39
+ const argv = { dir: testDir };
40
+ const result = await readLinkedConfig(argv);
41
+ assert.strictEqual(result.accountName, undefined);
42
+ assert.strictEqual(result.projectName, undefined);
43
+ });
44
+ it("caches the result on argv so the file is only read once", async () => {
45
+ await writeFile(join(testDir, ".env.zuplo"), "ZUPLO_ACCOUNT_NAME=my-account\n", "utf-8");
46
+ const argv = { dir: testDir };
47
+ const first = await readLinkedConfig(argv);
48
+ await rm(join(testDir, ".env.zuplo"));
49
+ const second = await readLinkedConfig(argv);
50
+ assert.strictEqual(first, second);
51
+ assert.strictEqual(second.accountName, "my-account");
52
+ });
53
+ it("returns empty object and does not throw on a malformed file", async () => {
54
+ await writeFile(join(testDir, ".env.zuplo"), "THIS IS NOT VALID\x00ENV\n", "utf-8");
55
+ const argv = { dir: testDir };
56
+ const result = await readLinkedConfig(argv);
57
+ assert.ok(typeof result === "object");
58
+ });
59
+ it("defaults dir to '.' when argv.dir is not set", async () => {
60
+ const argv = { dir: testDir };
61
+ const result = await readLinkedConfig(argv);
62
+ assert.deepStrictEqual(result, {});
63
+ });
64
+ });
65
+ describe("confirmLinkedValue", () => {
66
+ let originalStdinIsTTY;
67
+ let originalStdoutIsTTY;
68
+ beforeEach(() => {
69
+ originalStdinIsTTY = Object.getOwnPropertyDescriptor(process.stdin, "isTTY");
70
+ originalStdoutIsTTY = Object.getOwnPropertyDescriptor(process.stdout, "isTTY");
71
+ });
72
+ afterEach(() => {
73
+ mock.restoreAll();
74
+ if (originalStdinIsTTY) {
75
+ Object.defineProperty(process.stdin, "isTTY", originalStdinIsTTY);
76
+ }
77
+ else {
78
+ delete process.stdin.isTTY;
79
+ }
80
+ if (originalStdoutIsTTY) {
81
+ Object.defineProperty(process.stdout, "isTTY", originalStdoutIsTTY);
82
+ }
83
+ else {
84
+ delete process.stdout.isTTY;
85
+ }
86
+ });
87
+ it("returns true immediately when stdin is not a TTY (non-interactive)", async () => {
88
+ const createInterfaceSpy = mock.method(readline, "createInterface");
89
+ Object.defineProperty(process.stdin, "isTTY", {
90
+ value: false,
91
+ configurable: true,
92
+ });
93
+ const result = await confirmLinkedValue("Use linked account 'foo'?");
94
+ assert.strictEqual(result, true);
95
+ assert.strictEqual(createInterfaceSpy.mock.calls.length, 0);
96
+ });
97
+ it("returns true when user enters 'y'", async () => {
98
+ Object.defineProperty(process.stdin, "isTTY", {
99
+ value: true,
100
+ configurable: true,
101
+ });
102
+ Object.defineProperty(process.stdout, "isTTY", {
103
+ value: true,
104
+ configurable: true,
105
+ });
106
+ stubReadlineAnswer("y");
107
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), true);
108
+ });
109
+ it("returns true when user enters 'Y' (case-insensitive)", async () => {
110
+ Object.defineProperty(process.stdin, "isTTY", {
111
+ value: true,
112
+ configurable: true,
113
+ });
114
+ Object.defineProperty(process.stdout, "isTTY", {
115
+ value: true,
116
+ configurable: true,
117
+ });
118
+ stubReadlineAnswer("Y");
119
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), true);
120
+ });
121
+ it("returns true when user presses Enter (empty input — default yes)", async () => {
122
+ Object.defineProperty(process.stdin, "isTTY", {
123
+ value: true,
124
+ configurable: true,
125
+ });
126
+ Object.defineProperty(process.stdout, "isTTY", {
127
+ value: true,
128
+ configurable: true,
129
+ });
130
+ stubReadlineAnswer("");
131
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), true);
132
+ });
133
+ it("returns false when user enters 'n'", async () => {
134
+ Object.defineProperty(process.stdin, "isTTY", {
135
+ value: true,
136
+ configurable: true,
137
+ });
138
+ Object.defineProperty(process.stdout, "isTTY", {
139
+ value: true,
140
+ configurable: true,
141
+ });
142
+ stubReadlineAnswer("n");
143
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), false);
144
+ });
145
+ it("returns false when user enters 'N' (case-insensitive)", async () => {
146
+ Object.defineProperty(process.stdin, "isTTY", {
147
+ value: true,
148
+ configurable: true,
149
+ });
150
+ Object.defineProperty(process.stdout, "isTTY", {
151
+ value: true,
152
+ configurable: true,
153
+ });
154
+ stubReadlineAnswer("N");
155
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), false);
156
+ });
157
+ it("returns false when user enters 'no'", async () => {
158
+ Object.defineProperty(process.stdin, "isTTY", {
159
+ value: true,
160
+ configurable: true,
161
+ });
162
+ Object.defineProperty(process.stdout, "isTTY", {
163
+ value: true,
164
+ configurable: true,
165
+ });
166
+ stubReadlineAnswer("no");
167
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), false);
168
+ });
169
+ it("returns false when user enters 'NO' (case-insensitive)", async () => {
170
+ Object.defineProperty(process.stdin, "isTTY", {
171
+ value: true,
172
+ configurable: true,
173
+ });
174
+ Object.defineProperty(process.stdout, "isTTY", {
175
+ value: true,
176
+ configurable: true,
177
+ });
178
+ stubReadlineAnswer("NO");
179
+ assert.strictEqual(await confirmLinkedValue("Use linked account 'foo'?"), false);
180
+ });
181
+ it("exits the process when SIGINT is emitted on the readline interface", () => {
182
+ Object.defineProperty(process.stdin, "isTTY", {
183
+ value: true,
184
+ configurable: true,
185
+ });
186
+ Object.defineProperty(process.stdout, "isTTY", {
187
+ value: true,
188
+ configurable: true,
189
+ });
190
+ const exitStub = mock.method(process, "exit", () => {
191
+ throw new Error("process.exit called");
192
+ });
193
+ let sigintEmitter;
194
+ mock.method(readline, "createInterface", () => ({
195
+ on: (event, handler) => {
196
+ if (event === "SIGINT")
197
+ sigintEmitter = handler;
198
+ },
199
+ question: () => {
200
+ },
201
+ close: mock.fn(),
202
+ }));
203
+ void confirmLinkedValue("Use linked account 'foo'?");
204
+ assert.throws(() => sigintEmitter(), /process\.exit called/);
205
+ assert.strictEqual(exitStub.mock.calls[0].arguments[0], 0);
206
+ });
207
+ });
208
+ describe("USE_LINKED_DETAILS", () => {
209
+ let testDir;
210
+ beforeEach(async () => {
211
+ testDir = await mkdtemp(join(tmpdir(), "zuplo-use-linked-details-test-"));
212
+ });
213
+ afterEach(async () => {
214
+ await rm(testDir, { recursive: true, force: true });
215
+ });
216
+ it("is exported and has the expected value", () => {
217
+ assert.strictEqual(USE_LINKED_DETAILS, "useLinkedDetails");
218
+ });
219
+ it("setting it to false on argv does not collide with the internal cache key", async () => {
220
+ const argv = {
221
+ dir: testDir,
222
+ [USE_LINKED_DETAILS]: false,
223
+ };
224
+ const result = await readLinkedConfig(argv);
225
+ assert.deepStrictEqual(result, {});
226
+ });
227
+ });
228
+ function stubReadlineAnswer(answer) {
229
+ mock.method(readline, "createInterface", () => ({
230
+ on: () => {
231
+ },
232
+ question: (_prompt, callback) => {
233
+ callback(answer);
234
+ },
235
+ close: mock.fn(),
236
+ }));
237
+ }
238
+ //# sourceMappingURL=read-linked-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-linked-config.test.js","sourceRoot":"","sources":["../../src/common/read-linked-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert\";\nimport { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport readline from \"node:readline\";\nimport { afterEach, beforeEach, describe, it, mock } from \"node:test\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n USE_LINKED_DETAILS,\n} from \"./read-linked-config.js\";\n\ndescribe(\"readLinkedConfig\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-read-linked-config-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"returns empty object when .env.zuplo does not exist\", async () => {\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n\n it(\"returns both fields when all are present\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n [\"ZUPLO_ACCOUNT_NAME=my-account\", \"ZUPLO_PROJECT_NAME=my-project\"].join(\n \"\\n\"\n ),\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {\n accountName: \"my-account\",\n projectName: \"my-project\",\n });\n });\n\n it(\"returns undefined for fields that are missing from the file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, \"my-account\");\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"returns undefined for fields set to empty string\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n 'ZUPLO_ACCOUNT_NAME=\\nZUPLO_PROJECT_NAME=\"\"\\n',\n \"utf-8\"\n );\n const argv = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.strictEqual(result.accountName, undefined);\n assert.strictEqual(result.projectName, undefined);\n });\n\n it(\"caches the result on argv so the file is only read once\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"ZUPLO_ACCOUNT_NAME=my-account\\n\",\n \"utf-8\"\n );\n const argv: { [key: string]: unknown } = { dir: testDir };\n\n const first = await readLinkedConfig(argv);\n // Delete the file — a second call must return the cached value, not throw\n await rm(join(testDir, \".env.zuplo\"));\n const second = await readLinkedConfig(argv);\n\n assert.strictEqual(first, second); // same object reference\n assert.strictEqual(second.accountName, \"my-account\");\n });\n\n it(\"returns empty object and does not throw on a malformed file\", async () => {\n await writeFile(\n join(testDir, \".env.zuplo\"),\n \"THIS IS NOT VALID\\x00ENV\\n\",\n \"utf-8\"\n );\n const argv = { dir: testDir };\n // dotenv silently skips lines it cannot parse, so no throw is expected\n const result = await readLinkedConfig(argv);\n assert.ok(typeof result === \"object\");\n });\n\n it(\"defaults dir to '.' when argv.dir is not set\", async () => {\n // Use testDir so the test is not sensitive to whether .env.zuplo exists in the process CWD\n const argv: { [key: string]: unknown } = { dir: testDir };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\ndescribe(\"confirmLinkedValue\", () => {\n let originalStdinIsTTY: PropertyDescriptor | undefined;\n let originalStdoutIsTTY: PropertyDescriptor | undefined;\n\n beforeEach(() => {\n originalStdinIsTTY = Object.getOwnPropertyDescriptor(\n process.stdin,\n \"isTTY\"\n );\n originalStdoutIsTTY = Object.getOwnPropertyDescriptor(\n process.stdout,\n \"isTTY\"\n );\n });\n\n afterEach(() => {\n mock.restoreAll();\n if (originalStdinIsTTY) {\n Object.defineProperty(process.stdin, \"isTTY\", originalStdinIsTTY);\n } else {\n delete (process.stdin as { isTTY?: boolean }).isTTY;\n }\n if (originalStdoutIsTTY) {\n Object.defineProperty(process.stdout, \"isTTY\", originalStdoutIsTTY);\n } else {\n delete (process.stdout as { isTTY?: boolean }).isTTY;\n }\n });\n\n it(\"returns true immediately when stdin is not a TTY (non-interactive)\", async () => {\n // Stub createInterface to ensure readline is never touched\n const createInterfaceSpy = mock.method(readline, \"createInterface\");\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: false,\n configurable: true,\n });\n\n const result = await confirmLinkedValue(\"Use linked account 'foo'?\");\n\n assert.strictEqual(result, true);\n assert.strictEqual(createInterfaceSpy.mock.calls.length, 0);\n });\n\n it(\"returns true when user enters 'y'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user enters 'Y' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"Y\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns true when user presses Enter (empty input — default yes)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n true\n );\n });\n\n it(\"returns false when user enters 'n'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"n\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'N' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"N\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'no'\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"no\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"returns false when user enters 'NO' (case-insensitive)\", async () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n stubReadlineAnswer(\"NO\");\n assert.strictEqual(\n await confirmLinkedValue(\"Use linked account 'foo'?\"),\n false\n );\n });\n\n it(\"exits the process when SIGINT is emitted on the readline interface\", () => {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: true,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: true,\n configurable: true,\n });\n\n const exitStub = mock.method(process, \"exit\", () => {\n throw new Error(\"process.exit called\");\n });\n\n let sigintEmitter: (() => void) | undefined;\n mock.method(readline, \"createInterface\", () => ({\n on: (event: string, handler: () => void) => {\n if (event === \"SIGINT\") sigintEmitter = handler;\n },\n question: () => {\n /* never resolves */\n },\n close: mock.fn(),\n }));\n\n // Start the prompt — it won't resolve (question callback never fires)\n void confirmLinkedValue(\"Use linked account 'foo'?\");\n\n // Emitting SIGINT calls process.exit(0) synchronously; our mock throws to intercept it\n assert.throws(() => sigintEmitter!(), /process\\.exit called/);\n assert.strictEqual(exitStub.mock.calls[0].arguments[0], 0);\n });\n});\n\ndescribe(\"USE_LINKED_DETAILS\", () => {\n let testDir: string;\n\n beforeEach(async () => {\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-use-linked-details-test-\"));\n });\n\n afterEach(async () => {\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"is exported and has the expected value\", () => {\n assert.strictEqual(USE_LINKED_DETAILS, \"useLinkedDetails\");\n });\n\n it(\"setting it to false on argv does not collide with the internal cache key\", async () => {\n // The useLinkedDetails key must not collide with the internal cache key so that\n // readLinkedConfig continues to work even when useLinkedDetails is false.\n const argv: { [key: string]: unknown } = {\n dir: testDir,\n [USE_LINKED_DETAILS]: false,\n };\n const result = await readLinkedConfig(argv);\n assert.deepStrictEqual(result, {});\n });\n});\n\n/**\n * Helper: stub readline.createInterface so that the `question` callback is\n * called synchronously with `answer`, simulating user input.\n */\nfunction stubReadlineAnswer(answer: string) {\n mock.method(readline, \"createInterface\", () => ({\n on: () => {\n /* ignore SIGINT in these tests */\n },\n question: (_prompt: string, callback: (a: string) => void) => {\n callback(answer);\n },\n close: mock.fn(),\n }));\n}\n"]}
@@ -1 +1 @@
1
- {"root":["../src/cli.ts","../src/internal.ts","../src/types.d.ts","../src/__tests__/archive-utils.test.ts","../src/__tests__/import-openapi.test.ts","../src/__tests__/outdated.test.ts","../src/__tests__/populate.test.ts","../src/__tests__/tsconfig-upgrader.test.ts","../src/__tests__/integration/custom-domain.integration.test.ts","../src/__tests__/integration/delete.integration.test.ts","../src/__tests__/integration/deploy.integration.test.ts","../src/__tests__/integration/jest-mocks-setup.ts","../src/__tests__/integration/jest-setup.ts","../src/__tests__/integration/link.integration.test.ts","../src/__tests__/integration/list.integration.test.ts","../src/__tests__/integration/test-utils.ts","../src/__tests__/integration/tunnel.integration.test.ts","../src/__tests__/integration/variable.integration.test.ts","../src/build/handler.ts","../src/cmds/build.ts","../src/cmds/compile.ts","../src/cmds/delete.ts","../src/cmds/deploy.ts","../src/cmds/dev.ts","../src/cmds/docs.ts","../src/cmds/editor.ts","../src/cmds/init.ts","../src/cmds/link.ts","../src/cmds/list.ts","../src/cmds/login.ts","../src/cmds/test.ts","../src/cmds/custom-domain/create.ts","../src/cmds/custom-domain/delete.ts","../src/cmds/custom-domain/index.ts","../src/cmds/custom-domain/list.ts","../src/cmds/custom-domain/update.ts","../src/cmds/mtls-certificates/create.ts","../src/cmds/mtls-certificates/delete.ts","../src/cmds/mtls-certificates/describe.ts","../src/cmds/mtls-certificates/disable.ts","../src/cmds/mtls-certificates/index.ts","../src/cmds/mtls-certificates/list.ts","../src/cmds/mtls-certificates/update.ts","../src/cmds/open-api/convert.ts","../src/cmds/open-api/index.ts","../src/cmds/open-api/merge.ts","../src/cmds/open-api/overlay.ts","../src/cmds/project/create.ts","../src/cmds/project/index.ts","../src/cmds/proxies/create.ts","../src/cmds/proxies/delete.ts","../src/cmds/proxies/describe.ts","../src/cmds/proxies/index.ts","../src/cmds/proxies/update.ts","../src/cmds/source/import-openapi.ts","../src/cmds/source/index.ts","../src/cmds/source/migrate.ts","../src/cmds/source/upgrade.ts","../src/cmds/tunnel/create.ts","../src/cmds/tunnel/delete.ts","../src/cmds/tunnel/describe.ts","../src/cmds/tunnel/index.ts","../src/cmds/tunnel/list.ts","../src/cmds/tunnel/rotate-token.ts","../src/cmds/tunnel/services/describe.ts","../src/cmds/tunnel/services/index.ts","../src/cmds/tunnel/services/update.ts","../src/cmds/variable/create.ts","../src/cmds/variable/index.ts","../src/cmds/variable/update.ts","../src/common/alias.ts","../src/common/args.ts","../src/common/constants.ts","../src/common/handler.ts","../src/common/logger.ts","../src/common/models.ts","../src/common/outdated.ts","../src/common/output.ts","../src/common/populate.ts","../src/common/runner.ts","../src/common/settings.ts","../src/common/worker-output.ts","../src/common/analytics/lib.ts","../src/common/api/lib.ts","../src/common/machine-id/lib.ts","../src/common/middleware/authentication.ts","../src/common/middleware/get-account-param.ts","../src/common/middleware/get-environment-param.ts","../src/common/middleware/get-project-param.ts","../src/common/middleware/logging.ts","../src/common/middleware/user-configuration.ts","../src/common/middleware/user-identification.ts","../src/common/middleware/validate-fleet.ts","../src/common/upgraders/lib.ts","../src/common/upgraders/package-json-upgrader.ts","../src/common/upgraders/tsconfig-upgrader.ts","../src/common/upgraders/vscode-settings-json-upgrader.ts","../src/common/utils/box.ts","../src/common/utils/branch.ts","../src/common/utils/ports.ts","../src/common/utils/prefixed-output.ts","../src/common/utils/pretty-print-environment-prompt.ts","../src/common/utils/stringify-config.test.ts","../src/common/utils/stringify-config.ts","../src/common/utils/types.ts","../src/common/utils/urls.ts","../src/common/validators/argument-validators.spec.ts","../src/common/validators/argument-validators.ts","../src/common/validators/file-system-validator.ts","../src/common/validators/lib.ts","../src/common/validators/project-name-validator.ts","../src/common/xdg/lib.ts","../src/compile/handler.ts","../src/custom-domain/models.ts","../src/custom-domain/create/handler.ts","../src/custom-domain/delete/handler.ts","../src/custom-domain/list/handler.ts","../src/custom-domain/update/handler.ts","../src/delete/handler.ts","../src/delete/poll-deployment.ts","../src/deploy/archive.test.ts","../src/deploy/archive.ts","../src/deploy/environments.ts","../src/deploy/file-upload.ts","../src/deploy/handler.ts","../src/deploy/poll-deployment.ts","../src/dev/handler.ts","../src/docs/handler.ts","../src/editor/handler.ts","../src/editor/e2e/editor.spec.ts","../src/init/handler.ts","../src/link/handler.ts","../src/list/handler.ts","../src/login/login.ts","../src/login/tokens.ts","../src/mtls-certificates/models.ts","../src/mtls-certificates/create/handler.ts","../src/mtls-certificates/delete/handler.ts","../src/mtls-certificates/describe/handler.ts","../src/mtls-certificates/disable/handler.ts","../src/mtls-certificates/list/handler.ts","../src/mtls-certificates/update/handler.ts","../src/open-api/convert/handler.spec.ts","../src/open-api/convert/handler.ts","../src/open-api/merge/handler.spec.ts","../src/open-api/merge/handler.ts","../src/open-api/overlay/handler.spec.ts","../src/open-api/overlay/handler.ts","../src/project/create/handler.ts","../src/proxies/models.ts","../src/proxies/create/handler.ts","../src/proxies/delete/handler.ts","../src/proxies/describe/handler.ts","../src/proxies/update/handler.ts","../src/source/migrate/dev-portal/handler.ts","../src/source/migrate/dev-portal/types.ts","../src/source/update/handler.ts","../src/test/esbuild-config.ts","../src/test/handler.ts","../src/test/invoke-test.ts","../src/test/test-files.test.ts","../src/test/test-files.ts","../src/test/esbuild-plugins/node-test-prep-plugin.ts","../src/tunnel/models.ts","../src/tunnel/create/handler.ts","../src/tunnel/delete/handler.ts","../src/tunnel/delete/poll-teardown-operation.ts","../src/tunnel/describe/handler.ts","../src/tunnel/list/handler.ts","../src/tunnel/rotate-token/handler.ts","../src/tunnel/services/describe/handler.ts","../src/tunnel/services/update/handler.ts","../src/tunnel/services/update/poll-provisioning-operations.ts","../src/variable/models.ts","../src/variable/create/handler.ts","../src/variable/update/handler.ts"],"version":"5.8.2"}
1
+ {"root":["../src/cli.ts","../src/internal.ts","../src/types.d.ts","../src/__tests__/archive-utils.test.ts","../src/__tests__/import-openapi.test.ts","../src/__tests__/outdated.test.ts","../src/__tests__/populate.test.ts","../src/__tests__/tsconfig-upgrader.test.ts","../src/__tests__/integration/custom-domain.integration.test.ts","../src/__tests__/integration/delete.integration.test.ts","../src/__tests__/integration/deploy.integration.test.ts","../src/__tests__/integration/jest-mocks-setup.ts","../src/__tests__/integration/jest-setup.ts","../src/__tests__/integration/link.integration.test.ts","../src/__tests__/integration/linked-config-cascade.integration.test.ts","../src/__tests__/integration/list.integration.test.ts","../src/__tests__/integration/test-utils.ts","../src/__tests__/integration/tunnel.integration.test.ts","../src/__tests__/integration/variable.integration.test.ts","../src/build/handler.ts","../src/cmds/build.ts","../src/cmds/compile.ts","../src/cmds/delete.ts","../src/cmds/deploy.ts","../src/cmds/dev.ts","../src/cmds/docs.ts","../src/cmds/editor.ts","../src/cmds/init.ts","../src/cmds/link.ts","../src/cmds/list.ts","../src/cmds/login.ts","../src/cmds/test.ts","../src/cmds/custom-domain/create.ts","../src/cmds/custom-domain/delete.ts","../src/cmds/custom-domain/index.ts","../src/cmds/custom-domain/list.ts","../src/cmds/custom-domain/update.ts","../src/cmds/mtls-certificates/create.ts","../src/cmds/mtls-certificates/delete.ts","../src/cmds/mtls-certificates/describe.ts","../src/cmds/mtls-certificates/disable.ts","../src/cmds/mtls-certificates/index.ts","../src/cmds/mtls-certificates/list.ts","../src/cmds/mtls-certificates/update.ts","../src/cmds/open-api/convert.ts","../src/cmds/open-api/index.ts","../src/cmds/open-api/merge.ts","../src/cmds/open-api/overlay.ts","../src/cmds/project/create.ts","../src/cmds/project/index.ts","../src/cmds/proxies/create.ts","../src/cmds/proxies/delete.ts","../src/cmds/proxies/describe.ts","../src/cmds/proxies/index.ts","../src/cmds/proxies/update.ts","../src/cmds/source/import-openapi.ts","../src/cmds/source/index.ts","../src/cmds/source/migrate.ts","../src/cmds/source/upgrade.ts","../src/cmds/tunnel/create.ts","../src/cmds/tunnel/delete.ts","../src/cmds/tunnel/describe.ts","../src/cmds/tunnel/index.ts","../src/cmds/tunnel/list.ts","../src/cmds/tunnel/rotate-token.ts","../src/cmds/tunnel/services/describe.ts","../src/cmds/tunnel/services/index.ts","../src/cmds/tunnel/services/update.ts","../src/cmds/variable/create.ts","../src/cmds/variable/index.ts","../src/cmds/variable/update.ts","../src/common/alias.ts","../src/common/args.ts","../src/common/constants.ts","../src/common/handler.ts","../src/common/logger.ts","../src/common/models.ts","../src/common/outdated.ts","../src/common/output.ts","../src/common/populate.ts","../src/common/read-linked-config.test.ts","../src/common/read-linked-config.ts","../src/common/runner.ts","../src/common/settings.ts","../src/common/worker-output.ts","../src/common/analytics/lib.ts","../src/common/api/lib.ts","../src/common/machine-id/lib.ts","../src/common/middleware/authentication.ts","../src/common/middleware/get-account-param.ts","../src/common/middleware/get-environment-param.ts","../src/common/middleware/get-project-param.ts","../src/common/middleware/logging.ts","../src/common/middleware/user-configuration.ts","../src/common/middleware/user-identification.ts","../src/common/middleware/validate-fleet.ts","../src/common/upgraders/lib.ts","../src/common/upgraders/package-json-upgrader.ts","../src/common/upgraders/tsconfig-upgrader.ts","../src/common/upgraders/vscode-settings-json-upgrader.ts","../src/common/utils/box.ts","../src/common/utils/branch.ts","../src/common/utils/ports.ts","../src/common/utils/prefixed-output.ts","../src/common/utils/pretty-print-environment-prompt.ts","../src/common/utils/stringify-config.test.ts","../src/common/utils/stringify-config.ts","../src/common/utils/types.ts","../src/common/utils/urls.ts","../src/common/validators/argument-validators.spec.ts","../src/common/validators/argument-validators.ts","../src/common/validators/file-system-validator.ts","../src/common/validators/lib.ts","../src/common/validators/project-name-validator.ts","../src/common/xdg/lib.ts","../src/compile/handler.ts","../src/custom-domain/models.ts","../src/custom-domain/create/handler.ts","../src/custom-domain/delete/handler.ts","../src/custom-domain/list/handler.ts","../src/custom-domain/update/handler.ts","../src/delete/handler.ts","../src/delete/poll-deployment.ts","../src/deploy/archive.test.ts","../src/deploy/archive.ts","../src/deploy/environments.ts","../src/deploy/file-upload.ts","../src/deploy/handler.ts","../src/deploy/poll-deployment.ts","../src/dev/handler.ts","../src/docs/handler.ts","../src/editor/handler.ts","../src/editor/e2e/editor.spec.ts","../src/init/handler.ts","../src/link/handler.ts","../src/list/handler.ts","../src/login/login.ts","../src/login/tokens.ts","../src/mtls-certificates/models.ts","../src/mtls-certificates/create/handler.ts","../src/mtls-certificates/delete/handler.ts","../src/mtls-certificates/describe/handler.ts","../src/mtls-certificates/disable/handler.ts","../src/mtls-certificates/list/handler.ts","../src/mtls-certificates/update/handler.ts","../src/open-api/convert/handler.spec.ts","../src/open-api/convert/handler.ts","../src/open-api/merge/handler.spec.ts","../src/open-api/merge/handler.ts","../src/open-api/overlay/handler.spec.ts","../src/open-api/overlay/handler.ts","../src/project/create/handler.ts","../src/proxies/models.ts","../src/proxies/create/handler.ts","../src/proxies/delete/handler.ts","../src/proxies/describe/handler.ts","../src/proxies/update/handler.ts","../src/source/migrate/dev-portal/handler.ts","../src/source/migrate/dev-portal/types.ts","../src/source/update/handler.ts","../src/test/esbuild-config.ts","../src/test/handler.ts","../src/test/invoke-test.ts","../src/test/test-files.test.ts","../src/test/test-files.ts","../src/test/esbuild-plugins/node-test-prep-plugin.ts","../src/tunnel/models.ts","../src/tunnel/create/handler.ts","../src/tunnel/delete/handler.ts","../src/tunnel/delete/poll-teardown-operation.ts","../src/tunnel/describe/handler.ts","../src/tunnel/list/handler.ts","../src/tunnel/rotate-token/handler.ts","../src/tunnel/services/describe/handler.ts","../src/tunnel/services/update/handler.ts","../src/tunnel/services/update/poll-provisioning-operations.ts","../src/variable/models.ts","../src/variable/create/handler.ts","../src/variable/update/handler.ts"],"version":"5.8.2"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuplo/cli",
3
- "version": "6.68.9",
3
+ "version": "6.68.15",
4
4
  "repository": "https://github.com/zuplo/zuplo",
5
5
  "author": "Zuplo, Inc.",
6
6
  "type": "module",
@@ -29,10 +29,10 @@
29
29
  "@opentelemetry/api": "1.9.0",
30
30
  "@sentry/node": "9.22.0",
31
31
  "@swc/core": "1.10.18",
32
- "@zuplo/core": "6.68.9",
32
+ "@zuplo/core": "6.68.15",
33
33
  "@zuplo/editor": "1.0.20821740935",
34
- "@zuplo/openapi-tools": "6.68.9",
35
- "@zuplo/runtime": "6.68.9",
34
+ "@zuplo/openapi-tools": "6.68.15",
35
+ "@zuplo/runtime": "6.68.15",
36
36
  "as-table": "1.0.55",
37
37
  "chalk": "5.4.1",
38
38
  "chokidar": "3.5.3",