@zuplo/cli 6.68.25 → 6.68.26
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/dist/__tests__/integration/link.integration.test.js +6 -0
- package/dist/__tests__/integration/link.integration.test.js.map +1 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js +62 -0
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js.map +1 -1
- package/dist/common/middleware/authentication.d.ts.map +1 -1
- package/dist/common/middleware/authentication.js +2 -4
- package/dist/common/middleware/authentication.js.map +1 -1
- package/dist/common/middleware/get-account-param.d.ts.map +1 -1
- package/dist/common/middleware/get-account-param.js +10 -1
- package/dist/common/middleware/get-account-param.js.map +1 -1
- package/dist/common/middleware/get-environment-param.d.ts.map +1 -1
- package/dist/common/middleware/get-environment-param.js +7 -2
- package/dist/common/middleware/get-environment-param.js.map +1 -1
- package/dist/common/middleware/get-project-param.d.ts.map +1 -1
- package/dist/common/middleware/get-project-param.js +10 -1
- package/dist/common/middleware/get-project-param.js.map +1 -1
- package/dist/common/read-linked-config.d.ts.map +1 -1
- package/dist/common/read-linked-config.js +3 -2
- package/dist/common/read-linked-config.js.map +1 -1
- package/dist/common/read-linked-config.test.js +17 -4
- package/dist/common/read-linked-config.test.js.map +1 -1
- package/dist/common/terminal.d.ts +2 -0
- package/dist/common/terminal.d.ts.map +1 -0
- package/dist/common/terminal.js +6 -0
- package/dist/common/terminal.js.map +1 -0
- package/dist/common/terminal.test.d.ts +2 -0
- package/dist/common/terminal.test.d.ts.map +1 -0
- package/dist/common/terminal.test.js +101 -0
- package/dist/common/terminal.test.js.map +1 -0
- package/dist/init/handler.d.ts.map +1 -1
- package/dist/init/handler.js +3 -5
- package/dist/init/handler.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -5,6 +5,7 @@ import { logger } from "../logger.js";
|
|
|
5
5
|
import { printCriticalFailureToConsoleAndExit, textOrJson } from "../output.js";
|
|
6
6
|
import { confirmLinkedValue, readLinkedConfig, USE_LINKED_DETAILS, } from "../read-linked-config.js";
|
|
7
7
|
import settings from "../settings.js";
|
|
8
|
+
import { isInteractiveTerminal } from "../terminal.js";
|
|
8
9
|
export async function fetchProject(argv) {
|
|
9
10
|
if (argv.project && typeof argv.project === "string") {
|
|
10
11
|
return;
|
|
@@ -15,6 +16,10 @@ export async function fetchProject(argv) {
|
|
|
15
16
|
if (argv[USE_LINKED_DETAILS] !== false) {
|
|
16
17
|
const linked = await readLinkedConfig(argv);
|
|
17
18
|
if (linked.projectName && linked.accountName === argv.account) {
|
|
19
|
+
if (!isInteractiveTerminal()) {
|
|
20
|
+
argv.project = linked.projectName;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
18
23
|
const useLinked = await confirmLinkedValue(`Use linked project '${linked.projectName}'?`);
|
|
19
24
|
if (useLinked) {
|
|
20
25
|
argv.project = linked.projectName;
|
|
@@ -23,6 +28,10 @@ export async function fetchProject(argv) {
|
|
|
23
28
|
argv[USE_LINKED_DETAILS] = false;
|
|
24
29
|
}
|
|
25
30
|
}
|
|
31
|
+
if (!isInteractiveTerminal()) {
|
|
32
|
+
await printCriticalFailureToConsoleAndExit("Error: --project is required in non-interactive environments (e.g. CI/CD).\nSee your available projects at https://portal.zuplo.com, then re-run with --project <name>.");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
26
35
|
const baseUrl = `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/projects`;
|
|
27
36
|
const queryParams = {
|
|
28
37
|
accountName: argv.account,
|
|
@@ -74,7 +83,7 @@ export async function fetchProject(argv) {
|
|
|
74
83
|
}
|
|
75
84
|
catch (error) {
|
|
76
85
|
if (error.isTtyError || error.name === "ExitPromptError") {
|
|
77
|
-
process.exit(
|
|
86
|
+
process.exit(1);
|
|
78
87
|
}
|
|
79
88
|
logger.trace("Failed to select project", error);
|
|
80
89
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-project-param.js","sourceRoot":"","sources":["../../../src/common/middleware/get-project-param.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,oCAAoC,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"get-project-param.js","sourceRoot":"","sources":["../../../src/common/middleware/get-project-param.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { input, select } from \"@inquirer/prompts\";\nimport { createProject } from \"../../project/create/handler.js\";\nimport { logger } from \"../logger.js\";\nimport { printCriticalFailureToConsoleAndExit, textOrJson } from \"../output.js\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n USE_LINKED_DETAILS,\n} from \"../read-linked-config.js\";\nimport settings from \"../settings.js\";\nimport { isInteractiveTerminal } from \"../terminal.js\";\n\n/**\n * Middleware that ensures a project is provided in argv. If not, prompts the user.\n * Note: must be called after get account param.\n */\nexport async function fetchProject(argv: { [key: string]: unknown }) {\n if (argv.project && typeof argv.project === \"string\") {\n return;\n }\n\n if (!argv.account || typeof argv.account !== \"string\") {\n throw new Error(\"Invalid state: account is not set.\");\n }\n\n // If the project is linked, confirm with the user before prompting for selection.\n // Skip if useLinkedDetails is false (e.g. set when account was declined, or by the link command).\n // Also skip if the linked account doesn't match argv.account (e.g. --account was passed\n // explicitly for a different account than what's stored in .env.zuplo).\n if (argv[USE_LINKED_DETAILS] !== false) {\n const linked = await readLinkedConfig(argv);\n if (linked.projectName && linked.accountName === argv.account) {\n if (!isInteractiveTerminal()) {\n argv.project = linked.projectName;\n return;\n }\n\n const useLinked = await confirmLinkedValue(\n `Use linked project '${linked.projectName}'?`\n );\n if (useLinked) {\n argv.project = linked.projectName;\n return;\n }\n argv[USE_LINKED_DETAILS] = false;\n }\n }\n\n // In non-interactive environments, --project must be passed explicitly.\n // We check here, before the API call, to avoid an unnecessary network round-trip.\n if (!isInteractiveTerminal()) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: --project is required in non-interactive environments (e.g. CI/CD).\\nSee your available projects at https://portal.zuplo.com, then re-run with --project <name>.\"\n );\n return;\n }\n\n const baseUrl = `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/projects`;\n const queryParams: Record<string, string> = {\n // This is safe because of the previous middleware where we set the account.\n accountName: argv.account!,\n };\n\n // Create the query string using URLSearchParams\n const url = new URL(baseUrl);\n url.search = new URLSearchParams(queryParams).toString();\n\n // Make a call to the API key\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${argv.authToken}`,\n },\n });\n\n if (response.ok) {\n const projectsJson: { data: { name: string }[] } = await response.json();\n if (projectsJson.data.length === 0) {\n let projectName: string | undefined;\n try {\n const packageJson = JSON.parse(await readFile(\"package.json\", \"utf-8\"));\n projectName = packageJson.name;\n } catch (error) {\n logger.trace(\"Failed to read package.json\", error);\n }\n const outputProjectName = await input({\n message:\n \"You don't have any projects configured for this account. Please enter a project name to create one.\",\n default: projectName,\n });\n\n await createProject({\n name: outputProjectName,\n account: argv.account,\n authToken: argv.authToken as string,\n });\n argv.project = outputProjectName;\n logger.trace(`Project ${outputProjectName} created successfully.`);\n } else {\n try {\n argv.project = await select({\n message: \"Select the project\",\n choices: projectsJson.data\n .map((project) => {\n return {\n name: project.name,\n value: project.name,\n };\n })\n .sort((a, b) => a.name.localeCompare(b.name)),\n });\n } catch (error) {\n if (error.isTtyError || error.name === \"ExitPromptError\") {\n process.exit(1);\n }\n logger.trace(\"Failed to select project\", error);\n process.exit(1);\n }\n }\n } else {\n if (response.status === 404) {\n await printCriticalFailureToConsoleAndExit(\n \"You don't have any projects configured for this account. Create a project in the Zuplo dashboard and try again.\"\n );\n }\n logger.trace(\n {\n status: response.status,\n statusText: response.statusText,\n response: textOrJson(await response.text()),\n },\n \"Failed to request projects for account\"\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to request projects for the account.\"\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-linked-config.d.ts","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read-linked-config.d.ts","sourceRoot":"","sources":["../../src/common/read-linked-config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AAOrD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsBxB;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,IAAI,CAE1E;AAQD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB1E"}
|
|
@@ -4,6 +4,7 @@ import readline from "node:readline";
|
|
|
4
4
|
import dotenv from "dotenv";
|
|
5
5
|
import { ZUPLO_SYSTEM_ENV_VAR } from "./constants.js";
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
|
+
import { isInteractiveTerminal } from "./terminal.js";
|
|
7
8
|
const LINKED_CONFIG_CACHE_KEY = "linkedConfig";
|
|
8
9
|
export const USE_LINKED_DETAILS = "useLinkedDetails";
|
|
9
10
|
export async function readLinkedConfig(argv) {
|
|
@@ -34,7 +35,7 @@ export function ignoreLinkedDetails(argv) {
|
|
|
34
35
|
argv[USE_LINKED_DETAILS] = false;
|
|
35
36
|
}
|
|
36
37
|
export async function confirmLinkedValue(message) {
|
|
37
|
-
if (!
|
|
38
|
+
if (!isInteractiveTerminal()) {
|
|
38
39
|
return true;
|
|
39
40
|
}
|
|
40
41
|
return new Promise((resolve) => {
|
|
@@ -44,7 +45,7 @@ export async function confirmLinkedValue(message) {
|
|
|
44
45
|
});
|
|
45
46
|
rl.on("SIGINT", () => {
|
|
46
47
|
rl.close();
|
|
47
|
-
process.exit(
|
|
48
|
+
process.exit(1);
|
|
48
49
|
});
|
|
49
50
|
rl.question(`${message} [Y/n] `, (answer) => {
|
|
50
51
|
rl.close();
|
|
@@ -1 +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;
|
|
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;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD,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;AAQD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAe;IACtD,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;QAC7B,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\";\nimport { isInteractiveTerminal } from \"./terminal.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 * Returns true immediately in non-interactive terminals. Callers should check\n * isInteractiveTerminal() and skip this call entirely when possible.\n */\nexport async function confirmLinkedValue(message: string): Promise<boolean> {\n if (!isInteractiveTerminal()) {\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(1);\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"]}
|
|
@@ -65,9 +65,14 @@ describe("readLinkedConfig", () => {
|
|
|
65
65
|
describe("confirmLinkedValue", () => {
|
|
66
66
|
let originalStdinIsTTY;
|
|
67
67
|
let originalStdoutIsTTY;
|
|
68
|
+
let originalCI;
|
|
69
|
+
let hadCI;
|
|
68
70
|
beforeEach(() => {
|
|
69
71
|
originalStdinIsTTY = Object.getOwnPropertyDescriptor(process.stdin, "isTTY");
|
|
70
72
|
originalStdoutIsTTY = Object.getOwnPropertyDescriptor(process.stdout, "isTTY");
|
|
73
|
+
hadCI = Object.hasOwn(process.env, "CI");
|
|
74
|
+
originalCI = process.env.CI;
|
|
75
|
+
delete process.env.CI;
|
|
71
76
|
});
|
|
72
77
|
afterEach(() => {
|
|
73
78
|
mock.restoreAll();
|
|
@@ -83,16 +88,24 @@ describe("confirmLinkedValue", () => {
|
|
|
83
88
|
else {
|
|
84
89
|
delete process.stdout.isTTY;
|
|
85
90
|
}
|
|
91
|
+
if (hadCI) {
|
|
92
|
+
process.env.CI = originalCI;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
delete process.env.CI;
|
|
96
|
+
}
|
|
86
97
|
});
|
|
87
|
-
it("returns true immediately
|
|
88
|
-
const createInterfaceSpy = mock.method(readline, "createInterface");
|
|
98
|
+
it("returns true immediately without prompting in non-interactive terminals", async () => {
|
|
89
99
|
Object.defineProperty(process.stdin, "isTTY", {
|
|
90
100
|
value: false,
|
|
91
101
|
configurable: true,
|
|
92
102
|
});
|
|
103
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
104
|
+
value: false,
|
|
105
|
+
configurable: true,
|
|
106
|
+
});
|
|
93
107
|
const result = await confirmLinkedValue("Use linked account 'foo'?");
|
|
94
108
|
assert.strictEqual(result, true);
|
|
95
|
-
assert.strictEqual(createInterfaceSpy.mock.calls.length, 0);
|
|
96
109
|
});
|
|
97
110
|
it("returns true when user enters 'y'", async () => {
|
|
98
111
|
Object.defineProperty(process.stdin, "isTTY", {
|
|
@@ -202,7 +215,7 @@ describe("confirmLinkedValue", () => {
|
|
|
202
215
|
}));
|
|
203
216
|
void confirmLinkedValue("Use linked account 'foo'?");
|
|
204
217
|
assert.throws(() => sigintEmitter(), /process\.exit called/);
|
|
205
|
-
assert.strictEqual(exitStub.mock.calls[0].arguments[0],
|
|
218
|
+
assert.strictEqual(exitStub.mock.calls[0].arguments[0], 1);
|
|
206
219
|
});
|
|
207
220
|
});
|
|
208
221
|
describe("USE_LINKED_DETAILS", () => {
|
|
@@ -1 +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
|
+
{"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 let originalCI: string | undefined;\n let hadCI: boolean;\n\n beforeEach(() => {\n originalStdinIsTTY = Object.getOwnPropertyDescriptor(\n process.stdin,\n \"isTTY\"\n );\n originalStdoutIsTTY = Object.getOwnPropertyDescriptor(\n process.stdout,\n \"isTTY\"\n );\n hadCI = Object.hasOwn(process.env, \"CI\");\n originalCI = process.env.CI;\n // Clear CI so isInteractiveTerminal() doesn't short-circuit the readline path\n // in CI environments (e.g. GitHub Actions sets CI=true automatically).\n delete process.env.CI;\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 if (hadCI) {\n process.env.CI = originalCI;\n } else {\n delete process.env.CI;\n }\n });\n\n it(\"returns true immediately without prompting in non-interactive terminals\", async () => {\n // Make isInteractiveTerminal() return false by setting stdin to non-TTY.\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: false,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: false,\n configurable: true,\n });\n // readline must not be touched — if it were, the test would hang.\n const result = await confirmLinkedValue(\"Use linked account 'foo'?\");\n assert.strictEqual(result, true);\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(1) synchronously; our mock throws to intercept it\n assert.throws(() => sigintEmitter!(), /process\\.exit called/);\n assert.strictEqual(exitStub.mock.calls[0].arguments[0], 1);\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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/common/terminal.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,IAAI,OAAO,CAU/C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function isInteractiveTerminal() {
|
|
2
|
+
const ci = process.env.CI;
|
|
3
|
+
const ciOptedOut = ci === undefined || ci === "" || ci === "false" || ci === "0";
|
|
4
|
+
return (process.stdin.isTTY === true && process.stdout.isTTY === true && ciOptedOut);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/common/terminal.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB;IAEnC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;IAG1B,MAAM,UAAU,GACd,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,IAAI,EAAE,KAAK,GAAG,CAAC;IAChE,OAAO,CACL,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,UAAU,CAC5E,CAAC;AACJ,CAAC","sourcesContent":["export function isInteractiveTerminal(): boolean {\n // biome-ignore lint/style/noProcessEnv: CI must be treated as non-interactive for automated CLI flows\n const ci = process.env.CI;\n // Treat any truthy CI value (e.g. \"true\", \"1\", \"True\", \"yes\") as non-interactive.\n // Only the explicit opt-out values (\"false\", \"0\", \"\") or an unset CI are interactive.\n const ciOptedOut =\n ci === undefined || ci === \"\" || ci === \"false\" || ci === \"0\";\n return (\n process.stdin.isTTY === true && process.stdout.isTTY === true && ciOptedOut\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.test.d.ts","sourceRoot":"","sources":["../../src/common/terminal.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
3
|
+
import { isInteractiveTerminal } from "./terminal.js";
|
|
4
|
+
describe("isInteractiveTerminal", () => {
|
|
5
|
+
let originalStdinIsTTY;
|
|
6
|
+
let originalStdoutIsTTY;
|
|
7
|
+
let originalCI;
|
|
8
|
+
let hadCI;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
originalStdinIsTTY = Object.getOwnPropertyDescriptor(process.stdin, "isTTY");
|
|
11
|
+
originalStdoutIsTTY = Object.getOwnPropertyDescriptor(process.stdout, "isTTY");
|
|
12
|
+
hadCI = Object.hasOwn(process.env, "CI");
|
|
13
|
+
originalCI = process.env.CI;
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
if (originalStdinIsTTY) {
|
|
17
|
+
Object.defineProperty(process.stdin, "isTTY", originalStdinIsTTY);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
delete process.stdin.isTTY;
|
|
21
|
+
}
|
|
22
|
+
if (originalStdoutIsTTY) {
|
|
23
|
+
Object.defineProperty(process.stdout, "isTTY", originalStdoutIsTTY);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
delete process.stdout.isTTY;
|
|
27
|
+
}
|
|
28
|
+
if (hadCI) {
|
|
29
|
+
process.env.CI = originalCI;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
delete process.env.CI;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
function setTTY(stdin, stdout) {
|
|
36
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
37
|
+
value: stdin,
|
|
38
|
+
configurable: true,
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
41
|
+
value: stdout,
|
|
42
|
+
configurable: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
it("returns true when both TTYs are interactive and CI is unset", () => {
|
|
46
|
+
setTTY(true, true);
|
|
47
|
+
delete process.env.CI;
|
|
48
|
+
assert.strictEqual(isInteractiveTerminal(), true);
|
|
49
|
+
});
|
|
50
|
+
it("returns false when stdin is not a TTY", () => {
|
|
51
|
+
setTTY(false, true);
|
|
52
|
+
delete process.env.CI;
|
|
53
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
54
|
+
});
|
|
55
|
+
it("returns false when stdout is not a TTY", () => {
|
|
56
|
+
setTTY(true, false);
|
|
57
|
+
delete process.env.CI;
|
|
58
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
59
|
+
});
|
|
60
|
+
it("returns false when neither TTY is interactive", () => {
|
|
61
|
+
setTTY(false, false);
|
|
62
|
+
delete process.env.CI;
|
|
63
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
64
|
+
});
|
|
65
|
+
it('returns false when CI is "true"', () => {
|
|
66
|
+
setTTY(true, true);
|
|
67
|
+
process.env.CI = "true";
|
|
68
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
69
|
+
});
|
|
70
|
+
it('returns false when CI is "1" (Vercel and others)', () => {
|
|
71
|
+
setTTY(true, true);
|
|
72
|
+
process.env.CI = "1";
|
|
73
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
74
|
+
});
|
|
75
|
+
it('returns false when CI is "True" (AppVeyor)', () => {
|
|
76
|
+
setTTY(true, true);
|
|
77
|
+
process.env.CI = "True";
|
|
78
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
79
|
+
});
|
|
80
|
+
it('returns false when CI is "yes"', () => {
|
|
81
|
+
setTTY(true, true);
|
|
82
|
+
process.env.CI = "yes";
|
|
83
|
+
assert.strictEqual(isInteractiveTerminal(), false);
|
|
84
|
+
});
|
|
85
|
+
it('returns true when CI is "false" (explicit opt-out of CI mode)', () => {
|
|
86
|
+
setTTY(true, true);
|
|
87
|
+
process.env.CI = "false";
|
|
88
|
+
assert.strictEqual(isInteractiveTerminal(), true);
|
|
89
|
+
});
|
|
90
|
+
it('returns true when CI is "0" (explicit opt-out of CI mode)', () => {
|
|
91
|
+
setTTY(true, true);
|
|
92
|
+
process.env.CI = "0";
|
|
93
|
+
assert.strictEqual(isInteractiveTerminal(), true);
|
|
94
|
+
});
|
|
95
|
+
it("returns true when CI is an empty string", () => {
|
|
96
|
+
setTTY(true, true);
|
|
97
|
+
process.env.CI = "";
|
|
98
|
+
assert.strictEqual(isInteractiveTerminal(), true);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=terminal.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.test.js","sourceRoot":"","sources":["../../src/common/terminal.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert\";\nimport { afterEach, beforeEach, describe, it } from \"node:test\";\nimport { isInteractiveTerminal } from \"./terminal.js\";\n\ndescribe(\"isInteractiveTerminal\", () => {\n let originalStdinIsTTY: PropertyDescriptor | undefined;\n let originalStdoutIsTTY: PropertyDescriptor | undefined;\n let originalCI: string | undefined;\n let hadCI: boolean;\n\n beforeEach(() => {\n originalStdinIsTTY = Object.getOwnPropertyDescriptor(\n process.stdin,\n \"isTTY\"\n );\n originalStdoutIsTTY = Object.getOwnPropertyDescriptor(\n process.stdout,\n \"isTTY\"\n );\n hadCI = Object.hasOwn(process.env, \"CI\");\n originalCI = process.env.CI;\n });\n\n afterEach(() => {\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 if (hadCI) {\n process.env.CI = originalCI;\n } else {\n delete process.env.CI;\n }\n });\n\n function setTTY(stdin: boolean, stdout: boolean) {\n Object.defineProperty(process.stdin, \"isTTY\", {\n value: stdin,\n configurable: true,\n });\n Object.defineProperty(process.stdout, \"isTTY\", {\n value: stdout,\n configurable: true,\n });\n }\n\n it(\"returns true when both TTYs are interactive and CI is unset\", () => {\n setTTY(true, true);\n delete process.env.CI;\n assert.strictEqual(isInteractiveTerminal(), true);\n });\n\n it(\"returns false when stdin is not a TTY\", () => {\n setTTY(false, true);\n delete process.env.CI;\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it(\"returns false when stdout is not a TTY\", () => {\n setTTY(true, false);\n delete process.env.CI;\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it(\"returns false when neither TTY is interactive\", () => {\n setTTY(false, false);\n delete process.env.CI;\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it('returns false when CI is \"true\"', () => {\n setTTY(true, true);\n process.env.CI = \"true\";\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it('returns false when CI is \"1\" (Vercel and others)', () => {\n setTTY(true, true);\n process.env.CI = \"1\";\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it('returns false when CI is \"True\" (AppVeyor)', () => {\n setTTY(true, true);\n process.env.CI = \"True\";\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it('returns false when CI is \"yes\"', () => {\n setTTY(true, true);\n process.env.CI = \"yes\";\n assert.strictEqual(isInteractiveTerminal(), false);\n });\n\n it('returns true when CI is \"false\" (explicit opt-out of CI mode)', () => {\n setTTY(true, true);\n process.env.CI = \"false\";\n assert.strictEqual(isInteractiveTerminal(), true);\n });\n\n it('returns true when CI is \"0\" (explicit opt-out of CI mode)', () => {\n setTTY(true, true);\n process.env.CI = \"0\";\n assert.strictEqual(isInteractiveTerminal(), true);\n });\n\n it(\"returns true when CI is an empty string\", () => {\n setTTY(true, true);\n process.env.CI = \"\";\n assert.strictEqual(isInteractiveTerminal(), true);\n });\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/init/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/init/handler.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAyGD,wBAAsB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+K7D"}
|
package/dist/init/handler.js
CHANGED
|
@@ -4,13 +4,11 @@ import { confirm, input, select } from "@inquirer/prompts";
|
|
|
4
4
|
import { logger } from "../common/logger.js";
|
|
5
5
|
import { printCriticalFailureToConsoleAndExit, printResultToConsoleAndExitGracefully, printSpinnerToConsole, printWarningToConsole, } from "../common/output.js";
|
|
6
6
|
import settings from "../common/settings.js";
|
|
7
|
+
import { isInteractiveTerminal } from "../common/terminal.js";
|
|
7
8
|
import { deploy } from "../deploy/handler.js";
|
|
8
9
|
import { login } from "../login/login.js";
|
|
9
10
|
import { getAuthToken } from "../login/tokens.js";
|
|
10
11
|
import { createProject } from "../project/create/handler.js";
|
|
11
|
-
function isInteractive() {
|
|
12
|
-
return process.stdout.isTTY === true && !process.env.CI;
|
|
13
|
-
}
|
|
14
12
|
async function fetchAccounts(authToken) {
|
|
15
13
|
try {
|
|
16
14
|
const response = await fetch(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts`, {
|
|
@@ -63,7 +61,7 @@ async function fetchProjects(authToken, accountName) {
|
|
|
63
61
|
async function ensureAuthenticated() {
|
|
64
62
|
let token = await getAuthToken();
|
|
65
63
|
if (!token) {
|
|
66
|
-
if (!
|
|
64
|
+
if (!isInteractiveTerminal()) {
|
|
67
65
|
logger.debug("Non-interactive mode, skipping login prompt");
|
|
68
66
|
return undefined;
|
|
69
67
|
}
|
|
@@ -80,7 +78,7 @@ async function ensureAuthenticated() {
|
|
|
80
78
|
return token;
|
|
81
79
|
}
|
|
82
80
|
export async function init(argv) {
|
|
83
|
-
const skipPrompts = argv.yes || !
|
|
81
|
+
const skipPrompts = argv.yes || !isInteractiveTerminal();
|
|
84
82
|
let projectPath;
|
|
85
83
|
if (argv.dir) {
|
|
86
84
|
projectPath = resolve(argv.dir);
|
package/dist/init/handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/init/handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { confirm, input, select } from \"@inquirer/prompts\";\nimport { logger } from \"../common/logger.js\";\nimport {\n printCriticalFailureToConsoleAndExit,\n printResultToConsoleAndExitGracefully,\n printSpinnerToConsole,\n printWarningToConsole,\n} from \"../common/output.js\";\nimport settings from \"../common/settings.js\";\nimport { deploy } from \"../deploy/handler.js\";\nimport { login } from \"../login/login.js\";\nimport { getAuthToken } from \"../login/tokens.js\";\nimport { createProject } from \"../project/create/handler.js\";\n\nexport interface InitArguments {\n dir?: string;\n withAccount?: string;\n withProject?: string;\n yes?: boolean;\n}\n\ninterface Account {\n name: string;\n}\n\ninterface Project {\n name: string;\n}\n\nfunction isInteractive(): boolean {\n // biome-ignore lint/style/noProcessEnv: Checking for CI environment\n return process.stdout.isTTY === true && !process.env.CI;\n}\n\nasync function fetchAccounts(authToken: string): Promise<Account[]> {\n try {\n const response = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts`,\n {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${authToken}`,\n },\n }\n );\n\n if (response.ok) {\n const data: { data: Account[] } = await response.json();\n return data.data;\n }\n\n logger.error(\n `Failed to fetch accounts: received ${response.status} ${response.statusText}`\n );\n } catch (error) {\n logger.error(`Failed to fetch accounts: ${String(error)}`);\n }\n return [];\n}\n\nasync function fetchProjects(\n authToken: string,\n accountName: string\n): Promise<Project[]> {\n const url = new URL(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/projects`);\n url.searchParams.set(\"accountName\", accountName);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${authToken}`,\n },\n });\n\n if (!response.ok) {\n let errorBody: string | undefined;\n try {\n errorBody = await response.text();\n } catch {\n // ignore errors while reading the body\n }\n\n logger.error(\n `Failed to fetch projects for account \"${accountName}\": ` +\n `${response.status} ${response.statusText}` +\n (errorBody ? ` - ${errorBody}` : \"\")\n );\n return [];\n }\n\n const data: { data: Project[] } = await response.json();\n return data.data;\n } catch (error) {\n logger.error(\n `Error while fetching projects for account \"${accountName}\":`,\n error\n );\n return [];\n }\n}\n\nasync function ensureAuthenticated(): Promise<string | undefined> {\n let token = await getAuthToken();\n\n if (!token) {\n if (!isInteractive()) {\n logger.debug(\"Non-interactive mode, skipping login prompt\");\n return undefined;\n }\n\n const shouldLogin = await confirm({\n message: \"You are not logged in. Would you like to log in now?\",\n default: true,\n });\n\n if (!shouldLogin) {\n return undefined;\n }\n\n await login();\n token = await getAuthToken();\n }\n\n return token;\n}\n\nexport async function init(argv: InitArguments): Promise<void> {\n const skipPrompts = argv.yes || !isInteractive();\n\n // Determine the project directory (defaults to current working directory)\n let projectPath: string;\n if (argv.dir) {\n projectPath = resolve(argv.dir);\n } else {\n projectPath = process.cwd();\n }\n\n // Verify the directory exists\n if (!existsSync(projectPath)) {\n await printCriticalFailureToConsoleAndExit(\n `Directory ${projectPath} does not exist. Please create your project first using 'npx create-zuplo-api'.`\n );\n return;\n }\n\n // Step 1: Authenticate\n const authToken = await ensureAuthenticated();\n\n if (!authToken) {\n await printResultToConsoleAndExitGracefully(\n \"\\nSkipped platform initialization. You can run 'zuplo init' later to set up your project.\"\n );\n return;\n }\n\n let accountName: string | undefined;\n let projectName: string | undefined;\n\n // Step 2: Get or select account\n if (argv.withAccount) {\n accountName = argv.withAccount;\n } else {\n const accounts = await fetchAccounts(authToken);\n if (accounts.length === 0) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nNo accounts found. Please create an account at https://portal.zuplo.com first.\"\n );\n return;\n } else if (accounts.length === 1) {\n accountName = accounts[0].name;\n } else if (!skipPrompts) {\n accountName = await select({\n message: \"Select the account\",\n choices: accounts.map((acc) => ({\n name: acc.name,\n value: acc.name,\n })),\n });\n } else {\n accountName = accounts[0].name;\n }\n }\n\n if (!accountName) {\n await printCriticalFailureToConsoleAndExit(\"No account selected.\");\n return;\n }\n\n // Step 3: Create or select project\n const shouldCreateProject =\n argv.withProject !== undefined ||\n (skipPrompts\n ? true\n : await confirm({\n message: \"Would you like to create a new Zuplo project?\",\n default: true,\n }));\n\n if (shouldCreateProject) {\n // Get project name\n projectName = argv.withProject || basename(projectPath);\n\n if (!argv.withProject && !skipPrompts) {\n projectName = await input({\n message: \"Enter the project name\",\n default: basename(projectPath),\n });\n }\n\n // Create the project\n const createSpinner = printSpinnerToConsole(\n `Creating project '${projectName}'...`\n );\n const created = await createProject({\n name: projectName,\n account: accountName,\n authToken,\n });\n\n if (!created) {\n createSpinner.fail(\"Failed to create project\");\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nFailed to create project. You can create one later at https://portal.zuplo.com\"\n );\n projectName = undefined;\n } else {\n createSpinner.succeed(`Project '${projectName}' created`);\n }\n } else {\n // Select existing project\n const projects = await fetchProjects(authToken, accountName);\n if (projects.length === 0) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nNo projects found. Create a project first using 'zuplo project create'.\"\n );\n } else if (projects.length === 1) {\n projectName = projects[0].name;\n } else if (!skipPrompts) {\n projectName = await select({\n message: \"Select the project\",\n choices: projects.map((proj) => ({\n name: proj.name,\n value: proj.name,\n })),\n });\n }\n }\n\n if (!projectName) {\n await printResultToConsoleAndExitGracefully(\n \"\\nNo project selected. You can run 'zuplo init' later to set up your project.\"\n );\n return;\n }\n\n // Step 4: Deploy the project to create the initial environment\n // This ensures the environment is ready before we try to link\n const shouldDeploy =\n skipPrompts ||\n (await confirm({\n message:\n \"Would you like to deploy your project now? (This creates the initial environment)\",\n default: true,\n }));\n\n // Use \"main\" as the default environment/branch name for initial deployment\n const defaultEnvironment = \"main\";\n\n if (shouldDeploy) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log();\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\"Deploying your project...\");\n\n try {\n // The deploy function handles its own spinners and output\n // We pass the environment explicitly since this might not be a git repo yet\n await deploy({\n account: accountName,\n project: projectName,\n dir: projectPath,\n environment: defaultEnvironment,\n authToken,\n });\n } catch (error) {\n logger.debug(\"Initial deployment failed\", error);\n printWarningToConsole(\n \"Initial deployment failed. You can deploy later using 'zuplo deploy'.\"\n );\n }\n }\n\n const isCurrentDir = resolve(projectPath) === resolve(process.cwd());\n const getStartedMessage = `\\nProject initialized successfully!\\n\\nTo get started:\\n${\n isCurrentDir ? \"\" : ` cd ${basename(projectPath)}\\n`\n } npm run dev`;\n\n await printResultToConsoleAndExitGracefully(getStartedMessage);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/init/handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { confirm, input, select } from \"@inquirer/prompts\";\nimport { logger } from \"../common/logger.js\";\nimport {\n printCriticalFailureToConsoleAndExit,\n printResultToConsoleAndExitGracefully,\n printSpinnerToConsole,\n printWarningToConsole,\n} from \"../common/output.js\";\nimport settings from \"../common/settings.js\";\nimport { isInteractiveTerminal } from \"../common/terminal.js\";\nimport { deploy } from \"../deploy/handler.js\";\nimport { login } from \"../login/login.js\";\nimport { getAuthToken } from \"../login/tokens.js\";\nimport { createProject } from \"../project/create/handler.js\";\n\nexport interface InitArguments {\n dir?: string;\n withAccount?: string;\n withProject?: string;\n yes?: boolean;\n}\n\ninterface Account {\n name: string;\n}\n\ninterface Project {\n name: string;\n}\n\nasync function fetchAccounts(authToken: string): Promise<Account[]> {\n try {\n const response = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/accounts`,\n {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${authToken}`,\n },\n }\n );\n\n if (response.ok) {\n const data: { data: Account[] } = await response.json();\n return data.data;\n }\n\n logger.error(\n `Failed to fetch accounts: received ${response.status} ${response.statusText}`\n );\n } catch (error) {\n logger.error(`Failed to fetch accounts: ${String(error)}`);\n }\n return [];\n}\n\nasync function fetchProjects(\n authToken: string,\n accountName: string\n): Promise<Project[]> {\n const url = new URL(`${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/projects`);\n url.searchParams.set(\"accountName\", accountName);\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n // biome-ignore lint/style/useNamingConvention: External API property\n Authorization: `Bearer ${authToken}`,\n },\n });\n\n if (!response.ok) {\n let errorBody: string | undefined;\n try {\n errorBody = await response.text();\n } catch {\n // ignore errors while reading the body\n }\n\n logger.error(\n `Failed to fetch projects for account \"${accountName}\": ` +\n `${response.status} ${response.statusText}` +\n (errorBody ? ` - ${errorBody}` : \"\")\n );\n return [];\n }\n\n const data: { data: Project[] } = await response.json();\n return data.data;\n } catch (error) {\n logger.error(\n `Error while fetching projects for account \"${accountName}\":`,\n error\n );\n return [];\n }\n}\n\nasync function ensureAuthenticated(): Promise<string | undefined> {\n let token = await getAuthToken();\n\n if (!token) {\n if (!isInteractiveTerminal()) {\n logger.debug(\"Non-interactive mode, skipping login prompt\");\n return undefined;\n }\n\n const shouldLogin = await confirm({\n message: \"You are not logged in. Would you like to log in now?\",\n default: true,\n });\n\n if (!shouldLogin) {\n return undefined;\n }\n\n await login();\n token = await getAuthToken();\n }\n\n return token;\n}\n\nexport async function init(argv: InitArguments): Promise<void> {\n const skipPrompts = argv.yes || !isInteractiveTerminal();\n\n // Determine the project directory (defaults to current working directory)\n let projectPath: string;\n if (argv.dir) {\n projectPath = resolve(argv.dir);\n } else {\n projectPath = process.cwd();\n }\n\n // Verify the directory exists\n if (!existsSync(projectPath)) {\n await printCriticalFailureToConsoleAndExit(\n `Directory ${projectPath} does not exist. Please create your project first using 'npx create-zuplo-api'.`\n );\n return;\n }\n\n // Step 1: Authenticate\n const authToken = await ensureAuthenticated();\n\n if (!authToken) {\n await printResultToConsoleAndExitGracefully(\n \"\\nSkipped platform initialization. You can run 'zuplo init' later to set up your project.\"\n );\n return;\n }\n\n let accountName: string | undefined;\n let projectName: string | undefined;\n\n // Step 2: Get or select account\n if (argv.withAccount) {\n accountName = argv.withAccount;\n } else {\n const accounts = await fetchAccounts(authToken);\n if (accounts.length === 0) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nNo accounts found. Please create an account at https://portal.zuplo.com first.\"\n );\n return;\n } else if (accounts.length === 1) {\n accountName = accounts[0].name;\n } else if (!skipPrompts) {\n accountName = await select({\n message: \"Select the account\",\n choices: accounts.map((acc) => ({\n name: acc.name,\n value: acc.name,\n })),\n });\n } else {\n accountName = accounts[0].name;\n }\n }\n\n if (!accountName) {\n await printCriticalFailureToConsoleAndExit(\"No account selected.\");\n return;\n }\n\n // Step 3: Create or select project\n const shouldCreateProject =\n argv.withProject !== undefined ||\n (skipPrompts\n ? true\n : await confirm({\n message: \"Would you like to create a new Zuplo project?\",\n default: true,\n }));\n\n if (shouldCreateProject) {\n // Get project name\n projectName = argv.withProject || basename(projectPath);\n\n if (!argv.withProject && !skipPrompts) {\n projectName = await input({\n message: \"Enter the project name\",\n default: basename(projectPath),\n });\n }\n\n // Create the project\n const createSpinner = printSpinnerToConsole(\n `Creating project '${projectName}'...`\n );\n const created = await createProject({\n name: projectName,\n account: accountName,\n authToken,\n });\n\n if (!created) {\n createSpinner.fail(\"Failed to create project\");\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nFailed to create project. You can create one later at https://portal.zuplo.com\"\n );\n projectName = undefined;\n } else {\n createSpinner.succeed(`Project '${projectName}' created`);\n }\n } else {\n // Select existing project\n const projects = await fetchProjects(authToken, accountName);\n if (projects.length === 0) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\n \"\\nNo projects found. Create a project first using 'zuplo project create'.\"\n );\n } else if (projects.length === 1) {\n projectName = projects[0].name;\n } else if (!skipPrompts) {\n projectName = await select({\n message: \"Select the project\",\n choices: projects.map((proj) => ({\n name: proj.name,\n value: proj.name,\n })),\n });\n }\n }\n\n if (!projectName) {\n await printResultToConsoleAndExitGracefully(\n \"\\nNo project selected. You can run 'zuplo init' later to set up your project.\"\n );\n return;\n }\n\n // Step 4: Deploy the project to create the initial environment\n // This ensures the environment is ready before we try to link\n const shouldDeploy =\n skipPrompts ||\n (await confirm({\n message:\n \"Would you like to deploy your project now? (This creates the initial environment)\",\n default: true,\n }));\n\n // Use \"main\" as the default environment/branch name for initial deployment\n const defaultEnvironment = \"main\";\n\n if (shouldDeploy) {\n // biome-ignore lint/suspicious/noConsole: User output\n console.log();\n // biome-ignore lint/suspicious/noConsole: User output\n console.log(\"Deploying your project...\");\n\n try {\n // The deploy function handles its own spinners and output\n // We pass the environment explicitly since this might not be a git repo yet\n await deploy({\n account: accountName,\n project: projectName,\n dir: projectPath,\n environment: defaultEnvironment,\n authToken,\n });\n } catch (error) {\n logger.debug(\"Initial deployment failed\", error);\n printWarningToConsole(\n \"Initial deployment failed. You can deploy later using 'zuplo deploy'.\"\n );\n }\n }\n\n const isCurrentDir = resolve(projectPath) === resolve(process.cwd());\n const getStartedMessage = `\\nProject initialized successfully!\\n\\nTo get started:\\n${\n isCurrentDir ? \"\" : ` cd ${basename(projectPath)}\\n`\n } npm run dev`;\n\n await printResultToConsoleAndExitGracefully(getStartedMessage);\n}\n"]}
|