@devkong/cli 0.0.67-alpha.27 → 0.0.67-alpha.28

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/index.js CHANGED
@@ -47978,13 +47978,18 @@ var globalThisPolyfill = (function() {
47978
47978
  }
47979
47979
  })();
47980
47980
 
47981
- // packages/kong-ts/src/lib/connect.ts
47982
- var KONG_CONNECT_PORT = 41321;
47983
- var KONG_CONNECT_BASE_URL = `http://localhost:${KONG_CONNECT_PORT}`;
47984
-
47985
47981
  // packages/kong-ts/src/lib/cron.ts
47986
47982
  var import_cronstrue = __toESM(require_cronstrue());
47987
47983
 
47984
+ // packages/kong-ts/src/lib/guard.ts
47985
+ function notNull(value) {
47986
+ if (value === void 0 || value === null) {
47987
+ debugger;
47988
+ throw new AppError(`The provided value must not be null, got ${value}`);
47989
+ }
47990
+ return value;
47991
+ }
47992
+
47988
47993
  // packages/kong-ts/src/lib/jq.ts
47989
47994
  function jqFilter(value) {
47990
47995
  return value;
@@ -60729,7 +60734,7 @@ function uuidToJavaHashCode(uuid) {
60729
60734
  const hash = Number(mostSigBits >> 32n ^ mostSigBits ^ leastSigBits >> 32n ^ leastSigBits);
60730
60735
  return hash | 0;
60731
60736
  }
60732
- function generateShortId() {
60737
+ function generateShortId2() {
60733
60738
  const sqids = new Sqids({
60734
60739
  minLength: 12,
60735
60740
  alphabet: "abcdefghijklmnopqrstuvwxyz0123456789"
@@ -60897,1610 +60902,1092 @@ var ConfigureCommand = class {
60897
60902
  }
60898
60903
  };
60899
60904
 
60905
+ // packages/kong-ts-contract/src/lib/appConnect.ts
60906
+ var APP_CONNECT_PORT = 41321;
60907
+ var APP_CONNECT_BASE_URL = `http://localhost:${APP_CONNECT_PORT}`;
60908
+
60900
60909
  // packages/kong-cli/src/commands/connectCommand.ts
60901
- var import_child_process2 = require("child_process");
60902
- var import_fs3 = __toESM(require("fs"));
60910
+ var import_child_process3 = require("child_process");
60911
+ var import_fs5 = __toESM(require("fs"));
60903
60912
  var import_http4 = __toESM(require("http"));
60904
- var import_os2 = __toESM(require("os"));
60913
+ var import_os3 = __toESM(require("os"));
60914
+ var import_path6 = __toESM(require("path"));
60915
+
60916
+ // packages/kong-cli/src/common/cli.ts
60917
+ var import_fs3 = __toESM(require("fs"));
60905
60918
  var import_path4 = __toESM(require("path"));
60919
+ function getPresetVersion() {
60920
+ const packageJsonPath = import_path4.default.join(__dirname, "package.json");
60921
+ if (!import_fs3.default.existsSync(packageJsonPath)) {
60922
+ throw new AppError(`package.json file was not found at path: ${packageJsonPath}`);
60923
+ }
60924
+ return require(packageJsonPath).version;
60925
+ }
60906
60926
 
60907
- // packages/kong-cli/src/services/api.ts
60908
- var import_keyring2 = __toESM(require_keyring());
60927
+ // packages/kong-cli/src/commands/generateCommand.ts
60928
+ var import_create_nx_workspace = require("create-nx-workspace");
60909
60929
 
60910
- // node_modules/jwt-decode/build/esm/index.js
60911
- var InvalidTokenError = class extends Error {
60912
- };
60913
- InvalidTokenError.prototype.name = "InvalidTokenError";
60914
- function b64DecodeUnicode(str) {
60915
- return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
60916
- let code = p.charCodeAt(0).toString(16).toUpperCase();
60917
- if (code.length < 2) {
60918
- code = "0" + code;
60930
+ // packages/kong-cli/src/common/kongJson.ts
60931
+ var import_ajv = __toESM(require_ajv());
60932
+ var import_fs4 = __toESM(require("fs"));
60933
+
60934
+ // packages/kong-cli/src/common/kongJsonSchema.ts
60935
+ var KONG_JSON_SCHEMA = {
60936
+ $schema: "http://json-schema.org/draft-07/schema#",
60937
+ type: "object",
60938
+ properties: {
60939
+ id: {
60940
+ type: "string"
60941
+ },
60942
+ name: {
60943
+ type: "string"
60944
+ },
60945
+ sdk: {
60946
+ type: "string",
60947
+ enum: ["python", "kotlin"]
60948
+ },
60949
+ category: {
60950
+ type: "string"
60951
+ },
60952
+ settings: {
60953
+ type: "object",
60954
+ properties: {
60955
+ input: {
60956
+ type: "object",
60957
+ properties: {
60958
+ filter: {
60959
+ type: "string"
60960
+ },
60961
+ schema: {
60962
+ $ref: "http://json-schema.org/draft-07/schema#"
60963
+ }
60964
+ },
60965
+ required: ["schema", "filter"]
60966
+ },
60967
+ output: {
60968
+ type: "object",
60969
+ properties: {
60970
+ filter: {
60971
+ type: "string"
60972
+ },
60973
+ schema: {
60974
+ $ref: "http://json-schema.org/draft-07/schema#"
60975
+ }
60976
+ },
60977
+ required: ["schema", "filter"]
60978
+ },
60979
+ invoke: {
60980
+ type: "object",
60981
+ properties: {
60982
+ prefix: {
60983
+ type: "string"
60984
+ },
60985
+ cache: {
60986
+ type: "object",
60987
+ properties: {
60988
+ enabled: {
60989
+ type: "boolean"
60990
+ },
60991
+ key: {
60992
+ type: ["string"]
60993
+ },
60994
+ ttl: {
60995
+ type: "string"
60996
+ },
60997
+ onFailure: {
60998
+ type: "string",
60999
+ enum: ["skip", "retry"]
61000
+ }
61001
+ },
61002
+ required: ["enabled", "key", "ttl", "onFailure"]
61003
+ },
61004
+ retry: {
61005
+ type: "object",
61006
+ properties: {
61007
+ maxAttempts: {
61008
+ type: "number"
61009
+ },
61010
+ attemptDelay: {
61011
+ type: "string"
61012
+ },
61013
+ attemptTimeout: {
61014
+ type: "string"
61015
+ }
61016
+ },
61017
+ required: ["maxAttempts", "attemptDelay", "attemptTimeout"]
61018
+ },
61019
+ circuitBreaker: {
61020
+ type: "object",
61021
+ properties: {
61022
+ enabled: {
61023
+ type: "boolean"
61024
+ },
61025
+ requestVolumeThreshold: {
61026
+ type: "number"
61027
+ },
61028
+ failureRatio: {
61029
+ type: "number"
61030
+ },
61031
+ successThreshold: {
61032
+ type: "number"
61033
+ }
61034
+ },
61035
+ required: ["enabled", "requestVolumeThreshold", "failureRatio", "successThreshold"]
61036
+ }
61037
+ }
61038
+ }
61039
+ },
61040
+ additionalProperties: false
60919
61041
  }
60920
- return "%" + code;
60921
- }));
60922
- }
60923
- function base64UrlDecode(str) {
60924
- let output = str.replace(/-/g, "+").replace(/_/g, "/");
60925
- switch (output.length % 4) {
60926
- case 0:
60927
- break;
60928
- case 2:
60929
- output += "==";
60930
- break;
60931
- case 3:
60932
- output += "=";
60933
- break;
60934
- default:
60935
- throw new Error("base64 string is not of the correct length");
61042
+ },
61043
+ additionalProperties: false,
61044
+ required: ["id", "name", "sdk", "category"]
61045
+ };
61046
+
61047
+ // packages/kong-cli/src/common/kongJson.ts
61048
+ var ajv = new import_ajv.default();
61049
+ var validate2 = ajv.compile(KONG_JSON_SCHEMA);
61050
+ var SUPPORTED_SDK = ["kotlin", "python"];
61051
+ function validateKongJson(kongJson) {
61052
+ if (isEmpty(kongJson.id)) {
61053
+ throw new AppError(
61054
+ "The `id` field should not be empty. Please provide a valid identifier in kong.json."
61055
+ );
60936
61056
  }
60937
- try {
60938
- return b64DecodeUnicode(output);
60939
- } catch (err) {
60940
- return atob(output);
61057
+ if (isEmpty(kongJson.category)) {
61058
+ throw new AppError(
61059
+ "The `category` field should not be empty. Please provide a category value in kong.json."
61060
+ );
60941
61061
  }
60942
- }
60943
- function jwtDecode(token, options) {
60944
- if (typeof token !== "string") {
60945
- throw new InvalidTokenError("Invalid token specified: must be a string");
61062
+ if (!/^[a-z][a-z0-9]{11}$/.test(kongJson.id)) {
61063
+ throw new AppError(
61064
+ "The id must be exactly 12 characters long and consist of alphanumeric characters (lowercase letters and digits). It must start with a letter. Ensure the ID does not exceed 12 characters. Please provide a valid identifier in kong.json"
61065
+ );
60946
61066
  }
60947
- options || (options = {});
60948
- const pos = options.header === true ? 0 : 1;
60949
- const part = token.split(".")[pos];
60950
- if (typeof part !== "string") {
60951
- throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
61067
+ if (!SUPPORTED_SDK.includes(kongJson.sdk)) {
61068
+ throw new AppError(
61069
+ `Unexpected SDK value: ${kongJson.sdk}. Supported SDK: ${SUPPORTED_SDK}.Please provide a valid identifier in kong.json.`
61070
+ );
60952
61071
  }
60953
- let decoded;
60954
- try {
60955
- decoded = base64UrlDecode(part);
60956
- } catch (e) {
60957
- throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
61072
+ if (isEmpty(kongJson.name)) {
61073
+ throw new AppError(
61074
+ "The `name` field should not be empty. Please provide a valid name in kong.json."
61075
+ );
61076
+ }
61077
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(kongJson.name)) {
61078
+ throw new AppError(
61079
+ "The `name` should only contain lowercase letters, digits, and dashes. Dashes can only appear between alphanumeric characters, and the name cannot start or end with a dash.Please provide a valid name in kong.json."
61080
+ );
61081
+ }
61082
+ const isValid2 = validate2(kongJson);
61083
+ if (!isValid2) {
61084
+ throw new AppError(
61085
+ "The provided `kong.json` does not follow the expected JSON schema. Errors: \n" + prettyJsonObject(validate2.errors || [])
61086
+ );
60958
61087
  }
61088
+ return kongJson;
61089
+ }
61090
+ function getKongJson() {
61091
+ const kongJsonPath = resolveProjectPath("kong.json");
60959
61092
  try {
60960
- return JSON.parse(decoded);
60961
- } catch (e) {
60962
- throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
61093
+ const fileContent = import_fs4.default.readFileSync(kongJsonPath, "utf-8");
61094
+ const kongJson = JSON.parse(fileContent);
61095
+ return validateKongJson(kongJson);
61096
+ } catch (ex) {
61097
+ if (ex instanceof SyntaxError) {
61098
+ throw new AppError(`Error parsing kong.json: ${ex.message}`);
61099
+ }
61100
+ throw ex;
60963
61101
  }
60964
61102
  }
60965
61103
 
60966
- // packages/kong-cli/src/services/api.ts
60967
- function requestConfigProvider(profile) {
60968
- const cached = {
60969
- headers: {
60970
- "Content-Type": "application/json",
60971
- "X-App-Tenant": parseTenant(profile.kongBaseUrl)
60972
- }
60973
- };
60974
- return async () => {
60975
- if (cached.headers?.Authorization) {
60976
- try {
60977
- const auth = cached.headers.Authorization;
60978
- const accessToken = auth.split("Bearer ")[1]?.trim();
60979
- if (accessToken) {
60980
- const decoded = jwtDecode(accessToken);
60981
- if (decoded.exp !== void 0) {
60982
- const nowSeconds = Date.now() / 1e3;
60983
- if (decoded.exp > nowSeconds + 60) {
60984
- return cached;
60985
- }
60986
- }
60987
- }
60988
- } catch (ex) {
60989
- console.warn("failed to use cached token, fetching new one", ex);
60990
- }
60991
- }
60992
- const url2 = joinUrlAndPath(
60993
- profile.kongBaseUrl,
60994
- "api/keycloak/realms/kong/protocol/openid-connect/token"
60995
- );
60996
- const entry = new import_keyring2.Entry(profile.kongBaseUrl, profile.userName);
60997
- const password = entry.getPassword();
60998
- if (!password) {
60999
- throw new Error("No password found in keyring for user: " + profile.userName);
61000
- }
61001
- const params = new URLSearchParams({
61002
- grant_type: "password",
61003
- client_id: "kong-web",
61004
- username: profile.userName,
61005
- password
61104
+ // packages/kong-cli/src/commands/generateCommand.ts
61105
+ var GenerateCommand = class {
61106
+ async execute(extensionName, sdk, presetVersion, template2) {
61107
+ const id = generateShortId2();
61108
+ const variant = sdk === "python" ? template2 ?? await this.promptTemplate() : "basic";
61109
+ validateKongJson({
61110
+ id,
61111
+ sdk,
61112
+ name: extensionName,
61113
+ category: "unknown",
61114
+ settings: {}
61006
61115
  });
61007
- const response = await axios_default.post(url2, params, {
61008
- headers: {
61009
- "Content-Type": "application/x-www-form-urlencoded"
61010
- }
61116
+ await (0, import_create_nx_workspace.createWorkspace)(`@devkong/cli-nx@${presetVersion}`, {
61117
+ name: extensionName,
61118
+ id,
61119
+ platform: sdk,
61120
+ // Passed through to the preset generator. Not named `template` on purpose:
61121
+ // create-nx-workspace reserves that option for cloning a GitHub workspace.
61122
+ variant,
61123
+ nxCloud: "skip",
61124
+ packageManager: "npm",
61125
+ trustThirdPartyPreset: true,
61126
+ analytics: false
61011
61127
  });
61012
- cached.headers = {
61013
- ...cached.headers,
61014
- ["Authorization"]: `Bearer ${response.data.access_token}`
61015
- };
61016
- return cached;
61017
- };
61018
- }
61019
-
61020
- // packages/kong-cli/src/services/managementClient.ts
61021
- var ManagementClient = class {
61022
- constructor(kongBaseUrl, requestConfigProvider2) {
61023
- this.requestConfigProvider = requestConfigProvider2;
61024
- this.baseUrl = joinUrlAndPath(kongBaseUrl, "/api/management");
61025
- }
61026
- async updateExtension(extension) {
61027
- const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions");
61028
- await axios_default.put(url2, extension, await this.requestConfigProvider());
61029
- }
61030
- async createExtensionSnapshot(extensionId, snapshot) {
61031
- const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "snapshots");
61032
- await axios_default.post(url2, snapshot, await this.requestConfigProvider());
61033
- }
61034
- async getExtensionSnapshot(extensionId, extensionSnapshotVersion) {
61035
- const url2 = joinUrlAndPath(
61036
- this.baseUrl,
61037
- "v1/extensions",
61038
- extensionId,
61039
- "snapshots",
61040
- extensionSnapshotVersion
61041
- );
61042
- return (await axios_default.get(url2, await this.requestConfigProvider())).data;
61043
- }
61044
- async getExtensionSnapshotVersions(extensionId) {
61045
- const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "/snapshots/versions");
61046
- return (await axios_default.get(url2, await this.requestConfigProvider())).data;
61047
- }
61048
- async getExtensionSnapshotAliases(extensionId) {
61049
- const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "/aliases");
61050
- return (await axios_default.get(url2, await this.requestConfigProvider())).data;
61051
- }
61052
- async getDocumentSnapshotVersions(documentId) {
61053
- const url2 = joinUrlAndPath(this.baseUrl, "v1/documents", documentId, "/snapshots/versions");
61054
- return (await axios_default.get(url2, await this.requestConfigProvider())).data;
61055
- }
61056
- async getProcessAliases(documentId) {
61057
- const url2 = joinUrlAndPath(this.baseUrl, "v1/processes", documentId, "/aliases");
61058
- return (await axios_default.get(url2, await this.requestConfigProvider())).data;
61059
61128
  }
61060
- async getAuditLog(objectType2, objectId, createdAfter) {
61061
- const url2 = joinUrlAndPath(this.baseUrl, "v1/audit");
61062
- const config = await this.requestConfigProvider();
61063
- const response = await axios_default.get(url2, {
61064
- ...config,
61065
- params: { ...config.params, objectType: objectType2, objectId, createdAfter }
61129
+ async promptTemplate() {
61130
+ const { template: template2 } = await dist_default14.prompt({
61131
+ type: "select",
61132
+ name: "template",
61133
+ message: "which template would you like to use?",
61134
+ default: "basic",
61135
+ choices: [
61136
+ { name: "basic - a single operation", value: "basic" },
61137
+ {
61138
+ name: "with-secret - multiple operations with a secret example",
61139
+ value: "with-secret"
61140
+ },
61141
+ {
61142
+ name: "with-s3 - download a file from S3 using an s3 secret",
61143
+ value: "with-s3"
61144
+ }
61145
+ ]
61066
61146
  });
61067
- return response.data;
61068
- }
61069
- };
61070
-
61071
- // packages/kong-cli/src/services/registryClient.ts
61072
- var RegistryClient = class {
61073
- constructor(kongBaseUrl, requestConfigProvider2) {
61074
- this.requestConfigProvider = requestConfigProvider2;
61075
- this.baseUrl = joinUrlAndPath(kongBaseUrl, "/api/registry");
61076
- }
61077
- async getPublishDetails(appName) {
61078
- const url2 = joinUrlAndPath(this.baseUrl, "v1/repository", appName, "publish/details");
61079
- return (await axios_default.post(url2, {}, await this.requestConfigProvider())).data;
61147
+ return template2;
61080
61148
  }
61081
61149
  };
61082
61150
 
61083
- // packages/kong-cli/src/commands/connectCommand.ts
61084
- var DOCKERFILE = `# syntax=docker/dockerfile:1
61085
- FROM --platform=linux/amd64 python:3.13.1-slim-bookworm
61086
-
61087
- ENV APP_DIR=/deployments/app \\
61088
- PYTHONUNBUFFERED=1 \\
61089
- PYTHONDONTWRITEBYTECODE=1
61090
-
61091
- WORKDIR $APP_DIR
61092
-
61093
- COPY --chown=1001:root ./requirements.txt ./requirements.txt
61094
- RUN pip install --upgrade pip && \\
61095
- pip install -r requirements.txt
61096
-
61097
- COPY --chown=1001:root ./src ./src
61098
-
61099
- RUN useradd --uid 1001 --gid root --create-home app \\
61100
- && chown 1001:root $APP_DIR \\
61101
- && chmod "g+rwX" $APP_DIR
61102
-
61103
- USER 1001
61151
+ // node_modules/listr2/node_modules/eventemitter3/index.mjs
61152
+ var import_index = __toESM(require_eventemitter3(), 1);
61153
+ var eventemitter3_default = import_index.default;
61104
61154
 
61105
- CMD ["python", "./src/main.py"]
61106
- `;
61107
- var PYPROJECT = `[tool.pytest.ini_options]
61108
- asyncio_mode = "auto"
61109
- asyncio_default_fixture_loop_scope = "function"
61110
- `;
61111
- var TEST_DEPENDENCIES = ["pytest==9.1.1", "pytest-asyncio==1.4.0"];
61112
- var DEPLOY_STEPS = [
61113
- "install dependencies",
61114
- "generate schema",
61115
- "get publish details",
61116
- "docker login",
61117
- "docker build",
61118
- "docker push",
61119
- "save publish details"
61120
- ];
61121
- function notNullStep(job, name) {
61122
- const step = job.steps.find((item) => item.name === name);
61123
- if (!step) {
61124
- throw new Error(`unknown deployment step ${name}`);
61125
- }
61126
- return step;
61127
- }
61128
- var ConnectCommand = class {
61129
- constructor(profileName, profile) {
61130
- this.profileName = profileName;
61131
- this.profile = profile;
61132
- this.isWin = process.platform === "win32";
61133
- this.deployments = /* @__PURE__ */ new Map();
61134
- const provider = requestConfigProvider(profile);
61135
- this.registryClient = new RegistryClient(profile.kongBaseUrl, provider);
61136
- this.managementClient = new ManagementClient(profile.kongBaseUrl, provider);
61155
+ // node_modules/listr2/dist/index.mjs
61156
+ var import_node_util11 = require("node:util");
61157
+ var import_util4 = require("util");
61158
+ var import_os2 = require("os");
61159
+ var import_string_decoder = require("string_decoder");
61160
+ var import_stream5 = require("stream");
61161
+ var import_rfdc = __toESM(require_rfdc(), 1);
61162
+ var import_crypto2 = require("crypto");
61163
+ var ANSI_ESCAPE_CODES = {
61164
+ CURSOR_HIDE: "\x1B[?25l",
61165
+ CURSOR_SHOW: "\x1B[?25h"
61166
+ };
61167
+ var ListrTaskState = /* @__PURE__ */ (function(ListrTaskState2) {
61168
+ ListrTaskState2["WAITING"] = "WAITING";
61169
+ ListrTaskState2["STARTED"] = "STARTED";
61170
+ ListrTaskState2["COMPLETED"] = "COMPLETED";
61171
+ ListrTaskState2["FAILED"] = "FAILED";
61172
+ ListrTaskState2["SKIPPED"] = "SKIPPED";
61173
+ ListrTaskState2["ROLLING_BACK"] = "ROLLING_BACK";
61174
+ ListrTaskState2["ROLLED_BACK"] = "ROLLED_BACK";
61175
+ ListrTaskState2["RETRY"] = "RETRY";
61176
+ ListrTaskState2["PAUSED"] = "PAUSED";
61177
+ ListrTaskState2["PROMPT"] = "PROMPT";
61178
+ ListrTaskState2["PROMPT_COMPLETED"] = "PROMPT_COMPLETED";
61179
+ ListrTaskState2["PROMPT_FAILED"] = "PROMPT_FAILED";
61180
+ return ListrTaskState2;
61181
+ })({});
61182
+ var EventManager = class {
61183
+ emitter = new eventemitter3_default();
61184
+ emit(dispatch, args) {
61185
+ this.emitter.emit(dispatch, args);
61137
61186
  }
61138
- async execute() {
61139
- const server = import_http4.default.createServer((request, response) => {
61140
- this.handle(request, response).catch((ex) => {
61141
- console.error("request failed", ex);
61142
- if (!response.headersSent) {
61143
- this.json(response, 500, { error: String(ex) });
61144
- }
61145
- });
61146
- });
61147
- server.listen(KONG_CONNECT_PORT, () => {
61148
- console.info(
61149
- `kong connect is listening on http://localhost:${KONG_CONNECT_PORT} (profile=${this.profileName}, baseUrl=${this.profile.kongBaseUrl})`
61150
- );
61151
- console.info("keep this terminal open while working in the kong ui; ctrl+c to stop");
61152
- });
61187
+ on(dispatch, handler) {
61188
+ this.emitter.addListener(dispatch, handler);
61153
61189
  }
61154
- async handle(request, response) {
61155
- response.setHeader("Access-Control-Allow-Origin", "*");
61156
- response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
61157
- response.setHeader("Access-Control-Allow-Headers", "Content-Type");
61158
- if (request.method === "OPTIONS") {
61159
- response.writeHead(204);
61160
- response.end();
61161
- return;
61162
- }
61163
- const url2 = new URL(request.url ?? "/", `http://localhost:${KONG_CONNECT_PORT}`);
61164
- if (request.method === "GET" && url2.pathname === "/v1/profile") {
61165
- this.json(response, 200, this.profileInfo());
61166
- return;
61167
- }
61168
- if (request.method === "POST" && url2.pathname === "/v1/tests") {
61169
- const body = await this.readBody(request);
61170
- this.json(response, 200, await this.runTests(body));
61171
- return;
61172
- }
61173
- if (request.method === "POST" && url2.pathname === "/v1/deployments") {
61174
- const body = await this.readBody(request);
61175
- this.json(response, 200, this.startDeployment(body));
61176
- return;
61177
- }
61178
- const statusMatch = url2.pathname.match(/^\/v1\/deployments\/([A-Za-z0-9-]+)$/);
61179
- if (request.method === "GET" && statusMatch) {
61180
- const job = this.deployments.get(statusMatch[1]);
61181
- if (!job) {
61182
- this.json(response, 404, { error: `unknown deployment ${statusMatch[1]}` });
61183
- return;
61184
- }
61185
- this.json(response, 200, job);
61186
- return;
61187
- }
61188
- this.json(response, 404, { error: `unknown route ${request.method} ${url2.pathname}` });
61190
+ once(dispatch, handler) {
61191
+ this.emitter.once(dispatch, handler);
61189
61192
  }
61190
- profileInfo() {
61191
- return {
61192
- profile: this.profileName,
61193
- baseUrl: this.profile.kongBaseUrl,
61194
- userName: this.profile.userName,
61195
- docker: !(0, import_child_process2.spawnSync)("docker", ["--version"]).error,
61196
- python: !(0, import_child_process2.spawnSync)(this.pythonBin(), ["--version"]).error
61197
- };
61193
+ off(dispatch, handler) {
61194
+ this.emitter.off(dispatch, handler);
61198
61195
  }
61199
- /** Runs only src/main_test.py in a fresh venv and returns the raw output. */
61200
- async runTests(request) {
61201
- const workDir = this.materialize(request.files);
61202
- try {
61203
- const log = [];
61204
- const prepared = await this.prepareVenv(workDir, log);
61205
- if (prepared.exitCode !== 0) {
61206
- return { passed: false, output: log.join("\n") };
61207
- }
61208
- const result = await this.run(
61209
- this.venvPython(workDir),
61210
- ["-m", "pytest", import_path4.default.join("src", "main_test.py"), "-v"],
61211
- workDir
61212
- );
61213
- log.push(result.output);
61214
- return { passed: result.exitCode === 0, output: log.join("\n") };
61215
- } finally {
61216
- import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61217
- }
61196
+ complete() {
61197
+ this.emitter.removeAllListeners();
61218
61198
  }
61219
- /**
61220
- * Deployments are asynchronous: the ui polls GET /v1/deployments/{id} and
61221
- * renders the steps in the same progress dialog as the kong-build path.
61222
- */
61223
- startDeployment(request) {
61224
- const deploymentId = generateShortId();
61225
- const job = {
61226
- status: "pending",
61227
- steps: DEPLOY_STEPS.map((name) => ({ name, status: "idle" })),
61228
- output: ""
61229
- };
61230
- this.deployments.set(deploymentId, job);
61231
- this.deploy(request, job).catch((ex) => {
61232
- job.status = "failed";
61233
- job.error = ex.message;
61234
- for (const step of job.steps) {
61235
- if (step.status === "pending") {
61236
- step.status = "failed";
61237
- }
61238
- }
61239
- });
61240
- return { deploymentId };
61199
+ };
61200
+ function isObservable(obj) {
61201
+ return !!obj && typeof obj === "object" && typeof obj.subscribe === "function";
61202
+ }
61203
+ function isReadable(obj) {
61204
+ return !!obj && typeof obj === "object" && obj.readable === true && typeof obj.read === "function" && typeof obj.on === "function";
61205
+ }
61206
+ function isUnicodeSupported2() {
61207
+ return !!process.env["LISTR_FORCE_UNICODE"] || process.platform !== "win32" || !!process.env.CI || !!process.env.WT_SESSION || process.env.TERM_PROGRAM === "vscode" || process.env.TERM === "xterm-256color" || process.env.TERM === "alacritty";
61208
+ }
61209
+ var CLEAR_LINE_REGEX = "(?:\\u001b|\\u009b)\\[[\\=><~/#&.:=?%@~_-]*[0-9]*[\\a-ln-tqyz=><~/#&.:=?%@~_-]+";
61210
+ var BELL_REGEX = /\u0007/;
61211
+ function cleanseAnsi(chunk) {
61212
+ return String(chunk).replace(new RegExp(CLEAR_LINE_REGEX, "gmi"), "").replace(new RegExp(BELL_REGEX, "gmi"), "").trim();
61213
+ }
61214
+ var color = Object.fromEntries(Object.keys(import_node_util11.inspect.colors).map((color2) => [color2, (text) => (0, import_node_util11.styleText)(color2, String(text))]));
61215
+ function indent(string, count) {
61216
+ return string.replace(/^(?!\s*$)/gm, " ".repeat(count));
61217
+ }
61218
+ var FIGURES_MAIN = {
61219
+ warning: "\u26A0",
61220
+ cross: "\u2716",
61221
+ arrowDown: "\u2193",
61222
+ tick: "\u2714",
61223
+ arrowRight: "\u2192",
61224
+ pointer: "\u276F",
61225
+ checkboxOn: "\u2612",
61226
+ arrowLeft: "\u2190",
61227
+ squareSmallFilled: "\u25FC",
61228
+ pointerSmall: "\u203A"
61229
+ };
61230
+ var FIGURES_FALLBACK = {
61231
+ ...FIGURES_MAIN,
61232
+ warning: "\u203C",
61233
+ cross: "\xD7",
61234
+ tick: "\u221A",
61235
+ pointer: ">",
61236
+ checkboxOn: "[\xD7]",
61237
+ squareSmallFilled: "\u25A0"
61238
+ };
61239
+ var figures2 = isUnicodeSupported2() ? FIGURES_MAIN : FIGURES_FALLBACK;
61240
+ function splat(message2, ...splat2) {
61241
+ return (0, import_util4.format)(String(message2), ...splat2);
61242
+ }
61243
+ var LISTR_LOGGER_STYLE = {
61244
+ icon: {
61245
+ ["STARTED"]: figures2.pointer,
61246
+ ["FAILED"]: figures2.cross,
61247
+ ["SKIPPED"]: figures2.arrowDown,
61248
+ ["COMPLETED"]: figures2.tick,
61249
+ ["OUTPUT"]: figures2.pointerSmall,
61250
+ ["TITLE"]: figures2.arrowRight,
61251
+ ["RETRY"]: figures2.warning,
61252
+ ["ROLLBACK"]: figures2.arrowLeft,
61253
+ ["PAUSED"]: figures2.squareSmallFilled
61254
+ },
61255
+ color: {
61256
+ ["STARTED"]: color.yellow,
61257
+ ["FAILED"]: color.red,
61258
+ ["SKIPPED"]: color.yellow,
61259
+ ["COMPLETED"]: color.green,
61260
+ ["RETRY"]: color.yellowBright,
61261
+ ["ROLLBACK"]: color.redBright,
61262
+ ["PAUSED"]: color.yellowBright
61241
61263
  }
61242
- /**
61243
- * The client-side twin of the kong-build pipeline: docker build + push from
61244
- * this machine (requirements.txt applied), schema generated locally with
61245
- * `main.py --schema`, then the snapshot registered in kong-management.
61246
- */
61247
- async deploy(request, job) {
61248
- const step = (name) => notNullStep(job, name);
61249
- const runStep = async (name, action) => {
61250
- step(name).status = "pending";
61251
- try {
61252
- const result = await action();
61253
- step(name).status = "succeeded";
61254
- return result;
61255
- } catch (ex) {
61256
- step(name).status = "failed";
61257
- throw ex;
61258
- }
61264
+ };
61265
+ var LISTR_LOGGER_STDERR_LEVELS = [
61266
+ "RETRY",
61267
+ "ROLLBACK",
61268
+ "FAILED"
61269
+ ];
61270
+ var ListrLogger = class {
61271
+ options;
61272
+ process;
61273
+ constructor(options) {
61274
+ this.options = options;
61275
+ this.options = {
61276
+ useIcons: true,
61277
+ toStderr: [],
61278
+ ...options ?? {}
61259
61279
  };
61260
- const workDir = this.materialize(request.files);
61261
- try {
61262
- const log = [];
61263
- import_fs3.default.writeFileSync(import_path4.default.join(workDir, "Dockerfile"), DOCKERFILE);
61264
- await runStep("install dependencies", async () => {
61265
- const prepared = await this.prepareVenv(workDir, log);
61266
- job.output = log.join("\n");
61267
- if (prepared.exitCode !== 0) {
61268
- throw new Error(`dependency install failed:
61269
- ${log.join("\n")}`);
61270
- }
61271
- });
61272
- const contract = await runStep("generate schema", async () => {
61273
- const schema = await this.run(
61274
- this.venvPython(workDir),
61275
- [import_path4.default.join("src", "main.py"), "--schema"],
61276
- workDir
61277
- );
61278
- if (schema.exitCode !== 0) {
61279
- throw new Error(`schema generation failed:
61280
- ${schema.output}`);
61281
- }
61282
- return JSON.parse(schema.output);
61283
- });
61284
- const publishDetails = await runStep("get publish details", () => {
61285
- const tenant = parseTenant(this.profile.kongBaseUrl);
61286
- return this.registryClient.getPublishDetails(
61287
- `${tenant}-k-extension-${request.extensionId}`
61288
- );
61289
- });
61290
- const registryUrl = publishDetails.repoName === "docker-registry:5000" ? "localhost:5000" : publishDetails.repoName;
61291
- const imageName = `${registryUrl}/${publishDetails.imageName}:${publishDetails.imageVersion}`;
61292
- for (const dockerStep of [
61293
- {
61294
- title: "docker login",
61295
- command: "docker",
61296
- args: ["login", "-u", publishDetails.userName, "--password-stdin", registryUrl],
61297
- stdin: publishDetails.token
61298
- },
61299
- {
61300
- title: "docker build",
61301
- command: "docker",
61302
- args: ["build", "--network=host", "-t", imageName, "-f", "Dockerfile", "."]
61303
- },
61304
- { title: "docker push", command: "docker", args: ["push", imageName] }
61305
- ]) {
61306
- await runStep(dockerStep.title, async () => {
61307
- log.push(`> ${dockerStep.title}`);
61308
- const result = await this.run(
61309
- dockerStep.command,
61310
- dockerStep.args,
61311
- workDir,
61312
- dockerStep.stdin
61313
- );
61314
- log.push(result.output);
61315
- job.output = log.join("\n");
61316
- if (result.exitCode !== 0) {
61317
- throw new Error(`${dockerStep.title} failed:
61318
- ${result.output}`);
61319
- }
61320
- });
61321
- }
61322
- const version = Number(publishDetails.imageVersion);
61323
- await runStep(
61324
- "save publish details",
61325
- () => this.managementClient.createExtensionSnapshot(
61326
- request.extensionId,
61327
- this.snapshotFor(request, version, contract)
61328
- )
61329
- );
61330
- log.push(`the version ${version} has been successfully published!`);
61331
- job.output = log.join("\n");
61332
- job.version = version;
61333
- job.status = "succeeded";
61334
- } finally {
61335
- import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61336
- }
61280
+ this.options.fields ??= {};
61281
+ this.options.fields.prefix ??= [];
61282
+ this.options.fields.suffix ??= [];
61283
+ this.process = this.options.processOutput ?? new ProcessOutput();
61337
61284
  }
61338
- snapshotFor(request, version, contract) {
61339
- return {
61340
- extensionId: request.extensionId,
61341
- extensionName: request.extensionName,
61342
- sdk: "python",
61343
- inputSchema: contract.input,
61344
- outputSchema: contract.output,
61345
- metadata: {
61346
- id: request.extensionId,
61347
- name: request.extensionName,
61348
- sdk: "python",
61349
- settings: {
61350
- input: { filter: jqFilter(""), schema: contract.input },
61351
- output: { filter: jqFilter(""), schema: contract.output }
61352
- }
61353
- },
61354
- version,
61355
- notes: request.notes ?? "",
61356
- checkpoint: "",
61357
- created: utcNow(DEFAULT_TIMEZONE),
61358
- createdBy: ""
61359
- };
61360
- }
61361
- /** Writes the bundle to a fresh temp folder, decoding binary entries. */
61362
- materialize(files) {
61363
- const workDir = import_fs3.default.mkdtempSync(import_path4.default.join(import_os2.default.tmpdir(), `kong-connect-${generateShortId()}-`));
61364
- for (const file of files) {
61365
- const target = import_path4.default.resolve(workDir, file.name);
61366
- if (!target.startsWith(workDir)) {
61367
- continue;
61368
- }
61369
- import_fs3.default.mkdirSync(import_path4.default.dirname(target), { recursive: true });
61370
- import_fs3.default.writeFileSync(
61371
- target,
61372
- file.binary === true ? Buffer.from(file.content, "base64") : file.content
61373
- );
61285
+ log(level, message2, options) {
61286
+ const output = this.format(level, message2, options);
61287
+ if (this.options.toStderr.includes(level)) {
61288
+ this.process.toStderr(output);
61289
+ return;
61374
61290
  }
61375
- import_fs3.default.writeFileSync(import_path4.default.join(workDir, "pyproject.toml"), PYPROJECT);
61376
- return workDir;
61291
+ this.process.toStdout(output);
61377
61292
  }
61378
- async prepareVenv(workDir, log) {
61379
- const venv = await this.run(this.pythonBin(), ["-m", "venv", "--clear", ".venv"], workDir);
61380
- log.push(venv.output);
61381
- if (venv.exitCode !== 0) {
61382
- return venv;
61383
- }
61384
- const install = await this.run(
61385
- this.venvPython(workDir),
61386
- [
61387
- "-m",
61388
- "pip",
61389
- "install",
61390
- "--default-timeout=120",
61391
- "-r",
61392
- "requirements.txt",
61393
- ...TEST_DEPENDENCIES
61394
- ],
61395
- workDir
61396
- );
61397
- log.push(install.output);
61398
- return install;
61293
+ toStdout(message2, options, eol = true) {
61294
+ this.process.toStdout(this.format(null, message2, options), eol);
61399
61295
  }
61400
- pythonBin() {
61401
- return (0, import_child_process2.spawnSync)("python", ["--version"]).error ? "python3" : "python";
61296
+ toStderr(message2, options, eol = true) {
61297
+ this.process.toStderr(this.format(null, message2, options), eol);
61402
61298
  }
61403
- venvPython(workDir) {
61404
- return this.isWin ? import_path4.default.join(workDir, ".venv", "Scripts", "python.exe") : import_path4.default.join(workDir, ".venv", "bin", "python");
61299
+ wrap(message2, options) {
61300
+ if (!message2) return message2;
61301
+ return this.applyFormat(`[${message2}]`, options);
61405
61302
  }
61406
- run(command, args, cwd, stdin) {
61407
- return new Promise((resolve2) => {
61408
- const child = (0, import_child_process2.spawn)(command, args, { cwd });
61409
- const chunks = [];
61410
- child.stdout.on("data", (data) => chunks.push(String(data)));
61411
- child.stderr.on("data", (data) => chunks.push(String(data)));
61412
- child.on("error", (error) => resolve2({ exitCode: -1, output: String(error) }));
61413
- child.on("close", (exitCode) => resolve2({ exitCode: exitCode ?? -1, output: chunks.join("") }));
61414
- if (stdin !== void 0) {
61415
- child.stdin.write(stdin);
61303
+ splat(...args) {
61304
+ const message2 = args.shift() ?? "";
61305
+ return args.length === 0 ? message2 : splat(message2, args);
61306
+ }
61307
+ suffix(message2, ...suffixes) {
61308
+ suffixes.filter(Boolean).forEach((suffix) => {
61309
+ message2 += this.spacing(message2);
61310
+ if (typeof suffix === "string") message2 += this.wrap(suffix);
61311
+ else if (typeof suffix === "object") {
61312
+ suffix.args ??= [];
61313
+ if (typeof suffix.condition === "function" ? !suffix.condition(...suffix.args) : !(suffix.condition ?? true)) return message2;
61314
+ message2 += this.wrap(typeof suffix.field === "function" ? suffix.field(...suffix.args) : suffix.field, { format: suffix?.format(...suffix.args) });
61416
61315
  }
61417
- child.stdin.end();
61418
61316
  });
61317
+ return message2;
61419
61318
  }
61420
- readBody(request) {
61421
- return new Promise((resolve2, reject) => {
61422
- const chunks = [];
61423
- request.on("data", (chunk) => chunks.push(chunk));
61424
- request.on("error", reject);
61425
- request.on("end", () => {
61426
- try {
61427
- resolve2(JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}"));
61428
- } catch (ex) {
61429
- reject(ex instanceof Error ? ex : new Error(String(ex)));
61430
- }
61431
- });
61319
+ prefix(message2, ...prefixes) {
61320
+ prefixes.filter(Boolean).forEach((prefix) => {
61321
+ message2 = this.spacing(message2) + message2;
61322
+ if (typeof prefix === "string") message2 = this.wrap(prefix) + message2;
61323
+ else if (typeof prefix === "object") {
61324
+ prefix.args ??= [];
61325
+ if (typeof prefix.condition === "function" ? !prefix.condition(...prefix.args) : !(prefix.condition ?? true)) return message2;
61326
+ message2 = this.wrap(typeof prefix.field === "function" ? prefix.field(...prefix.args) : prefix.field, { format: prefix?.format() }) + message2;
61327
+ }
61432
61328
  });
61329
+ return message2;
61433
61330
  }
61434
- json(response, status, body) {
61435
- response.writeHead(status, { "Content-Type": "application/json" });
61436
- response.end(JSON.stringify(body));
61331
+ fields(message2, options) {
61332
+ if (this.options?.fields?.prefix) message2 = this.prefix(message2, ...this.options.fields.prefix);
61333
+ if (options?.prefix) message2 = this.prefix(message2, ...options.prefix);
61334
+ if (options?.suffix) message2 = this.suffix(message2, ...options.suffix);
61335
+ if (this.options?.fields?.suffix) message2 = this.suffix(message2, ...this.options.fields.suffix);
61336
+ return message2;
61337
+ }
61338
+ icon(level, icon) {
61339
+ if (!level) return null;
61340
+ if (!icon) {
61341
+ const i = this.options.icon?.[level];
61342
+ icon = typeof i === "function" ? i() : i;
61343
+ }
61344
+ const coloring = this.options.color?.[level];
61345
+ if (icon && coloring) icon = coloring(icon);
61346
+ return icon;
61347
+ }
61348
+ format(level, message2, options) {
61349
+ if (!Array.isArray(message2)) message2 = [message2];
61350
+ message2 = this.splat(message2.shift(), ...message2).toString().split(import_os2.EOL).filter((m) => !m || m.trim() !== "").map((m) => {
61351
+ return this.style(level, this.fields(m, {
61352
+ prefix: Array.isArray(options?.prefix) ? options.prefix : [options?.prefix],
61353
+ suffix: Array.isArray(options?.suffix) ? options.suffix : [options?.suffix]
61354
+ }));
61355
+ }).join(import_os2.EOL);
61356
+ return message2;
61357
+ }
61358
+ style(level, message2) {
61359
+ if (!level || !message2) return message2;
61360
+ const icon = this.icon(level, !this.options.useIcons && this.wrap(level));
61361
+ if (icon) message2 = icon + " " + message2;
61362
+ return message2;
61363
+ }
61364
+ applyFormat(message2, options) {
61365
+ if (options?.format) return options.format(message2);
61366
+ return message2;
61367
+ }
61368
+ spacing(message2) {
61369
+ return typeof message2 === "undefined" || message2.trim() === "" ? "" : " ";
61437
61370
  }
61438
61371
  };
61439
-
61440
- // packages/kong-cli/src/commands/generateCommand.ts
61441
- var import_create_nx_workspace = require("create-nx-workspace");
61442
-
61443
- // packages/kong-cli/src/common/kongJson.ts
61444
- var import_ajv = __toESM(require_ajv());
61445
- var import_fs4 = __toESM(require("fs"));
61446
-
61447
- // packages/kong-cli/src/common/kongJsonSchema.ts
61448
- var KONG_JSON_SCHEMA = {
61449
- $schema: "http://json-schema.org/draft-07/schema#",
61450
- type: "object",
61451
- properties: {
61452
- id: {
61453
- type: "string"
61454
- },
61455
- name: {
61456
- type: "string"
61457
- },
61458
- sdk: {
61459
- type: "string",
61460
- enum: ["python", "kotlin"]
61461
- },
61462
- category: {
61463
- type: "string"
61464
- },
61465
- settings: {
61466
- type: "object",
61467
- properties: {
61468
- input: {
61469
- type: "object",
61470
- properties: {
61471
- filter: {
61472
- type: "string"
61473
- },
61474
- schema: {
61475
- $ref: "http://json-schema.org/draft-07/schema#"
61476
- }
61477
- },
61478
- required: ["schema", "filter"]
61479
- },
61480
- output: {
61481
- type: "object",
61482
- properties: {
61483
- filter: {
61484
- type: "string"
61485
- },
61486
- schema: {
61487
- $ref: "http://json-schema.org/draft-07/schema#"
61488
- }
61489
- },
61490
- required: ["schema", "filter"]
61491
- },
61492
- invoke: {
61493
- type: "object",
61494
- properties: {
61495
- prefix: {
61496
- type: "string"
61497
- },
61498
- cache: {
61499
- type: "object",
61500
- properties: {
61501
- enabled: {
61502
- type: "boolean"
61503
- },
61504
- key: {
61505
- type: ["string"]
61506
- },
61507
- ttl: {
61508
- type: "string"
61509
- },
61510
- onFailure: {
61511
- type: "string",
61512
- enum: ["skip", "retry"]
61513
- }
61514
- },
61515
- required: ["enabled", "key", "ttl", "onFailure"]
61516
- },
61517
- retry: {
61518
- type: "object",
61519
- properties: {
61520
- maxAttempts: {
61521
- type: "number"
61522
- },
61523
- attemptDelay: {
61524
- type: "string"
61525
- },
61526
- attemptTimeout: {
61527
- type: "string"
61528
- }
61529
- },
61530
- required: ["maxAttempts", "attemptDelay", "attemptTimeout"]
61531
- },
61532
- circuitBreaker: {
61533
- type: "object",
61534
- properties: {
61535
- enabled: {
61536
- type: "boolean"
61537
- },
61538
- requestVolumeThreshold: {
61539
- type: "number"
61540
- },
61541
- failureRatio: {
61542
- type: "number"
61543
- },
61544
- successThreshold: {
61545
- type: "number"
61546
- }
61547
- },
61548
- required: ["enabled", "requestVolumeThreshold", "failureRatio", "successThreshold"]
61549
- }
61550
- }
61551
- }
61552
- },
61553
- additionalProperties: false
61554
- }
61555
- },
61556
- additionalProperties: false,
61557
- required: ["id", "name", "sdk", "category"]
61558
- };
61559
-
61560
- // packages/kong-cli/src/common/kongJson.ts
61561
- var ajv = new import_ajv.default();
61562
- var validate2 = ajv.compile(KONG_JSON_SCHEMA);
61563
- var SUPPORTED_SDK = ["kotlin", "python"];
61564
- function validateKongJson(kongJson) {
61565
- if (isEmpty(kongJson.id)) {
61566
- throw new AppError(
61567
- "The `id` field should not be empty. Please provide a valid identifier in kong.json."
61568
- );
61372
+ var ProcessOutputBuffer = class {
61373
+ options;
61374
+ buffer = [];
61375
+ decoder = new import_string_decoder.StringDecoder();
61376
+ constructor(options) {
61377
+ this.options = options;
61569
61378
  }
61570
- if (isEmpty(kongJson.category)) {
61571
- throw new AppError(
61572
- "The `category` field should not be empty. Please provide a category value in kong.json."
61573
- );
61379
+ get all() {
61380
+ return this.buffer;
61574
61381
  }
61575
- if (!/^[a-z][a-z0-9]{11}$/.test(kongJson.id)) {
61576
- throw new AppError(
61577
- "The id must be exactly 12 characters long and consist of alphanumeric characters (lowercase letters and digits). It must start with a letter. Ensure the ID does not exceed 12 characters. Please provide a valid identifier in kong.json"
61578
- );
61382
+ get last() {
61383
+ return this.buffer.at(-1);
61579
61384
  }
61580
- if (!SUPPORTED_SDK.includes(kongJson.sdk)) {
61581
- throw new AppError(
61582
- `Unexpected SDK value: ${kongJson.sdk}. Supported SDK: ${SUPPORTED_SDK}.Please provide a valid identifier in kong.json.`
61583
- );
61385
+ get length() {
61386
+ return this.buffer.length;
61584
61387
  }
61585
- if (isEmpty(kongJson.name)) {
61586
- throw new AppError(
61587
- "The `name` field should not be empty. Please provide a valid name in kong.json."
61588
- );
61388
+ write(data, ...args) {
61389
+ const callback = args[args.length - 1];
61390
+ this.buffer.push({
61391
+ time: Date.now(),
61392
+ stream: this.options?.stream,
61393
+ entry: this.decoder.write(typeof data === "string" ? Buffer.from(data, typeof args[0] === "string" ? args[0] : void 0) : Buffer.from(data))
61394
+ });
61395
+ if (this.options?.limit) this.buffer = this.buffer.slice(-this.options.limit);
61396
+ if (typeof callback === "function") callback();
61397
+ return true;
61589
61398
  }
61590
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(kongJson.name)) {
61591
- throw new AppError(
61592
- "The `name` should only contain lowercase letters, digits, and dashes. Dashes can only appear between alphanumeric characters, and the name cannot start or end with a dash.Please provide a valid name in kong.json."
61593
- );
61399
+ reset() {
61400
+ this.buffer = [];
61594
61401
  }
61595
- const isValid2 = validate2(kongJson);
61596
- if (!isValid2) {
61597
- throw new AppError(
61598
- "The provided `kong.json` does not follow the expected JSON schema. Errors: \n" + prettyJsonObject(validate2.errors || [])
61599
- );
61402
+ };
61403
+ var ProcessOutputStream = class {
61404
+ stream;
61405
+ method;
61406
+ buffer;
61407
+ constructor(stream4) {
61408
+ this.stream = stream4;
61409
+ this.method = stream4.write;
61410
+ this.buffer = new ProcessOutputBuffer({ stream: stream4 });
61600
61411
  }
61601
- return kongJson;
61602
- }
61603
- function getKongJson() {
61604
- const kongJsonPath = resolveProjectPath("kong.json");
61605
- try {
61606
- const fileContent = import_fs4.default.readFileSync(kongJsonPath, "utf-8");
61607
- const kongJson = JSON.parse(fileContent);
61608
- return validateKongJson(kongJson);
61609
- } catch (ex) {
61610
- if (ex instanceof SyntaxError) {
61611
- throw new AppError(`Error parsing kong.json: ${ex.message}`);
61612
- }
61613
- throw ex;
61412
+ get out() {
61413
+ const self2 = this;
61414
+ return new Proxy(this.stream, { get(target, prop, receiver) {
61415
+ if (prop === "write") return self2.write.bind(self2);
61416
+ return Reflect.get(target, prop, receiver);
61417
+ } });
61614
61418
  }
61615
- }
61616
-
61617
- // packages/kong-cli/src/commands/generateCommand.ts
61618
- var GenerateCommand = class {
61619
- async execute(extensionName, sdk, presetVersion, template2) {
61620
- const id = generateShortId();
61621
- const variant = sdk === "python" ? template2 ?? await this.promptTemplate() : "basic";
61622
- validateKongJson({
61623
- id,
61624
- sdk,
61625
- name: extensionName,
61626
- category: "unknown",
61627
- settings: {}
61628
- });
61629
- await (0, import_create_nx_workspace.createWorkspace)(`@devkong/cli-nx@${presetVersion}`, {
61630
- name: extensionName,
61631
- id,
61632
- platform: sdk,
61633
- // Passed through to the preset generator. Not named `template` on purpose:
61634
- // create-nx-workspace reserves that option for cloning a GitHub workspace.
61635
- variant,
61636
- nxCloud: "skip",
61637
- packageManager: "npm",
61638
- trustThirdPartyPreset: true,
61639
- analytics: false
61640
- });
61419
+ hijack() {
61420
+ this.stream.write = this.buffer.write.bind(this.buffer);
61641
61421
  }
61642
- async promptTemplate() {
61643
- const { template: template2 } = await dist_default14.prompt({
61644
- type: "select",
61645
- name: "template",
61646
- message: "which template would you like to use?",
61647
- default: "basic",
61648
- choices: [
61649
- { name: "basic - a single operation", value: "basic" },
61650
- {
61651
- name: "with-secret - multiple operations with a secret example",
61652
- value: "with-secret"
61653
- },
61654
- {
61655
- name: "with-s3 - download a file from S3 using an s3 secret",
61656
- value: "with-s3"
61657
- }
61658
- ]
61659
- });
61660
- return template2;
61422
+ release() {
61423
+ this.stream.write = this.method;
61424
+ const buffer = [...this.buffer.all];
61425
+ this.buffer.reset();
61426
+ return buffer;
61427
+ }
61428
+ write(...args) {
61429
+ return this.method.apply(this.stream, args);
61661
61430
  }
61662
61431
  };
61663
-
61664
- // node_modules/listr2/node_modules/eventemitter3/index.mjs
61665
- var import_index = __toESM(require_eventemitter3(), 1);
61666
- var eventemitter3_default = import_index.default;
61667
-
61668
- // node_modules/listr2/dist/index.mjs
61669
- var import_node_util11 = require("node:util");
61670
- var import_util4 = require("util");
61671
- var import_os3 = require("os");
61672
- var import_string_decoder = require("string_decoder");
61673
- var import_stream5 = require("stream");
61674
- var import_rfdc = __toESM(require_rfdc(), 1);
61675
- var import_crypto2 = require("crypto");
61676
- var ANSI_ESCAPE_CODES = {
61677
- CURSOR_HIDE: "\x1B[?25l",
61678
- CURSOR_SHOW: "\x1B[?25h"
61679
- };
61680
- var ListrTaskState = /* @__PURE__ */ (function(ListrTaskState2) {
61681
- ListrTaskState2["WAITING"] = "WAITING";
61682
- ListrTaskState2["STARTED"] = "STARTED";
61683
- ListrTaskState2["COMPLETED"] = "COMPLETED";
61684
- ListrTaskState2["FAILED"] = "FAILED";
61685
- ListrTaskState2["SKIPPED"] = "SKIPPED";
61686
- ListrTaskState2["ROLLING_BACK"] = "ROLLING_BACK";
61687
- ListrTaskState2["ROLLED_BACK"] = "ROLLED_BACK";
61688
- ListrTaskState2["RETRY"] = "RETRY";
61689
- ListrTaskState2["PAUSED"] = "PAUSED";
61690
- ListrTaskState2["PROMPT"] = "PROMPT";
61691
- ListrTaskState2["PROMPT_COMPLETED"] = "PROMPT_COMPLETED";
61692
- ListrTaskState2["PROMPT_FAILED"] = "PROMPT_FAILED";
61693
- return ListrTaskState2;
61694
- })({});
61695
- var EventManager = class {
61696
- emitter = new eventemitter3_default();
61697
- emit(dispatch, args) {
61698
- this.emitter.emit(dispatch, args);
61432
+ var ProcessOutput = class {
61433
+ options;
61434
+ stream;
61435
+ active;
61436
+ constructor(stdout, stderr, options) {
61437
+ this.options = options;
61438
+ this.stream = {
61439
+ stdout: new ProcessOutputStream(stdout ?? process.stdout),
61440
+ stderr: new ProcessOutputStream(stderr ?? process.stderr)
61441
+ };
61442
+ this.options = {
61443
+ dump: ["stdout", "stderr"],
61444
+ leaveEmptyLine: true,
61445
+ ...options
61446
+ };
61699
61447
  }
61700
- on(dispatch, handler) {
61701
- this.emitter.addListener(dispatch, handler);
61448
+ get stdout() {
61449
+ return this.stream.stdout.out;
61702
61450
  }
61703
- once(dispatch, handler) {
61704
- this.emitter.once(dispatch, handler);
61451
+ get stderr() {
61452
+ return this.stream.stderr.out;
61705
61453
  }
61706
- off(dispatch, handler) {
61707
- this.emitter.off(dispatch, handler);
61454
+ hijack() {
61455
+ if (this.active) throw new Error("ProcessOutput has been already hijacked!");
61456
+ this.stream.stdout.write(ANSI_ESCAPE_CODES.CURSOR_HIDE);
61457
+ Object.values(this.stream).forEach((stream4) => stream4.hijack());
61458
+ this.active = true;
61708
61459
  }
61709
- complete() {
61710
- this.emitter.removeAllListeners();
61460
+ release() {
61461
+ const output = Object.entries(this.stream).map(([name, stream4]) => ({
61462
+ name,
61463
+ buffer: stream4.release()
61464
+ })).filter((output2) => this.options.dump.includes(output2.name)).flatMap((output2) => output2.buffer).sort((a, b) => a.time - b.time).map((message2) => {
61465
+ return {
61466
+ ...message2,
61467
+ entry: cleanseAnsi(message2.entry)
61468
+ };
61469
+ }).filter((message2) => message2.entry);
61470
+ if (output.length > 0) {
61471
+ if (this.options.leaveEmptyLine) this.stdout.write(import_os2.EOL);
61472
+ output.forEach((message2) => {
61473
+ (message2.stream ?? this.stdout).write(message2.entry + import_os2.EOL);
61474
+ });
61475
+ }
61476
+ this.stream.stdout.write(ANSI_ESCAPE_CODES.CURSOR_SHOW);
61477
+ this.active = false;
61478
+ }
61479
+ toStdout(buffer, eol = true) {
61480
+ if (eol) buffer = buffer + import_os2.EOL;
61481
+ return this.stream.stdout.write(buffer);
61482
+ }
61483
+ toStderr(buffer, eol = true) {
61484
+ if (eol) buffer = buffer + import_os2.EOL;
61485
+ return this.stream.stderr.write(buffer);
61711
61486
  }
61712
61487
  };
61713
- function isObservable(obj) {
61714
- return !!obj && typeof obj === "object" && typeof obj.subscribe === "function";
61715
- }
61716
- function isReadable(obj) {
61717
- return !!obj && typeof obj === "object" && obj.readable === true && typeof obj.read === "function" && typeof obj.on === "function";
61718
- }
61719
- function isUnicodeSupported2() {
61720
- return !!process.env["LISTR_FORCE_UNICODE"] || process.platform !== "win32" || !!process.env.CI || !!process.env.WT_SESSION || process.env.TERM_PROGRAM === "vscode" || process.env.TERM === "xterm-256color" || process.env.TERM === "alacritty";
61721
- }
61722
- var CLEAR_LINE_REGEX = "(?:\\u001b|\\u009b)\\[[\\=><~/#&.:=?%@~_-]*[0-9]*[\\a-ln-tqyz=><~/#&.:=?%@~_-]+";
61723
- var BELL_REGEX = /\u0007/;
61724
- function cleanseAnsi(chunk) {
61725
- return String(chunk).replace(new RegExp(CLEAR_LINE_REGEX, "gmi"), "").replace(new RegExp(BELL_REGEX, "gmi"), "").trim();
61726
- }
61727
- var color = Object.fromEntries(Object.keys(import_node_util11.inspect.colors).map((color2) => [color2, (text) => (0, import_node_util11.styleText)(color2, String(text))]));
61728
- function indent(string, count) {
61729
- return string.replace(/^(?!\s*$)/gm, " ".repeat(count));
61488
+ function createWritable(cb) {
61489
+ const writable = new import_stream5.Writable();
61490
+ writable.rows = Infinity;
61491
+ writable.columns = Infinity;
61492
+ writable.write = (chunk) => {
61493
+ cb(chunk.toString());
61494
+ return true;
61495
+ };
61496
+ return writable;
61730
61497
  }
61731
- var FIGURES_MAIN = {
61732
- warning: "\u26A0",
61733
- cross: "\u2716",
61734
- arrowDown: "\u2193",
61735
- tick: "\u2714",
61736
- arrowRight: "\u2192",
61737
- pointer: "\u276F",
61738
- checkboxOn: "\u2612",
61739
- arrowLeft: "\u2190",
61740
- squareSmallFilled: "\u25FC",
61741
- pointerSmall: "\u203A"
61742
- };
61743
- var FIGURES_FALLBACK = {
61744
- ...FIGURES_MAIN,
61745
- warning: "\u203C",
61746
- cross: "\xD7",
61747
- tick: "\u221A",
61748
- pointer: ">",
61749
- checkboxOn: "[\xD7]",
61750
- squareSmallFilled: "\u25A0"
61498
+ var Spinner = class {
61499
+ spinner = !isUnicodeSupported2() ? [
61500
+ "-",
61501
+ "\\",
61502
+ "|",
61503
+ "/"
61504
+ ] : [
61505
+ "\u280B",
61506
+ "\u2819",
61507
+ "\u2839",
61508
+ "\u2838",
61509
+ "\u283C",
61510
+ "\u2834",
61511
+ "\u2826",
61512
+ "\u2827",
61513
+ "\u2807",
61514
+ "\u280F"
61515
+ ];
61516
+ id;
61517
+ spinnerPosition = 0;
61518
+ spin() {
61519
+ this.spinnerPosition = ++this.spinnerPosition % this.spinner.length;
61520
+ }
61521
+ fetch() {
61522
+ return this.spinner[this.spinnerPosition];
61523
+ }
61524
+ isRunning() {
61525
+ return !!this.id;
61526
+ }
61527
+ start(cb, interval = 100) {
61528
+ this.id = setInterval(() => {
61529
+ this.spin();
61530
+ if (cb) cb();
61531
+ }, interval);
61532
+ }
61533
+ stop() {
61534
+ clearInterval(this.id);
61535
+ this.id = void 0;
61536
+ }
61751
61537
  };
61752
- var figures2 = isUnicodeSupported2() ? FIGURES_MAIN : FIGURES_FALLBACK;
61753
- function splat(message2, ...splat2) {
61754
- return (0, import_util4.format)(String(message2), ...splat2);
61755
- }
61756
- var LISTR_LOGGER_STYLE = {
61538
+ var LISTR_DEFAULT_RENDERER_STYLE = {
61757
61539
  icon: {
61758
- ["STARTED"]: figures2.pointer,
61759
- ["FAILED"]: figures2.cross,
61760
- ["SKIPPED"]: figures2.arrowDown,
61761
- ["COMPLETED"]: figures2.tick,
61540
+ ["SKIPPED_WITH_COLLAPSE"]: figures2.arrowDown,
61541
+ ["SKIPPED_WITHOUT_COLLAPSE"]: figures2.warning,
61762
61542
  ["OUTPUT"]: figures2.pointerSmall,
61763
- ["TITLE"]: figures2.arrowRight,
61543
+ ["OUTPUT_WITH_BOTTOMBAR"]: figures2.pointerSmall,
61544
+ ["PENDING"]: figures2.pointer,
61545
+ ["COMPLETED"]: figures2.tick,
61546
+ ["COMPLETED_WITH_FAILED_SUBTASKS"]: figures2.warning,
61547
+ ["COMPLETED_WITH_SISTER_TASKS_FAILED"]: figures2.squareSmallFilled,
61764
61548
  ["RETRY"]: figures2.warning,
61765
- ["ROLLBACK"]: figures2.arrowLeft,
61549
+ ["ROLLING_BACK"]: figures2.warning,
61550
+ ["ROLLED_BACK"]: figures2.arrowLeft,
61551
+ ["FAILED"]: figures2.cross,
61552
+ ["FAILED_WITH_SUBTASKS"]: figures2.pointer,
61553
+ ["WAITING"]: figures2.squareSmallFilled,
61766
61554
  ["PAUSED"]: figures2.squareSmallFilled
61767
61555
  },
61768
61556
  color: {
61769
- ["STARTED"]: color.yellow,
61770
- ["FAILED"]: color.red,
61771
- ["SKIPPED"]: color.yellow,
61557
+ ["SKIPPED_WITH_COLLAPSE"]: color.yellow,
61558
+ ["SKIPPED_WITHOUT_COLLAPSE"]: color.yellow,
61559
+ ["PENDING"]: color.yellow,
61772
61560
  ["COMPLETED"]: color.green,
61561
+ ["COMPLETED_WITH_FAILED_SUBTASKS"]: color.yellow,
61562
+ ["COMPLETED_WITH_SISTER_TASKS_FAILED"]: color.red,
61773
61563
  ["RETRY"]: color.yellowBright,
61774
- ["ROLLBACK"]: color.redBright,
61564
+ ["ROLLING_BACK"]: color.redBright,
61565
+ ["ROLLED_BACK"]: color.redBright,
61566
+ ["FAILED"]: color.red,
61567
+ ["FAILED_WITH_SUBTASKS"]: color.red,
61568
+ ["WAITING"]: color.dim,
61775
61569
  ["PAUSED"]: color.yellowBright
61776
61570
  }
61777
61571
  };
61778
- var LISTR_LOGGER_STDERR_LEVELS = [
61779
- "RETRY",
61780
- "ROLLBACK",
61781
- "FAILED"
61782
- ];
61783
- var ListrLogger = class {
61572
+ function parseTimer(duration) {
61573
+ const seconds = Math.floor(duration / 1e3);
61574
+ const minutes = Math.floor(seconds / 60);
61575
+ let parsedTime;
61576
+ if (seconds === 0 && minutes === 0) parsedTime = `0.${Math.floor(duration / 100)}s`;
61577
+ if (seconds > 0) parsedTime = `${seconds % 60}s`;
61578
+ if (minutes > 0) parsedTime = `${minutes}m${parsedTime}`;
61579
+ return parsedTime;
61580
+ }
61581
+ var PRESET_TIMER = {
61582
+ condition: true,
61583
+ field: parseTimer,
61584
+ format: () => color.dim
61585
+ };
61586
+ var DefaultRenderer = class DefaultRenderer2 {
61587
+ tasks;
61784
61588
  options;
61785
- process;
61786
- constructor(options) {
61787
- this.options = options;
61788
- this.options = {
61789
- useIcons: true,
61790
- toStderr: [],
61791
- ...options ?? {}
61792
- };
61793
- this.options.fields ??= {};
61794
- this.options.fields.prefix ??= [];
61795
- this.options.fields.suffix ??= [];
61796
- this.process = this.options.processOutput ?? new ProcessOutput();
61797
- }
61798
- log(level, message2, options) {
61799
- const output = this.format(level, message2, options);
61800
- if (this.options.toStderr.includes(level)) {
61801
- this.process.toStderr(output);
61802
- return;
61589
+ events;
61590
+ static nonTTY = false;
61591
+ static rendererOptions = {
61592
+ indentation: 2,
61593
+ clearOutput: false,
61594
+ showSubtasks: true,
61595
+ collapseSubtasks: true,
61596
+ collapseSkips: true,
61597
+ showSkipMessage: true,
61598
+ suffixSkips: false,
61599
+ collapseErrors: true,
61600
+ showErrorMessage: true,
61601
+ suffixRetries: true,
61602
+ lazy: false,
61603
+ removeEmptyLines: true,
61604
+ formatOutput: "wrap",
61605
+ pausedTimer: {
61606
+ ...PRESET_TIMER,
61607
+ format: () => color.yellowBright
61803
61608
  }
61804
- this.process.toStdout(output);
61805
- }
61806
- toStdout(message2, options, eol = true) {
61807
- this.process.toStdout(this.format(null, message2, options), eol);
61808
- }
61809
- toStderr(message2, options, eol = true) {
61810
- this.process.toStderr(this.format(null, message2, options), eol);
61811
- }
61812
- wrap(message2, options) {
61813
- if (!message2) return message2;
61814
- return this.applyFormat(`[${message2}]`, options);
61815
- }
61816
- splat(...args) {
61817
- const message2 = args.shift() ?? "";
61818
- return args.length === 0 ? message2 : splat(message2, args);
61819
- }
61820
- suffix(message2, ...suffixes) {
61821
- suffixes.filter(Boolean).forEach((suffix) => {
61822
- message2 += this.spacing(message2);
61823
- if (typeof suffix === "string") message2 += this.wrap(suffix);
61824
- else if (typeof suffix === "object") {
61825
- suffix.args ??= [];
61826
- if (typeof suffix.condition === "function" ? !suffix.condition(...suffix.args) : !(suffix.condition ?? true)) return message2;
61827
- message2 += this.wrap(typeof suffix.field === "function" ? suffix.field(...suffix.args) : suffix.field, { format: suffix?.format(...suffix.args) });
61609
+ };
61610
+ static rendererTaskOptions = { outputBar: true };
61611
+ prompt;
61612
+ activePrompt;
61613
+ spinner;
61614
+ logger;
61615
+ updater;
61616
+ truncate;
61617
+ wrap;
61618
+ buffer = {
61619
+ output: /* @__PURE__ */ new Map(),
61620
+ bottom: /* @__PURE__ */ new Map()
61621
+ };
61622
+ cache = {
61623
+ render: /* @__PURE__ */ new Map(),
61624
+ rendererOptions: /* @__PURE__ */ new Map(),
61625
+ rendererTaskOptions: /* @__PURE__ */ new Map()
61626
+ };
61627
+ constructor(tasks, options, events) {
61628
+ this.tasks = tasks;
61629
+ this.options = options;
61630
+ this.events = events;
61631
+ this.options = {
61632
+ ...DefaultRenderer2.rendererOptions,
61633
+ ...this.options,
61634
+ icon: {
61635
+ ...LISTR_DEFAULT_RENDERER_STYLE.icon,
61636
+ ...options?.icon ?? {}
61637
+ },
61638
+ color: {
61639
+ ...LISTR_DEFAULT_RENDERER_STYLE.color,
61640
+ ...options?.color ?? {}
61828
61641
  }
61642
+ };
61643
+ this.spinner = this.options.spinner ?? new Spinner();
61644
+ this.logger = this.options.logger ?? new ListrLogger({
61645
+ useIcons: true,
61646
+ toStderr: []
61829
61647
  });
61830
- return message2;
61648
+ this.logger.options.icon = this.options.icon;
61649
+ this.logger.options.color = this.options.color;
61831
61650
  }
61832
- prefix(message2, ...prefixes) {
61833
- prefixes.filter(Boolean).forEach((prefix) => {
61834
- message2 = this.spacing(message2) + message2;
61835
- if (typeof prefix === "string") message2 = this.wrap(prefix) + message2;
61836
- else if (typeof prefix === "object") {
61837
- prefix.args ??= [];
61838
- if (typeof prefix.condition === "function" ? !prefix.condition(...prefix.args) : !(prefix.condition ?? true)) return message2;
61839
- message2 = this.wrap(typeof prefix.field === "function" ? prefix.field(...prefix.args) : prefix.field, { format: prefix?.format() }) + message2;
61840
- }
61651
+ async render() {
61652
+ const { createLogUpdate: createLogUpdate2 } = await Promise.resolve().then(() => (init_log_update(), log_update_exports));
61653
+ const { default: truncate } = await Promise.resolve().then(() => (init_cli_truncate(), cli_truncate_exports));
61654
+ const { default: wrap } = await Promise.resolve().then(() => (init_wrap_ansi2(), wrap_ansi_exports));
61655
+ this.updater = createLogUpdate2(this.logger.process.stdout);
61656
+ this.truncate = truncate;
61657
+ this.wrap = wrap;
61658
+ this.logger.process.hijack();
61659
+ if (!this.options?.lazy) this.spinner.start(() => {
61660
+ this.update();
61661
+ });
61662
+ this.events.on("SHOUD_REFRESH_RENDER", () => {
61663
+ this.update();
61841
61664
  });
61842
- return message2;
61843
61665
  }
61844
- fields(message2, options) {
61845
- if (this.options?.fields?.prefix) message2 = this.prefix(message2, ...this.options.fields.prefix);
61846
- if (options?.prefix) message2 = this.prefix(message2, ...options.prefix);
61847
- if (options?.suffix) message2 = this.suffix(message2, ...options.suffix);
61848
- if (this.options?.fields?.suffix) message2 = this.suffix(message2, ...this.options.fields.suffix);
61849
- return message2;
61666
+ update() {
61667
+ this.updater(this.create());
61850
61668
  }
61851
- icon(level, icon) {
61852
- if (!level) return null;
61853
- if (!icon) {
61854
- const i = this.options.icon?.[level];
61855
- icon = typeof i === "function" ? i() : i;
61669
+ end() {
61670
+ this.spinner.stop();
61671
+ this.updater.clear();
61672
+ this.updater.done();
61673
+ if (!this.options.clearOutput) this.logger.process.toStdout(this.create({ prompt: false }));
61674
+ this.logger.process.release();
61675
+ }
61676
+ create(options) {
61677
+ options = {
61678
+ tasks: true,
61679
+ bottomBar: true,
61680
+ prompt: true,
61681
+ ...options
61682
+ };
61683
+ const render = [];
61684
+ const renderTasks = this.renderer(this.tasks);
61685
+ const renderBottomBar = this.renderBottomBar();
61686
+ const renderPrompt = this.renderPrompt();
61687
+ if (options.tasks && renderTasks.length > 0) render.push(...renderTasks);
61688
+ if (options.bottomBar && renderBottomBar.length > 0) {
61689
+ if (render.length > 0) render.push("");
61690
+ render.push(...renderBottomBar);
61856
61691
  }
61857
- const coloring = this.options.color?.[level];
61858
- if (icon && coloring) icon = coloring(icon);
61859
- return icon;
61692
+ if (options.prompt && renderPrompt.length > 0) {
61693
+ if (render.length > 0) render.push("");
61694
+ render.push(...renderPrompt);
61695
+ }
61696
+ return render.join(import_os2.EOL);
61860
61697
  }
61861
- format(level, message2, options) {
61862
- if (!Array.isArray(message2)) message2 = [message2];
61863
- message2 = this.splat(message2.shift(), ...message2).toString().split(import_os3.EOL).filter((m) => !m || m.trim() !== "").map((m) => {
61864
- return this.style(level, this.fields(m, {
61865
- prefix: Array.isArray(options?.prefix) ? options.prefix : [options?.prefix],
61866
- suffix: Array.isArray(options?.suffix) ? options.suffix : [options?.suffix]
61867
- }));
61868
- }).join(import_os3.EOL);
61869
- return message2;
61698
+ style(task, output = false) {
61699
+ const rendererOptions = this.cache.rendererOptions.get(task.id);
61700
+ if (task.isSkipped()) {
61701
+ if (output || rendererOptions.collapseSkips) return this.logger.icon("SKIPPED_WITH_COLLAPSE");
61702
+ else if (rendererOptions.collapseSkips === false) return this.logger.icon("SKIPPED_WITHOUT_COLLAPSE");
61703
+ }
61704
+ if (output) {
61705
+ if (this.shouldOutputToBottomBar(task)) return this.logger.icon("OUTPUT_WITH_BOTTOMBAR");
61706
+ return this.logger.icon("OUTPUT");
61707
+ }
61708
+ if (task.hasSubtasks()) {
61709
+ if (task.isStarted() || task.isPrompt() && rendererOptions.showSubtasks !== false && !task.subtasks.every((subtask) => !subtask.hasTitle())) return this.logger.icon("PENDING");
61710
+ else if (task.isCompleted() && task.subtasks.some((subtask) => subtask.hasFailed())) return this.logger.icon("COMPLETED_WITH_FAILED_SUBTASKS");
61711
+ else if (task.hasFailed()) return this.logger.icon("FAILED_WITH_SUBTASKS");
61712
+ }
61713
+ if (task.isStarted() || task.isPrompt()) return this.logger.icon("PENDING", !this.options?.lazy && this.spinner.fetch());
61714
+ else if (task.isCompleted()) return this.logger.icon("COMPLETED");
61715
+ else if (task.isRetrying()) return this.logger.icon("RETRY", !this.options?.lazy && this.spinner.fetch());
61716
+ else if (task.isRollingBack()) return this.logger.icon("ROLLING_BACK", !this.options?.lazy && this.spinner.fetch());
61717
+ else if (task.hasRolledBack()) return this.logger.icon("ROLLED_BACK");
61718
+ else if (task.hasFailed()) return this.logger.icon("FAILED");
61719
+ else if (task.isPaused()) return this.logger.icon("PAUSED");
61720
+ return this.logger.icon("WAITING");
61870
61721
  }
61871
- style(level, message2) {
61872
- if (!level || !message2) return message2;
61873
- const icon = this.icon(level, !this.options.useIcons && this.wrap(level));
61722
+ format(message2, icon, level) {
61723
+ if (message2.trim() === "") return [];
61874
61724
  if (icon) message2 = icon + " " + message2;
61875
- return message2;
61876
- }
61877
- applyFormat(message2, options) {
61878
- if (options?.format) return options.format(message2);
61879
- return message2;
61880
- }
61881
- spacing(message2) {
61882
- return typeof message2 === "undefined" || message2.trim() === "" ? "" : " ";
61883
- }
61884
- };
61885
- var ProcessOutputBuffer = class {
61886
- options;
61887
- buffer = [];
61888
- decoder = new import_string_decoder.StringDecoder();
61889
- constructor(options) {
61890
- this.options = options;
61891
- }
61892
- get all() {
61893
- return this.buffer;
61894
- }
61895
- get last() {
61896
- return this.buffer.at(-1);
61897
- }
61898
- get length() {
61899
- return this.buffer.length;
61900
- }
61901
- write(data, ...args) {
61902
- const callback = args[args.length - 1];
61903
- this.buffer.push({
61904
- time: Date.now(),
61905
- stream: this.options?.stream,
61906
- entry: this.decoder.write(typeof data === "string" ? Buffer.from(data, typeof args[0] === "string" ? args[0] : void 0) : Buffer.from(data))
61907
- });
61908
- if (this.options?.limit) this.buffer = this.buffer.slice(-this.options.limit);
61909
- if (typeof callback === "function") callback();
61910
- return true;
61911
- }
61912
- reset() {
61913
- this.buffer = [];
61914
- }
61915
- };
61916
- var ProcessOutputStream = class {
61917
- stream;
61918
- method;
61919
- buffer;
61920
- constructor(stream4) {
61921
- this.stream = stream4;
61922
- this.method = stream4.write;
61923
- this.buffer = new ProcessOutputBuffer({ stream: stream4 });
61924
- }
61925
- get out() {
61926
- const self2 = this;
61927
- return new Proxy(this.stream, { get(target, prop, receiver) {
61928
- if (prop === "write") return self2.write.bind(self2);
61929
- return Reflect.get(target, prop, receiver);
61930
- } });
61931
- }
61932
- hijack() {
61933
- this.stream.write = this.buffer.write.bind(this.buffer);
61725
+ let parsed;
61726
+ const columns = (process.stdout.columns ?? 80) - level * this.options.indentation - 2;
61727
+ switch (this.options.formatOutput) {
61728
+ case "truncate":
61729
+ parsed = message2.split(import_os2.EOL).map((s, i) => {
61730
+ return this.truncate(this.indent(s, i), columns);
61731
+ });
61732
+ break;
61733
+ case "wrap":
61734
+ parsed = this.wrap(message2, columns, {
61735
+ hard: true,
61736
+ trim: false
61737
+ }).split(import_os2.EOL).map((s, i) => this.indent(s, i));
61738
+ break;
61739
+ default:
61740
+ throw new ListrRendererError("Format option for the renderer is wrong.");
61741
+ }
61742
+ if (this.options.removeEmptyLines) parsed = parsed.filter(Boolean);
61743
+ return parsed.map((str) => indent(str, level * this.options.indentation));
61934
61744
  }
61935
- release() {
61936
- this.stream.write = this.method;
61937
- const buffer = [...this.buffer.all];
61938
- this.buffer.reset();
61939
- return buffer;
61745
+ shouldOutputToOutputBar(task) {
61746
+ const outputBar = this.cache.rendererTaskOptions.get(task.id).outputBar;
61747
+ return typeof outputBar === "number" && outputBar !== 0 || typeof outputBar === "boolean" && outputBar !== false;
61940
61748
  }
61941
- write(...args) {
61942
- return this.method.apply(this.stream, args);
61749
+ shouldOutputToBottomBar(task) {
61750
+ const bottomBar = this.cache.rendererTaskOptions.get(task.id).bottomBar;
61751
+ return typeof bottomBar === "number" && bottomBar !== 0 || typeof bottomBar === "boolean" && bottomBar !== false || !task.hasTitle();
61943
61752
  }
61944
- };
61945
- var ProcessOutput = class {
61946
- options;
61947
- stream;
61948
- active;
61949
- constructor(stdout, stderr, options) {
61950
- this.options = options;
61951
- this.stream = {
61952
- stdout: new ProcessOutputStream(stdout ?? process.stdout),
61953
- stderr: new ProcessOutputStream(stderr ?? process.stderr)
61954
- };
61955
- this.options = {
61956
- dump: ["stdout", "stderr"],
61957
- leaveEmptyLine: true,
61958
- ...options
61959
- };
61753
+ renderer(tasks, level = 0) {
61754
+ return tasks.flatMap((task) => {
61755
+ if (!task.isEnabled()) return [];
61756
+ if (this.cache.render.has(task.id)) return this.cache.render.get(task.id);
61757
+ this.calculate(task);
61758
+ this.setupBuffer(task);
61759
+ const rendererOptions = this.cache.rendererOptions.get(task.id);
61760
+ const rendererTaskOptions = this.cache.rendererTaskOptions.get(task.id);
61761
+ const output = [];
61762
+ if (task.isPrompt()) {
61763
+ if (this.activePrompt && this.activePrompt !== task.id) throw new ListrRendererError("Only one prompt can be active at the given time, please re-evaluate your task design.");
61764
+ else if (!this.activePrompt) {
61765
+ task.on("PROMPT", (prompt2) => {
61766
+ const cleansed = cleanseAnsi(prompt2);
61767
+ if (cleansed) this.prompt = cleansed;
61768
+ });
61769
+ task.on("STATE", (state) => {
61770
+ if (state === "PROMPT_COMPLETED" || task.hasFinalized() || task.hasReset()) {
61771
+ this.prompt = null;
61772
+ this.activePrompt = null;
61773
+ task.off("PROMPT");
61774
+ }
61775
+ });
61776
+ this.activePrompt = task.id;
61777
+ }
61778
+ }
61779
+ if (task.hasTitle()) if (!(tasks.some((task2) => task2.hasFailed()) && !task.hasFailed() && task.options.exitOnError !== false && !(task.isCompleted() || task.isSkipped()))) if (task.hasFailed() && rendererOptions.collapseErrors) output.push(...this.format(!task.hasSubtasks() && task.message.error && rendererOptions.showErrorMessage ? task.message.error : task.title, this.style(task), level));
61780
+ else if (task.isSkipped() && rendererOptions.collapseSkips) output.push(...this.format(this.logger.suffix(task.message.skip && rendererOptions.showSkipMessage ? task.message.skip : task.title, {
61781
+ field: "SKIPPED",
61782
+ condition: rendererOptions.suffixSkips,
61783
+ format: () => color.dim
61784
+ }), this.style(task), level));
61785
+ else if (task.isRetrying()) output.push(...this.format(this.logger.suffix(task.title, {
61786
+ field: `${"RETRY"}:${task.message.retry.count}`,
61787
+ format: () => color.yellow,
61788
+ condition: rendererOptions.suffixRetries
61789
+ }), this.style(task), level));
61790
+ else if (task.isCompleted() && task.hasTitle() && assertFunctionOrSelf(rendererTaskOptions.timer?.condition, task.message.duration)) output.push(...this.format(this.logger.suffix(task?.title, {
61791
+ ...rendererTaskOptions.timer,
61792
+ args: [task.message.duration]
61793
+ }), this.style(task), level));
61794
+ else if (task.isPaused()) output.push(...this.format(this.logger.suffix(task.title, {
61795
+ ...rendererOptions.pausedTimer,
61796
+ args: [task.message.paused - Date.now()]
61797
+ }), this.style(task), level));
61798
+ else output.push(...this.format(task.title, this.style(task), level));
61799
+ else output.push(...this.format(task.title, this.logger.icon("COMPLETED_WITH_SISTER_TASKS_FAILED"), level));
61800
+ if (!task.hasSubtasks() || !rendererOptions.showSubtasks) {
61801
+ if (task.hasFailed() && rendererOptions.collapseErrors === false && (rendererOptions.showErrorMessage || !rendererOptions.showSubtasks)) output.push(...this.dump(task, level, "FAILED"));
61802
+ else if (task.isSkipped() && rendererOptions.collapseSkips === false && (rendererOptions.showSkipMessage || !rendererOptions.showSubtasks)) output.push(...this.dump(task, level, "SKIPPED"));
61803
+ }
61804
+ if (task.isPending() || rendererTaskOptions.persistentOutput) output.push(...this.renderOutputBar(task, level));
61805
+ if (rendererOptions.showSubtasks !== false && task.hasSubtasks() && (task.isPending() || task.hasFinalized() && !task.hasTitle() || task.isCompleted() && rendererOptions.collapseSubtasks === false && !task.subtasks.some((subtask) => this.cache.rendererOptions.get(subtask.id)?.collapseSubtasks === true) || task.subtasks.some((subtask) => this.cache.rendererOptions.get(subtask.id)?.collapseSubtasks === false) || task.subtasks.some((subtask) => subtask.hasFailed()) || task.subtasks.some((subtask) => subtask.hasRolledBack()))) {
61806
+ const subtaskLevel = !task.hasTitle() ? level : level + 1;
61807
+ const subtaskRender = this.renderer(task.subtasks, subtaskLevel);
61808
+ output.push(...subtaskRender);
61809
+ }
61810
+ if (task.hasFinalized()) {
61811
+ if (!rendererTaskOptions.persistentOutput) {
61812
+ this.buffer.bottom.delete(task.id);
61813
+ this.buffer.output.delete(task.id);
61814
+ }
61815
+ }
61816
+ if (task.isClosed()) {
61817
+ this.cache.render.set(task.id, output);
61818
+ this.reset(task);
61819
+ }
61820
+ return output;
61821
+ });
61960
61822
  }
61961
- get stdout() {
61962
- return this.stream.stdout.out;
61823
+ renderOutputBar(task, level) {
61824
+ const output = this.buffer.output.get(task.id);
61825
+ if (!output) return [];
61826
+ return output.all.flatMap((o) => this.dump(task, level, "OUTPUT", o.entry));
61963
61827
  }
61964
- get stderr() {
61965
- return this.stream.stderr.out;
61828
+ renderBottomBar() {
61829
+ if (this.buffer.bottom.size === 0) return [];
61830
+ return Array.from(this.buffer.bottom.values()).flatMap((output) => output.all).sort((a, b) => a.time - b.time).map((output) => output.entry);
61966
61831
  }
61967
- hijack() {
61968
- if (this.active) throw new Error("ProcessOutput has been already hijacked!");
61969
- this.stream.stdout.write(ANSI_ESCAPE_CODES.CURSOR_HIDE);
61970
- Object.values(this.stream).forEach((stream4) => stream4.hijack());
61971
- this.active = true;
61832
+ renderPrompt() {
61833
+ if (!this.prompt) return [];
61834
+ return [this.prompt];
61972
61835
  }
61973
- release() {
61974
- const output = Object.entries(this.stream).map(([name, stream4]) => ({
61975
- name,
61976
- buffer: stream4.release()
61977
- })).filter((output2) => this.options.dump.includes(output2.name)).flatMap((output2) => output2.buffer).sort((a, b) => a.time - b.time).map((message2) => {
61978
- return {
61979
- ...message2,
61980
- entry: cleanseAnsi(message2.entry)
61981
- };
61982
- }).filter((message2) => message2.entry);
61983
- if (output.length > 0) {
61984
- if (this.options.leaveEmptyLine) this.stdout.write(import_os3.EOL);
61985
- output.forEach((message2) => {
61986
- (message2.stream ?? this.stdout).write(message2.entry + import_os3.EOL);
61836
+ calculate(task) {
61837
+ if (this.cache.rendererOptions.has(task.id) && this.cache.rendererTaskOptions.has(task.id)) return;
61838
+ const rendererOptions = {
61839
+ ...this.options,
61840
+ ...task.rendererOptions
61841
+ };
61842
+ this.cache.rendererOptions.set(task.id, rendererOptions);
61843
+ this.cache.rendererTaskOptions.set(task.id, {
61844
+ ...DefaultRenderer2.rendererTaskOptions,
61845
+ timer: rendererOptions.timer,
61846
+ ...task.rendererTaskOptions
61847
+ });
61848
+ }
61849
+ setupBuffer(task) {
61850
+ if (this.buffer.bottom.has(task.id) || this.buffer.output.has(task.id)) return;
61851
+ const rendererTaskOptions = this.cache.rendererTaskOptions.get(task.id);
61852
+ if (this.shouldOutputToBottomBar(task) && !this.buffer.bottom.has(task.id)) {
61853
+ this.buffer.bottom.set(task.id, new ProcessOutputBuffer({ limit: typeof rendererTaskOptions.bottomBar === "number" ? rendererTaskOptions.bottomBar : 1 }));
61854
+ task.on("OUTPUT", (output) => {
61855
+ const data = this.dump(task, -1, "OUTPUT", output);
61856
+ this.buffer.bottom.get(task.id).write(data.join(import_os2.EOL));
61857
+ });
61858
+ task.on("STATE", (state) => {
61859
+ switch (state) {
61860
+ case "RETRY":
61861
+ this.buffer.bottom.delete(task.id);
61862
+ break;
61863
+ }
61864
+ });
61865
+ } else if (this.shouldOutputToOutputBar(task) && !this.buffer.output.has(task.id)) {
61866
+ this.buffer.output.set(task.id, new ProcessOutputBuffer({ limit: typeof rendererTaskOptions.outputBar === "number" ? rendererTaskOptions.outputBar : 1 }));
61867
+ task.on("OUTPUT", (output) => {
61868
+ this.buffer.output.get(task.id).write(output);
61869
+ });
61870
+ task.on("STATE", (state) => {
61871
+ switch (state) {
61872
+ case "RETRY":
61873
+ this.buffer.output.delete(task.id);
61874
+ break;
61875
+ }
61987
61876
  });
61988
61877
  }
61989
- this.stream.stdout.write(ANSI_ESCAPE_CODES.CURSOR_SHOW);
61990
- this.active = false;
61991
61878
  }
61992
- toStdout(buffer, eol = true) {
61993
- if (eol) buffer = buffer + import_os3.EOL;
61994
- return this.stream.stdout.write(buffer);
61995
- }
61996
- toStderr(buffer, eol = true) {
61997
- if (eol) buffer = buffer + import_os3.EOL;
61998
- return this.stream.stderr.write(buffer);
61879
+ reset(task) {
61880
+ this.cache.rendererOptions.delete(task.id);
61881
+ this.cache.rendererTaskOptions.delete(task.id);
61882
+ this.buffer.output.delete(task.id);
61999
61883
  }
62000
- };
62001
- function createWritable(cb) {
62002
- const writable = new import_stream5.Writable();
62003
- writable.rows = Infinity;
62004
- writable.columns = Infinity;
62005
- writable.write = (chunk) => {
62006
- cb(chunk.toString());
62007
- return true;
62008
- };
62009
- return writable;
62010
- }
62011
- var Spinner = class {
62012
- spinner = !isUnicodeSupported2() ? [
62013
- "-",
62014
- "\\",
62015
- "|",
62016
- "/"
62017
- ] : [
62018
- "\u280B",
62019
- "\u2819",
62020
- "\u2839",
62021
- "\u2838",
62022
- "\u283C",
62023
- "\u2834",
62024
- "\u2826",
62025
- "\u2827",
62026
- "\u2807",
62027
- "\u280F"
62028
- ];
62029
- id;
62030
- spinnerPosition = 0;
62031
- spin() {
62032
- this.spinnerPosition = ++this.spinnerPosition % this.spinner.length;
61884
+ dump(task, level, source = "OUTPUT", data) {
61885
+ if (!data) switch (source) {
61886
+ case "OUTPUT":
61887
+ data = task.output;
61888
+ break;
61889
+ case "SKIPPED":
61890
+ data = task.message.skip;
61891
+ break;
61892
+ case "FAILED":
61893
+ data = task.message.error;
61894
+ break;
61895
+ }
61896
+ if (task.hasTitle() && source === "FAILED" && data === task.title || typeof data !== "string") return [];
61897
+ if (source === "OUTPUT") data = cleanseAnsi(data);
61898
+ return this.format(data, this.style(task, true), level + 1);
62033
61899
  }
62034
- fetch() {
62035
- return this.spinner[this.spinnerPosition];
61900
+ indent(str, i) {
61901
+ return i > 0 ? indent(str.trimEnd(), this.options.indentation) : str.trimEnd();
62036
61902
  }
62037
- isRunning() {
62038
- return !!this.id;
61903
+ };
61904
+ var SilentRenderer = class {
61905
+ tasks;
61906
+ options;
61907
+ static nonTTY = true;
61908
+ static rendererOptions;
61909
+ static rendererTaskOptions;
61910
+ constructor(tasks, options) {
61911
+ this.tasks = tasks;
61912
+ this.options = options;
62039
61913
  }
62040
- start(cb, interval = 100) {
62041
- this.id = setInterval(() => {
62042
- this.spin();
62043
- if (cb) cb();
62044
- }, interval);
61914
+ render() {
62045
61915
  }
62046
- stop() {
62047
- clearInterval(this.id);
62048
- this.id = void 0;
61916
+ end() {
62049
61917
  }
62050
61918
  };
62051
- var LISTR_DEFAULT_RENDERER_STYLE = {
62052
- icon: {
62053
- ["SKIPPED_WITH_COLLAPSE"]: figures2.arrowDown,
62054
- ["SKIPPED_WITHOUT_COLLAPSE"]: figures2.warning,
62055
- ["OUTPUT"]: figures2.pointerSmall,
62056
- ["OUTPUT_WITH_BOTTOMBAR"]: figures2.pointerSmall,
62057
- ["PENDING"]: figures2.pointer,
62058
- ["COMPLETED"]: figures2.tick,
62059
- ["COMPLETED_WITH_FAILED_SUBTASKS"]: figures2.warning,
62060
- ["COMPLETED_WITH_SISTER_TASKS_FAILED"]: figures2.squareSmallFilled,
62061
- ["RETRY"]: figures2.warning,
62062
- ["ROLLING_BACK"]: figures2.warning,
62063
- ["ROLLED_BACK"]: figures2.arrowLeft,
62064
- ["FAILED"]: figures2.cross,
62065
- ["FAILED_WITH_SUBTASKS"]: figures2.pointer,
62066
- ["WAITING"]: figures2.squareSmallFilled,
62067
- ["PAUSED"]: figures2.squareSmallFilled
62068
- },
62069
- color: {
62070
- ["SKIPPED_WITH_COLLAPSE"]: color.yellow,
62071
- ["SKIPPED_WITHOUT_COLLAPSE"]: color.yellow,
62072
- ["PENDING"]: color.yellow,
62073
- ["COMPLETED"]: color.green,
62074
- ["COMPLETED_WITH_FAILED_SUBTASKS"]: color.yellow,
62075
- ["COMPLETED_WITH_SISTER_TASKS_FAILED"]: color.red,
62076
- ["RETRY"]: color.yellowBright,
62077
- ["ROLLING_BACK"]: color.redBright,
62078
- ["ROLLED_BACK"]: color.redBright,
62079
- ["FAILED"]: color.red,
62080
- ["FAILED_WITH_SUBTASKS"]: color.red,
62081
- ["WAITING"]: color.dim,
62082
- ["PAUSED"]: color.yellowBright
62083
- }
62084
- };
62085
- function parseTimer(duration) {
62086
- const seconds = Math.floor(duration / 1e3);
62087
- const minutes = Math.floor(seconds / 60);
62088
- let parsedTime;
62089
- if (seconds === 0 && minutes === 0) parsedTime = `0.${Math.floor(duration / 100)}s`;
62090
- if (seconds > 0) parsedTime = `${seconds % 60}s`;
62091
- if (minutes > 0) parsedTime = `${minutes}m${parsedTime}`;
62092
- return parsedTime;
62093
- }
62094
- var PRESET_TIMER = {
62095
- condition: true,
62096
- field: parseTimer,
62097
- format: () => color.dim
62098
- };
62099
- var DefaultRenderer = class DefaultRenderer2 {
61919
+ var SimpleRenderer = class SimpleRenderer2 {
62100
61920
  tasks;
62101
61921
  options;
62102
- events;
62103
- static nonTTY = false;
62104
- static rendererOptions = {
62105
- indentation: 2,
62106
- clearOutput: false,
62107
- showSubtasks: true,
62108
- collapseSubtasks: true,
62109
- collapseSkips: true,
62110
- showSkipMessage: true,
62111
- suffixSkips: false,
62112
- collapseErrors: true,
62113
- showErrorMessage: true,
62114
- suffixRetries: true,
62115
- lazy: false,
62116
- removeEmptyLines: true,
62117
- formatOutput: "wrap",
62118
- pausedTimer: {
62119
- ...PRESET_TIMER,
62120
- format: () => color.yellowBright
62121
- }
62122
- };
62123
- static rendererTaskOptions = { outputBar: true };
62124
- prompt;
62125
- activePrompt;
62126
- spinner;
61922
+ static nonTTY = true;
61923
+ static rendererOptions = { pausedTimer: {
61924
+ ...PRESET_TIMER,
61925
+ field: (time) => `${"PAUSED"}:${time}`,
61926
+ format: () => color.yellowBright
61927
+ } };
61928
+ static rendererTaskOptions = {};
62127
61929
  logger;
62128
- updater;
62129
- truncate;
62130
- wrap;
62131
- buffer = {
62132
- output: /* @__PURE__ */ new Map(),
62133
- bottom: /* @__PURE__ */ new Map()
62134
- };
62135
61930
  cache = {
62136
- render: /* @__PURE__ */ new Map(),
62137
61931
  rendererOptions: /* @__PURE__ */ new Map(),
62138
61932
  rendererTaskOptions: /* @__PURE__ */ new Map()
62139
61933
  };
62140
- constructor(tasks, options, events) {
61934
+ constructor(tasks, options) {
62141
61935
  this.tasks = tasks;
62142
61936
  this.options = options;
62143
- this.events = events;
62144
61937
  this.options = {
62145
- ...DefaultRenderer2.rendererOptions,
62146
- ...this.options,
61938
+ ...SimpleRenderer2.rendererOptions,
61939
+ ...options,
62147
61940
  icon: {
62148
- ...LISTR_DEFAULT_RENDERER_STYLE.icon,
61941
+ ...LISTR_LOGGER_STYLE.icon,
62149
61942
  ...options?.icon ?? {}
62150
61943
  },
62151
61944
  color: {
62152
- ...LISTR_DEFAULT_RENDERER_STYLE.color,
61945
+ ...LISTR_LOGGER_STYLE.color,
62153
61946
  ...options?.color ?? {}
62154
61947
  }
62155
61948
  };
62156
- this.spinner = this.options.spinner ?? new Spinner();
62157
61949
  this.logger = this.options.logger ?? new ListrLogger({
62158
61950
  useIcons: true,
62159
- toStderr: []
61951
+ toStderr: LISTR_LOGGER_STDERR_LEVELS
62160
61952
  });
62161
61953
  this.logger.options.icon = this.options.icon;
62162
61954
  this.logger.options.color = this.options.color;
62163
- }
62164
- async render() {
62165
- const { createLogUpdate: createLogUpdate2 } = await Promise.resolve().then(() => (init_log_update(), log_update_exports));
62166
- const { default: truncate } = await Promise.resolve().then(() => (init_cli_truncate(), cli_truncate_exports));
62167
- const { default: wrap } = await Promise.resolve().then(() => (init_wrap_ansi2(), wrap_ansi_exports));
62168
- this.updater = createLogUpdate2(this.logger.process.stdout);
62169
- this.truncate = truncate;
62170
- this.wrap = wrap;
62171
- this.logger.process.hijack();
62172
- if (!this.options?.lazy) this.spinner.start(() => {
62173
- this.update();
62174
- });
62175
- this.events.on("SHOUD_REFRESH_RENDER", () => {
62176
- this.update();
62177
- });
62178
- }
62179
- update() {
62180
- this.updater(this.create());
61955
+ if (this.options.timestamp) this.logger.options.fields.prefix.unshift(this.options.timestamp);
62181
61956
  }
62182
61957
  end() {
62183
- this.spinner.stop();
62184
- this.updater.clear();
62185
- this.updater.done();
62186
- if (!this.options.clearOutput) this.logger.process.toStdout(this.create({ prompt: false }));
62187
- this.logger.process.release();
62188
- }
62189
- create(options) {
62190
- options = {
62191
- tasks: true,
62192
- bottomBar: true,
62193
- prompt: true,
62194
- ...options
62195
- };
62196
- const render = [];
62197
- const renderTasks = this.renderer(this.tasks);
62198
- const renderBottomBar = this.renderBottomBar();
62199
- const renderPrompt = this.renderPrompt();
62200
- if (options.tasks && renderTasks.length > 0) render.push(...renderTasks);
62201
- if (options.bottomBar && renderBottomBar.length > 0) {
62202
- if (render.length > 0) render.push("");
62203
- render.push(...renderBottomBar);
62204
- }
62205
- if (options.prompt && renderPrompt.length > 0) {
62206
- if (render.length > 0) render.push("");
62207
- render.push(...renderPrompt);
62208
- }
62209
- return render.join(import_os3.EOL);
62210
61958
  }
62211
- style(task, output = false) {
62212
- const rendererOptions = this.cache.rendererOptions.get(task.id);
62213
- if (task.isSkipped()) {
62214
- if (output || rendererOptions.collapseSkips) return this.logger.icon("SKIPPED_WITH_COLLAPSE");
62215
- else if (rendererOptions.collapseSkips === false) return this.logger.icon("SKIPPED_WITHOUT_COLLAPSE");
62216
- }
62217
- if (output) {
62218
- if (this.shouldOutputToBottomBar(task)) return this.logger.icon("OUTPUT_WITH_BOTTOMBAR");
62219
- return this.logger.icon("OUTPUT");
62220
- }
62221
- if (task.hasSubtasks()) {
62222
- if (task.isStarted() || task.isPrompt() && rendererOptions.showSubtasks !== false && !task.subtasks.every((subtask) => !subtask.hasTitle())) return this.logger.icon("PENDING");
62223
- else if (task.isCompleted() && task.subtasks.some((subtask) => subtask.hasFailed())) return this.logger.icon("COMPLETED_WITH_FAILED_SUBTASKS");
62224
- else if (task.hasFailed()) return this.logger.icon("FAILED_WITH_SUBTASKS");
62225
- }
62226
- if (task.isStarted() || task.isPrompt()) return this.logger.icon("PENDING", !this.options?.lazy && this.spinner.fetch());
62227
- else if (task.isCompleted()) return this.logger.icon("COMPLETED");
62228
- else if (task.isRetrying()) return this.logger.icon("RETRY", !this.options?.lazy && this.spinner.fetch());
62229
- else if (task.isRollingBack()) return this.logger.icon("ROLLING_BACK", !this.options?.lazy && this.spinner.fetch());
62230
- else if (task.hasRolledBack()) return this.logger.icon("ROLLED_BACK");
62231
- else if (task.hasFailed()) return this.logger.icon("FAILED");
62232
- else if (task.isPaused()) return this.logger.icon("PAUSED");
62233
- return this.logger.icon("WAITING");
62234
- }
62235
- format(message2, icon, level) {
62236
- if (message2.trim() === "") return [];
62237
- if (icon) message2 = icon + " " + message2;
62238
- let parsed;
62239
- const columns = (process.stdout.columns ?? 80) - level * this.options.indentation - 2;
62240
- switch (this.options.formatOutput) {
62241
- case "truncate":
62242
- parsed = message2.split(import_os3.EOL).map((s, i) => {
62243
- return this.truncate(this.indent(s, i), columns);
62244
- });
62245
- break;
62246
- case "wrap":
62247
- parsed = this.wrap(message2, columns, {
62248
- hard: true,
62249
- trim: false
62250
- }).split(import_os3.EOL).map((s, i) => this.indent(s, i));
62251
- break;
62252
- default:
62253
- throw new ListrRendererError("Format option for the renderer is wrong.");
62254
- }
62255
- if (this.options.removeEmptyLines) parsed = parsed.filter(Boolean);
62256
- return parsed.map((str) => indent(str, level * this.options.indentation));
62257
- }
62258
- shouldOutputToOutputBar(task) {
62259
- const outputBar = this.cache.rendererTaskOptions.get(task.id).outputBar;
62260
- return typeof outputBar === "number" && outputBar !== 0 || typeof outputBar === "boolean" && outputBar !== false;
62261
- }
62262
- shouldOutputToBottomBar(task) {
62263
- const bottomBar = this.cache.rendererTaskOptions.get(task.id).bottomBar;
62264
- return typeof bottomBar === "number" && bottomBar !== 0 || typeof bottomBar === "boolean" && bottomBar !== false || !task.hasTitle();
61959
+ render() {
61960
+ this.renderer(this.tasks);
62265
61961
  }
62266
- renderer(tasks, level = 0) {
62267
- return tasks.flatMap((task) => {
62268
- if (!task.isEnabled()) return [];
62269
- if (this.cache.render.has(task.id)) return this.cache.render.get(task.id);
61962
+ renderer(tasks) {
61963
+ tasks.forEach((task) => {
62270
61964
  this.calculate(task);
62271
- this.setupBuffer(task);
61965
+ task.once("CLOSED", () => {
61966
+ this.reset(task);
61967
+ });
62272
61968
  const rendererOptions = this.cache.rendererOptions.get(task.id);
62273
61969
  const rendererTaskOptions = this.cache.rendererTaskOptions.get(task.id);
62274
- const output = [];
62275
- if (task.isPrompt()) {
62276
- if (this.activePrompt && this.activePrompt !== task.id) throw new ListrRendererError("Only one prompt can be active at the given time, please re-evaluate your task design.");
62277
- else if (!this.activePrompt) {
61970
+ task.on("SUBTASK", (subtasks) => {
61971
+ this.renderer(subtasks);
61972
+ });
61973
+ task.on("STATE", (state) => {
61974
+ if (!task.hasTitle()) return;
61975
+ if (state === "STARTED") this.logger.log("STARTED", task.title);
61976
+ else if (state === "COMPLETED") {
61977
+ const timer = rendererTaskOptions?.timer;
61978
+ this.logger.log("COMPLETED", task.title, timer && { suffix: {
61979
+ ...timer,
61980
+ condition: !!task.message?.duration && timer.condition,
61981
+ args: [task.message.duration]
61982
+ } });
61983
+ } else if (state === "PROMPT") {
61984
+ this.logger.process.hijack();
62278
61985
  task.on("PROMPT", (prompt2) => {
62279
- const cleansed = cleanseAnsi(prompt2);
62280
- if (cleansed) this.prompt = cleansed;
62281
- });
62282
- task.on("STATE", (state) => {
62283
- if (state === "PROMPT_COMPLETED" || task.hasFinalized() || task.hasReset()) {
62284
- this.prompt = null;
62285
- this.activePrompt = null;
62286
- task.off("PROMPT");
62287
- }
61986
+ this.logger.process.toStderr(prompt2, false);
62288
61987
  });
62289
- this.activePrompt = task.id;
62290
- }
62291
- }
62292
- if (task.hasTitle()) if (!(tasks.some((task2) => task2.hasFailed()) && !task.hasFailed() && task.options.exitOnError !== false && !(task.isCompleted() || task.isSkipped()))) if (task.hasFailed() && rendererOptions.collapseErrors) output.push(...this.format(!task.hasSubtasks() && task.message.error && rendererOptions.showErrorMessage ? task.message.error : task.title, this.style(task), level));
62293
- else if (task.isSkipped() && rendererOptions.collapseSkips) output.push(...this.format(this.logger.suffix(task.message.skip && rendererOptions.showSkipMessage ? task.message.skip : task.title, {
62294
- field: "SKIPPED",
62295
- condition: rendererOptions.suffixSkips,
62296
- format: () => color.dim
62297
- }), this.style(task), level));
62298
- else if (task.isRetrying()) output.push(...this.format(this.logger.suffix(task.title, {
62299
- field: `${"RETRY"}:${task.message.retry.count}`,
62300
- format: () => color.yellow,
62301
- condition: rendererOptions.suffixRetries
62302
- }), this.style(task), level));
62303
- else if (task.isCompleted() && task.hasTitle() && assertFunctionOrSelf(rendererTaskOptions.timer?.condition, task.message.duration)) output.push(...this.format(this.logger.suffix(task?.title, {
62304
- ...rendererTaskOptions.timer,
62305
- args: [task.message.duration]
62306
- }), this.style(task), level));
62307
- else if (task.isPaused()) output.push(...this.format(this.logger.suffix(task.title, {
62308
- ...rendererOptions.pausedTimer,
62309
- args: [task.message.paused - Date.now()]
62310
- }), this.style(task), level));
62311
- else output.push(...this.format(task.title, this.style(task), level));
62312
- else output.push(...this.format(task.title, this.logger.icon("COMPLETED_WITH_SISTER_TASKS_FAILED"), level));
62313
- if (!task.hasSubtasks() || !rendererOptions.showSubtasks) {
62314
- if (task.hasFailed() && rendererOptions.collapseErrors === false && (rendererOptions.showErrorMessage || !rendererOptions.showSubtasks)) output.push(...this.dump(task, level, "FAILED"));
62315
- else if (task.isSkipped() && rendererOptions.collapseSkips === false && (rendererOptions.showSkipMessage || !rendererOptions.showSubtasks)) output.push(...this.dump(task, level, "SKIPPED"));
62316
- }
62317
- if (task.isPending() || rendererTaskOptions.persistentOutput) output.push(...this.renderOutputBar(task, level));
62318
- if (rendererOptions.showSubtasks !== false && task.hasSubtasks() && (task.isPending() || task.hasFinalized() && !task.hasTitle() || task.isCompleted() && rendererOptions.collapseSubtasks === false && !task.subtasks.some((subtask) => this.cache.rendererOptions.get(subtask.id)?.collapseSubtasks === true) || task.subtasks.some((subtask) => this.cache.rendererOptions.get(subtask.id)?.collapseSubtasks === false) || task.subtasks.some((subtask) => subtask.hasFailed()) || task.subtasks.some((subtask) => subtask.hasRolledBack()))) {
62319
- const subtaskLevel = !task.hasTitle() ? level : level + 1;
62320
- const subtaskRender = this.renderer(task.subtasks, subtaskLevel);
62321
- output.push(...subtaskRender);
62322
- }
62323
- if (task.hasFinalized()) {
62324
- if (!rendererTaskOptions.persistentOutput) {
62325
- this.buffer.bottom.delete(task.id);
62326
- this.buffer.output.delete(task.id);
62327
- }
62328
- }
62329
- if (task.isClosed()) {
62330
- this.cache.render.set(task.id, output);
62331
- this.reset(task);
62332
- }
62333
- return output;
62334
- });
62335
- }
62336
- renderOutputBar(task, level) {
62337
- const output = this.buffer.output.get(task.id);
62338
- if (!output) return [];
62339
- return output.all.flatMap((o) => this.dump(task, level, "OUTPUT", o.entry));
62340
- }
62341
- renderBottomBar() {
62342
- if (this.buffer.bottom.size === 0) return [];
62343
- return Array.from(this.buffer.bottom.values()).flatMap((output) => output.all).sort((a, b) => a.time - b.time).map((output) => output.entry);
62344
- }
62345
- renderPrompt() {
62346
- if (!this.prompt) return [];
62347
- return [this.prompt];
62348
- }
62349
- calculate(task) {
62350
- if (this.cache.rendererOptions.has(task.id) && this.cache.rendererTaskOptions.has(task.id)) return;
62351
- const rendererOptions = {
62352
- ...this.options,
62353
- ...task.rendererOptions
62354
- };
62355
- this.cache.rendererOptions.set(task.id, rendererOptions);
62356
- this.cache.rendererTaskOptions.set(task.id, {
62357
- ...DefaultRenderer2.rendererTaskOptions,
62358
- timer: rendererOptions.timer,
62359
- ...task.rendererTaskOptions
62360
- });
62361
- }
62362
- setupBuffer(task) {
62363
- if (this.buffer.bottom.has(task.id) || this.buffer.output.has(task.id)) return;
62364
- const rendererTaskOptions = this.cache.rendererTaskOptions.get(task.id);
62365
- if (this.shouldOutputToBottomBar(task) && !this.buffer.bottom.has(task.id)) {
62366
- this.buffer.bottom.set(task.id, new ProcessOutputBuffer({ limit: typeof rendererTaskOptions.bottomBar === "number" ? rendererTaskOptions.bottomBar : 1 }));
62367
- task.on("OUTPUT", (output) => {
62368
- const data = this.dump(task, -1, "OUTPUT", output);
62369
- this.buffer.bottom.get(task.id).write(data.join(import_os3.EOL));
62370
- });
62371
- task.on("STATE", (state) => {
62372
- switch (state) {
62373
- case "RETRY":
62374
- this.buffer.bottom.delete(task.id);
62375
- break;
62376
- }
62377
- });
62378
- } else if (this.shouldOutputToOutputBar(task) && !this.buffer.output.has(task.id)) {
62379
- this.buffer.output.set(task.id, new ProcessOutputBuffer({ limit: typeof rendererTaskOptions.outputBar === "number" ? rendererTaskOptions.outputBar : 1 }));
62380
- task.on("OUTPUT", (output) => {
62381
- this.buffer.output.get(task.id).write(output);
62382
- });
62383
- task.on("STATE", (state) => {
62384
- switch (state) {
62385
- case "RETRY":
62386
- this.buffer.output.delete(task.id);
62387
- break;
62388
- }
62389
- });
62390
- }
62391
- }
62392
- reset(task) {
62393
- this.cache.rendererOptions.delete(task.id);
62394
- this.cache.rendererTaskOptions.delete(task.id);
62395
- this.buffer.output.delete(task.id);
62396
- }
62397
- dump(task, level, source = "OUTPUT", data) {
62398
- if (!data) switch (source) {
62399
- case "OUTPUT":
62400
- data = task.output;
62401
- break;
62402
- case "SKIPPED":
62403
- data = task.message.skip;
62404
- break;
62405
- case "FAILED":
62406
- data = task.message.error;
62407
- break;
62408
- }
62409
- if (task.hasTitle() && source === "FAILED" && data === task.title || typeof data !== "string") return [];
62410
- if (source === "OUTPUT") data = cleanseAnsi(data);
62411
- return this.format(data, this.style(task, true), level + 1);
62412
- }
62413
- indent(str, i) {
62414
- return i > 0 ? indent(str.trimEnd(), this.options.indentation) : str.trimEnd();
62415
- }
62416
- };
62417
- var SilentRenderer = class {
62418
- tasks;
62419
- options;
62420
- static nonTTY = true;
62421
- static rendererOptions;
62422
- static rendererTaskOptions;
62423
- constructor(tasks, options) {
62424
- this.tasks = tasks;
62425
- this.options = options;
62426
- }
62427
- render() {
62428
- }
62429
- end() {
62430
- }
62431
- };
62432
- var SimpleRenderer = class SimpleRenderer2 {
62433
- tasks;
62434
- options;
62435
- static nonTTY = true;
62436
- static rendererOptions = { pausedTimer: {
62437
- ...PRESET_TIMER,
62438
- field: (time) => `${"PAUSED"}:${time}`,
62439
- format: () => color.yellowBright
62440
- } };
62441
- static rendererTaskOptions = {};
62442
- logger;
62443
- cache = {
62444
- rendererOptions: /* @__PURE__ */ new Map(),
62445
- rendererTaskOptions: /* @__PURE__ */ new Map()
62446
- };
62447
- constructor(tasks, options) {
62448
- this.tasks = tasks;
62449
- this.options = options;
62450
- this.options = {
62451
- ...SimpleRenderer2.rendererOptions,
62452
- ...options,
62453
- icon: {
62454
- ...LISTR_LOGGER_STYLE.icon,
62455
- ...options?.icon ?? {}
62456
- },
62457
- color: {
62458
- ...LISTR_LOGGER_STYLE.color,
62459
- ...options?.color ?? {}
62460
- }
62461
- };
62462
- this.logger = this.options.logger ?? new ListrLogger({
62463
- useIcons: true,
62464
- toStderr: LISTR_LOGGER_STDERR_LEVELS
62465
- });
62466
- this.logger.options.icon = this.options.icon;
62467
- this.logger.options.color = this.options.color;
62468
- if (this.options.timestamp) this.logger.options.fields.prefix.unshift(this.options.timestamp);
62469
- }
62470
- end() {
62471
- }
62472
- render() {
62473
- this.renderer(this.tasks);
62474
- }
62475
- renderer(tasks) {
62476
- tasks.forEach((task) => {
62477
- this.calculate(task);
62478
- task.once("CLOSED", () => {
62479
- this.reset(task);
62480
- });
62481
- const rendererOptions = this.cache.rendererOptions.get(task.id);
62482
- const rendererTaskOptions = this.cache.rendererTaskOptions.get(task.id);
62483
- task.on("SUBTASK", (subtasks) => {
62484
- this.renderer(subtasks);
62485
- });
62486
- task.on("STATE", (state) => {
62487
- if (!task.hasTitle()) return;
62488
- if (state === "STARTED") this.logger.log("STARTED", task.title);
62489
- else if (state === "COMPLETED") {
62490
- const timer = rendererTaskOptions?.timer;
62491
- this.logger.log("COMPLETED", task.title, timer && { suffix: {
62492
- ...timer,
62493
- condition: !!task.message?.duration && timer.condition,
62494
- args: [task.message.duration]
62495
- } });
62496
- } else if (state === "PROMPT") {
62497
- this.logger.process.hijack();
62498
- task.on("PROMPT", (prompt2) => {
62499
- this.logger.process.toStderr(prompt2, false);
62500
- });
62501
- } else if (state === "PROMPT_COMPLETED") {
62502
- task.off("PROMPT");
62503
- this.logger.process.release();
61988
+ } else if (state === "PROMPT_COMPLETED") {
61989
+ task.off("PROMPT");
61990
+ this.logger.process.release();
62504
61991
  }
62505
61992
  });
62506
61993
  task.on("OUTPUT", (output) => {
@@ -63079,405 +62566,1142 @@ var Task = class extends ListrTaskEventManager {
63079
62566
  ...this.message,
63080
62567
  ...data
63081
62568
  };
63082
- this.emit("MESSAGE", data);
63083
- this.listr.events.emit("SHOUD_REFRESH_RENDER");
63084
- }
63085
- /**
63086
- * Update the current title of the Task and emit the neccassary events.
63087
- */
63088
- set title$(title) {
63089
- this.title = title;
63090
- this.emit("TITLE", title);
63091
- this.listr.events.emit("SHOUD_REFRESH_RENDER");
63092
- }
63093
- /**
63094
- * Current task path in the hierarchy.
63095
- */
63096
- get path() {
63097
- return [...this.listr.path, this.initialTitle];
63098
- }
63099
- /**
63100
- * Checks whether the current task with the given context should be set as enabled.
63101
- */
63102
- async check(ctx) {
63103
- if (this.state === "WAITING") {
63104
- this.enabled = await assertFunctionOrSelf(this.task?.enabled ?? true, ctx);
63105
- this.emit("ENABLED", this.enabled);
63106
- this.listr.events.emit("SHOUD_REFRESH_RENDER");
63107
- }
63108
- return this.enabled;
63109
- }
63110
- /** Returns whether this task has subtasks. */
63111
- hasSubtasks() {
63112
- return this.subtasks?.length > 0;
63113
- }
63114
- /** Returns whether this task is finalized in someform. */
63115
- hasFinalized() {
63116
- return this.isCompleted() || this.hasFailed() || this.isSkipped() || this.hasRolledBack();
63117
- }
63118
- /** Returns whether this task is in progress. */
63119
- isPending() {
63120
- return this.isStarted() || this.isPrompt() || this.hasReset();
63121
- }
63122
- /** Returns whether this task has started. */
63123
- isStarted() {
63124
- return this.state === "STARTED";
63125
- }
63126
- /** Returns whether this task is skipped. */
63127
- isSkipped() {
63128
- return this.state === "SKIPPED";
63129
- }
63130
- /** Returns whether this task has been completed. */
63131
- isCompleted() {
63132
- return this.state === "COMPLETED";
63133
- }
63134
- /** Returns whether this task has been failed. */
63135
- hasFailed() {
63136
- return this.state === "FAILED";
63137
- }
63138
- /** Returns whether this task has an active rollback task going on. */
63139
- isRollingBack() {
63140
- return this.state === "ROLLING_BACK";
63141
- }
63142
- /** Returns whether the rollback action was successful. */
63143
- hasRolledBack() {
63144
- return this.state === "ROLLED_BACK";
62569
+ this.emit("MESSAGE", data);
62570
+ this.listr.events.emit("SHOUD_REFRESH_RENDER");
62571
+ }
62572
+ /**
62573
+ * Update the current title of the Task and emit the neccassary events.
62574
+ */
62575
+ set title$(title) {
62576
+ this.title = title;
62577
+ this.emit("TITLE", title);
62578
+ this.listr.events.emit("SHOUD_REFRESH_RENDER");
62579
+ }
62580
+ /**
62581
+ * Current task path in the hierarchy.
62582
+ */
62583
+ get path() {
62584
+ return [...this.listr.path, this.initialTitle];
62585
+ }
62586
+ /**
62587
+ * Checks whether the current task with the given context should be set as enabled.
62588
+ */
62589
+ async check(ctx) {
62590
+ if (this.state === "WAITING") {
62591
+ this.enabled = await assertFunctionOrSelf(this.task?.enabled ?? true, ctx);
62592
+ this.emit("ENABLED", this.enabled);
62593
+ this.listr.events.emit("SHOUD_REFRESH_RENDER");
62594
+ }
62595
+ return this.enabled;
62596
+ }
62597
+ /** Returns whether this task has subtasks. */
62598
+ hasSubtasks() {
62599
+ return this.subtasks?.length > 0;
62600
+ }
62601
+ /** Returns whether this task is finalized in someform. */
62602
+ hasFinalized() {
62603
+ return this.isCompleted() || this.hasFailed() || this.isSkipped() || this.hasRolledBack();
62604
+ }
62605
+ /** Returns whether this task is in progress. */
62606
+ isPending() {
62607
+ return this.isStarted() || this.isPrompt() || this.hasReset();
62608
+ }
62609
+ /** Returns whether this task has started. */
62610
+ isStarted() {
62611
+ return this.state === "STARTED";
62612
+ }
62613
+ /** Returns whether this task is skipped. */
62614
+ isSkipped() {
62615
+ return this.state === "SKIPPED";
62616
+ }
62617
+ /** Returns whether this task has been completed. */
62618
+ isCompleted() {
62619
+ return this.state === "COMPLETED";
62620
+ }
62621
+ /** Returns whether this task has been failed. */
62622
+ hasFailed() {
62623
+ return this.state === "FAILED";
62624
+ }
62625
+ /** Returns whether this task has an active rollback task going on. */
62626
+ isRollingBack() {
62627
+ return this.state === "ROLLING_BACK";
62628
+ }
62629
+ /** Returns whether the rollback action was successful. */
62630
+ hasRolledBack() {
62631
+ return this.state === "ROLLED_BACK";
62632
+ }
62633
+ /** Returns whether this task has an actively retrying task going on. */
62634
+ isRetrying() {
62635
+ return this.state === "RETRY";
62636
+ }
62637
+ /** Returns whether this task has some kind of reset like retry and rollback going on. */
62638
+ hasReset() {
62639
+ return this.state === "RETRY" || this.state === "ROLLING_BACK";
62640
+ }
62641
+ /** Returns whether enabled function resolves to true. */
62642
+ isEnabled() {
62643
+ return this.enabled;
62644
+ }
62645
+ /** Returns whether this task actually has a title. */
62646
+ hasTitle() {
62647
+ return typeof this?.title === "string";
62648
+ }
62649
+ /** Returns whether this task has a prompt inside. */
62650
+ isPrompt() {
62651
+ return this.state === "PROMPT";
62652
+ }
62653
+ /** Returns whether this task is currently paused. */
62654
+ isPaused() {
62655
+ return this.state === "PAUSED";
62656
+ }
62657
+ /** Returns whether this task is closed. */
62658
+ isClosed() {
62659
+ return this.closed;
62660
+ }
62661
+ /** Pause the given task for certain time. */
62662
+ async pause(time) {
62663
+ const state = this.state;
62664
+ this.state$ = "PAUSED";
62665
+ this.message$ = { paused: Date.now() + time };
62666
+ await delay(time);
62667
+ this.state$ = state;
62668
+ this.message$ = { paused: null };
62669
+ }
62670
+ /** Run the current task. */
62671
+ async run(context, wrapper) {
62672
+ const handleResult = (result) => {
62673
+ if (result instanceof Listr) {
62674
+ result.options = {
62675
+ ...this.options,
62676
+ ...result.options
62677
+ };
62678
+ result.rendererClass = getRendererClass("silent");
62679
+ this.subtasks = result.tasks;
62680
+ result.errors = this.listr.errors;
62681
+ this.emit("SUBTASK", this.subtasks);
62682
+ result = result.run(context);
62683
+ } else if (result instanceof Promise) result = result.then(handleResult);
62684
+ else if (isReadable(result)) result = new Promise((resolve2, reject) => {
62685
+ result.on("data", (data) => {
62686
+ this.output$ = data.toString();
62687
+ });
62688
+ result.on("error", (error) => reject(error));
62689
+ result.on("end", () => resolve2(null));
62690
+ });
62691
+ else if (isObservable(result)) result = new Promise((resolve2, reject) => {
62692
+ result.subscribe({
62693
+ next: (data) => {
62694
+ this.output$ = data;
62695
+ },
62696
+ error: reject,
62697
+ complete: resolve2
62698
+ });
62699
+ });
62700
+ return result;
62701
+ };
62702
+ const startTime = Date.now();
62703
+ this.state$ = "STARTED";
62704
+ const skipped = await assertFunctionOrSelf(this.task?.skip ?? false, context);
62705
+ if (skipped) {
62706
+ if (typeof skipped === "string") this.message$ = { skip: skipped };
62707
+ else if (this.hasTitle()) this.message$ = { skip: this.title };
62708
+ else this.message$ = { skip: "Skipped task without a title." };
62709
+ this.state$ = "SKIPPED";
62710
+ return;
62711
+ }
62712
+ try {
62713
+ const retryCount = typeof this.task?.retry === "number" && this.task.retry > 0 ? this.task.retry + 1 : typeof this.task?.retry === "object" && this.task.retry.tries > 0 ? this.task.retry.tries + 1 : 1;
62714
+ const retryDelay = typeof this.task.retry === "object" && this.task.retry.delay;
62715
+ for (let retries = 1; retries <= retryCount; retries++) try {
62716
+ await handleResult(this.taskFn(context, wrapper));
62717
+ break;
62718
+ } catch (err) {
62719
+ if (retries !== retryCount) {
62720
+ this.retry = {
62721
+ count: retries,
62722
+ error: err
62723
+ };
62724
+ this.message$ = { retry: this.retry };
62725
+ this.title$ = this.initialTitle;
62726
+ this.output = void 0;
62727
+ wrapper.report(err, "WILL_RETRY");
62728
+ this.state$ = "RETRY";
62729
+ if (retryDelay) await this.pause(retryDelay);
62730
+ } else throw err;
62731
+ }
62732
+ if (this.isStarted() || this.isRetrying()) {
62733
+ this.message$ = { duration: Date.now() - startTime };
62734
+ this.state$ = "COMPLETED";
62735
+ }
62736
+ } catch (error) {
62737
+ if (this.prompt instanceof PromptError) error = this.prompt;
62738
+ if (this.task?.rollback) {
62739
+ wrapper.report(error, "WILL_ROLLBACK");
62740
+ try {
62741
+ this.state$ = "ROLLING_BACK";
62742
+ await this.task.rollback(context, wrapper);
62743
+ this.message$ = { rollback: this.title };
62744
+ this.state$ = "ROLLED_BACK";
62745
+ } catch (err) {
62746
+ this.state$ = "FAILED";
62747
+ wrapper.report(err, "HAS_FAILED_TO_ROLLBACK");
62748
+ this.close();
62749
+ throw err;
62750
+ }
62751
+ if (this.listr.options?.exitAfterRollback !== false) {
62752
+ this.close();
62753
+ throw error;
62754
+ }
62755
+ } else {
62756
+ this.state$ = "FAILED";
62757
+ if (this.listr.options.exitOnError !== false && await assertFunctionOrSelf(this.task?.exitOnError, context) !== false) {
62758
+ wrapper.report(error, "HAS_FAILED");
62759
+ this.close();
62760
+ throw error;
62761
+ } else if (!this.hasSubtasks()) wrapper.report(error, "HAS_FAILED_WITHOUT_ERROR");
62762
+ }
62763
+ } finally {
62764
+ this.close();
62765
+ }
62766
+ }
62767
+ close() {
62768
+ this.emit("CLOSED");
62769
+ this.listr.events.emit("SHOUD_REFRESH_RENDER");
62770
+ this.complete();
62771
+ }
62772
+ };
62773
+ var ListrEventManager = class extends EventManager {
62774
+ };
62775
+ var Listr = class {
62776
+ task;
62777
+ options;
62778
+ parentTask;
62779
+ tasks = [];
62780
+ errors = [];
62781
+ ctx;
62782
+ events;
62783
+ path = [];
62784
+ rendererClass;
62785
+ rendererClassOptions;
62786
+ rendererSelection;
62787
+ boundSignalHandler;
62788
+ concurrency;
62789
+ renderer;
62790
+ constructor(task, options, parentTask) {
62791
+ this.task = task;
62792
+ this.options = options;
62793
+ this.parentTask = parentTask;
62794
+ this.options = {
62795
+ concurrent: false,
62796
+ renderer: "default",
62797
+ fallbackRenderer: "simple",
62798
+ exitOnError: true,
62799
+ exitAfterRollback: true,
62800
+ collectErrors: false,
62801
+ registerSignalListeners: true,
62802
+ ...this.parentTask?.options ?? {},
62803
+ ...options
62804
+ };
62805
+ if (this.options.concurrent === true) this.options.concurrent = Infinity;
62806
+ else if (typeof this.options.concurrent !== "number") this.options.concurrent = 1;
62807
+ this.concurrency = new Concurrency({ concurrency: this.options.concurrent });
62808
+ if (parentTask) {
62809
+ this.path = [...parentTask.listr.path, parentTask.title];
62810
+ this.errors = parentTask.listr.errors;
62811
+ }
62812
+ if (this.parentTask?.listr.events instanceof ListrEventManager) this.events = this.parentTask.listr.events;
62813
+ else this.events = new ListrEventManager();
62814
+ if (this.options?.forceTTY || process.env["LISTR_FORCE_TTY"]) {
62815
+ process.stdout.isTTY = true;
62816
+ process.stderr.isTTY = true;
62817
+ }
62818
+ if (this.options?.forceUnicode) process.env["LISTR_FORCE_UNICODE"] = "1";
62819
+ const renderer = getRenderer({
62820
+ renderer: this.options.renderer,
62821
+ rendererOptions: this.options.rendererOptions,
62822
+ fallbackRenderer: this.options.fallbackRenderer,
62823
+ fallbackRendererOptions: this.options.fallbackRendererOptions,
62824
+ fallbackRendererCondition: this.options?.fallbackRendererCondition,
62825
+ silentRendererCondition: this.options?.silentRendererCondition
62826
+ });
62827
+ this.rendererClass = renderer.renderer;
62828
+ this.rendererClassOptions = renderer.options;
62829
+ this.rendererSelection = renderer.selection;
62830
+ this.add(task ?? []);
62831
+ if (this.options.registerSignalListeners) {
62832
+ this.boundSignalHandler = this.signalHandler.bind(this);
62833
+ process.once("SIGINT", this.boundSignalHandler).setMaxListeners(0);
62834
+ }
62835
+ }
62836
+ /**
62837
+ * Whether this is the root task.
62838
+ */
62839
+ isRoot() {
62840
+ return !this.parentTask;
62841
+ }
62842
+ /**
62843
+ * Whether this is a subtask of another task list.
62844
+ */
62845
+ isSubtask() {
62846
+ return !!this.parentTask;
62847
+ }
62848
+ /**
62849
+ * Add tasks to current task list.
62850
+ *
62851
+ * @see {@link https://listr2.kilic.dev/task/task.html}
62852
+ */
62853
+ add(tasks) {
62854
+ this.tasks.push(...this.generate(tasks));
62855
+ }
62856
+ /**
62857
+ * Run the task list.
62858
+ *
62859
+ * @see {@link https://listr2.kilic.dev/listr/listr.html#run-the-generated-task-list}
62860
+ */
62861
+ async run(context) {
62862
+ if (!this.renderer) this.renderer = new this.rendererClass(this.tasks, this.rendererClassOptions, this.events);
62863
+ await this.renderer.render();
62864
+ this.ctx = this.options?.ctx ?? context ?? {};
62865
+ try {
62866
+ await Promise.all(this.tasks.map((task) => task.check(this.ctx)));
62867
+ await Promise.all(this.tasks.map((task) => this.concurrency.add(() => this.runTask(task))));
62868
+ this.renderer.end();
62869
+ this.removeSignalHandler();
62870
+ } catch (err) {
62871
+ if (this.options.exitOnError !== false) {
62872
+ this.renderer.end(err);
62873
+ this.removeSignalHandler();
62874
+ throw err;
62875
+ }
62876
+ }
62877
+ return this.ctx;
62878
+ }
62879
+ generate(tasks) {
62880
+ tasks = Array.isArray(tasks) ? tasks : [tasks];
62881
+ return tasks.map((task) => {
62882
+ let rendererTaskOptions;
62883
+ if (this.rendererSelection === "PRIMARY") rendererTaskOptions = task.rendererOptions;
62884
+ else if (this.rendererSelection === "SECONDARY") rendererTaskOptions = task.fallbackRendererOptions;
62885
+ return new Task(this, task, this.options, this.rendererClassOptions, rendererTaskOptions);
62886
+ });
62887
+ }
62888
+ async runTask(task) {
62889
+ if (!await task.check(this.ctx)) return;
62890
+ return new TaskWrapper(task).run(this.ctx);
62891
+ }
62892
+ signalHandler() {
62893
+ this.tasks?.forEach(async (task) => {
62894
+ if (task.isPending()) task.state$ = "FAILED";
62895
+ });
62896
+ if (this.isRoot()) {
62897
+ this.renderer?.end(/* @__PURE__ */ new Error("Interrupted."));
62898
+ process.exit(127);
62899
+ }
62900
+ }
62901
+ removeSignalHandler() {
62902
+ if (this.boundSignalHandler) process.removeListener("SIGINT", this.boundSignalHandler);
62903
+ }
62904
+ };
62905
+
62906
+ // packages/kong-cli/src/commands/installCommand.ts
62907
+ var import_path5 = __toESM(require("path"));
62908
+
62909
+ // packages/kong-cli/src/common/listrTaskLogger.ts
62910
+ var ListrTaskLogger = class {
62911
+ constructor(task, logLevel = 0 /* INFO */) {
62912
+ this.task = task;
62913
+ this.logLevel = logLevel;
62914
+ }
62915
+ info(message2) {
62916
+ this.task.output = message2;
62917
+ }
62918
+ debug(message2) {
62919
+ if (this.logLevel === 3 /* DEBUG */) {
62920
+ this.task.output = message2;
62921
+ }
62922
+ }
62923
+ error(message2) {
62924
+ if (this.logLevel >= 2 /* ERROR */) {
62925
+ this.task.output = message2;
62926
+ }
62927
+ }
62928
+ warn(message2) {
62929
+ if (this.logLevel >= 1 /* WARN */) {
62930
+ this.task.output = message2;
62931
+ }
62932
+ }
62933
+ };
62934
+
62935
+ // packages/kong-cli/src/commands/installCommand.ts
62936
+ var InstallCommand = class {
62937
+ constructor(verbose) {
62938
+ this.verbose = verbose;
62939
+ }
62940
+ async execute(workspaceDirectory) {
62941
+ await new Listr([
62942
+ {
62943
+ title: "installing dependencies with pip",
62944
+ task: async (_2, task) => {
62945
+ const scriptPath = this.scriptPath();
62946
+ await spawnCommandWithArgs(
62947
+ escapePathSpaces(scriptPath),
62948
+ [escapePathSpaces(workspaceDirectory)],
62949
+ new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */),
62950
+ true
62951
+ );
62952
+ },
62953
+ rendererOptions: {
62954
+ bottomBar: this.verbose ? Infinity : true,
62955
+ persistentOutput: true
62956
+ }
62957
+ }
62958
+ ]).run();
62959
+ }
62960
+ scriptPath() {
62961
+ const scriptName = "python-install";
62962
+ if (process.platform === "win32") {
62963
+ return import_path5.default.join(__dirname, "assets", `${scriptName}.bat`);
62964
+ }
62965
+ return import_path5.default.join(__dirname, "assets", `${scriptName}.sh`);
62966
+ }
62967
+ };
62968
+
62969
+ // packages/kong-cli/src/commands/publishVersionCommand.ts
62970
+ var import_child_process2 = require("child_process");
62971
+
62972
+ // packages/kong-cli/src/common/extensionContract.ts
62973
+ var import__ = __toESM(require__());
62974
+ var ajv2 = new import__.default();
62975
+ function getExtensionContract(filePath) {
62976
+ const contract = loadJsonFile(filePath);
62977
+ if (contract.input) {
62978
+ ajv2.compile(contract.input);
62979
+ }
62980
+ if (contract.output) {
62981
+ ajv2.compile(contract.output);
62982
+ }
62983
+ return contract;
62984
+ }
62985
+
62986
+ // packages/kong-cli/src/services/api.ts
62987
+ var import_keyring2 = __toESM(require_keyring());
62988
+
62989
+ // node_modules/jwt-decode/build/esm/index.js
62990
+ var InvalidTokenError = class extends Error {
62991
+ };
62992
+ InvalidTokenError.prototype.name = "InvalidTokenError";
62993
+ function b64DecodeUnicode(str) {
62994
+ return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
62995
+ let code = p.charCodeAt(0).toString(16).toUpperCase();
62996
+ if (code.length < 2) {
62997
+ code = "0" + code;
62998
+ }
62999
+ return "%" + code;
63000
+ }));
63001
+ }
63002
+ function base64UrlDecode(str) {
63003
+ let output = str.replace(/-/g, "+").replace(/_/g, "/");
63004
+ switch (output.length % 4) {
63005
+ case 0:
63006
+ break;
63007
+ case 2:
63008
+ output += "==";
63009
+ break;
63010
+ case 3:
63011
+ output += "=";
63012
+ break;
63013
+ default:
63014
+ throw new Error("base64 string is not of the correct length");
63015
+ }
63016
+ try {
63017
+ return b64DecodeUnicode(output);
63018
+ } catch (err) {
63019
+ return atob(output);
63020
+ }
63021
+ }
63022
+ function jwtDecode(token, options) {
63023
+ if (typeof token !== "string") {
63024
+ throw new InvalidTokenError("Invalid token specified: must be a string");
63025
+ }
63026
+ options || (options = {});
63027
+ const pos = options.header === true ? 0 : 1;
63028
+ const part = token.split(".")[pos];
63029
+ if (typeof part !== "string") {
63030
+ throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
63031
+ }
63032
+ let decoded;
63033
+ try {
63034
+ decoded = base64UrlDecode(part);
63035
+ } catch (e) {
63036
+ throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
63037
+ }
63038
+ try {
63039
+ return JSON.parse(decoded);
63040
+ } catch (e) {
63041
+ throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
63042
+ }
63043
+ }
63044
+
63045
+ // packages/kong-cli/src/services/api.ts
63046
+ function requestConfigProvider(profile) {
63047
+ const cached = {
63048
+ headers: {
63049
+ "Content-Type": "application/json",
63050
+ "X-App-Tenant": parseTenant(profile.kongBaseUrl)
63051
+ }
63052
+ };
63053
+ return async () => {
63054
+ if (cached.headers?.Authorization) {
63055
+ try {
63056
+ const auth = cached.headers.Authorization;
63057
+ const accessToken = auth.split("Bearer ")[1]?.trim();
63058
+ if (accessToken) {
63059
+ const decoded = jwtDecode(accessToken);
63060
+ if (decoded.exp !== void 0) {
63061
+ const nowSeconds = Date.now() / 1e3;
63062
+ if (decoded.exp > nowSeconds + 60) {
63063
+ return cached;
63064
+ }
63065
+ }
63066
+ }
63067
+ } catch (ex) {
63068
+ console.warn("failed to use cached token, fetching new one", ex);
63069
+ }
63070
+ }
63071
+ const url2 = joinUrlAndPath(
63072
+ profile.kongBaseUrl,
63073
+ "api/keycloak/realms/kong/protocol/openid-connect/token"
63074
+ );
63075
+ const entry = new import_keyring2.Entry(profile.kongBaseUrl, profile.userName);
63076
+ const password = entry.getPassword();
63077
+ if (!password) {
63078
+ throw new Error("No password found in keyring for user: " + profile.userName);
63079
+ }
63080
+ const params = new URLSearchParams({
63081
+ grant_type: "password",
63082
+ client_id: "kong-web",
63083
+ username: profile.userName,
63084
+ password
63085
+ });
63086
+ const response = await axios_default.post(url2, params, {
63087
+ headers: {
63088
+ "Content-Type": "application/x-www-form-urlencoded"
63089
+ }
63090
+ });
63091
+ cached.headers = {
63092
+ ...cached.headers,
63093
+ ["Authorization"]: `Bearer ${response.data.access_token}`
63094
+ };
63095
+ return cached;
63096
+ };
63097
+ }
63098
+
63099
+ // packages/kong-cli/src/services/managementClient.ts
63100
+ var ManagementClient = class {
63101
+ constructor(kongBaseUrl, requestConfigProvider2) {
63102
+ this.requestConfigProvider = requestConfigProvider2;
63103
+ this.baseUrl = joinUrlAndPath(kongBaseUrl, "/api/management");
63104
+ }
63105
+ async updateExtension(extension) {
63106
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions");
63107
+ await axios_default.put(url2, extension, await this.requestConfigProvider());
63108
+ }
63109
+ async createExtensionSnapshot(extensionId, snapshot) {
63110
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "snapshots");
63111
+ await axios_default.post(url2, snapshot, await this.requestConfigProvider());
63112
+ }
63113
+ async getExtensionSnapshot(extensionId, extensionSnapshotVersion) {
63114
+ const url2 = joinUrlAndPath(
63115
+ this.baseUrl,
63116
+ "v1/extensions",
63117
+ extensionId,
63118
+ "snapshots",
63119
+ extensionSnapshotVersion
63120
+ );
63121
+ return (await axios_default.get(url2, await this.requestConfigProvider())).data;
63122
+ }
63123
+ async getExtensionSnapshotVersions(extensionId) {
63124
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "/snapshots/versions");
63125
+ return (await axios_default.get(url2, await this.requestConfigProvider())).data;
63126
+ }
63127
+ async getExtensionSnapshotAliases(extensionId) {
63128
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/extensions", extensionId, "/aliases");
63129
+ return (await axios_default.get(url2, await this.requestConfigProvider())).data;
63130
+ }
63131
+ async getDocumentSnapshotVersions(documentId) {
63132
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/documents", documentId, "/snapshots/versions");
63133
+ return (await axios_default.get(url2, await this.requestConfigProvider())).data;
63134
+ }
63135
+ async getProcessAliases(documentId) {
63136
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/processes", documentId, "/aliases");
63137
+ return (await axios_default.get(url2, await this.requestConfigProvider())).data;
63138
+ }
63139
+ async getAuditLog(objectType2, objectId, createdAfter) {
63140
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/audit");
63141
+ const config = await this.requestConfigProvider();
63142
+ const response = await axios_default.get(url2, {
63143
+ ...config,
63144
+ params: { ...config.params, objectType: objectType2, objectId, createdAfter }
63145
+ });
63146
+ return response.data;
63147
+ }
63148
+ };
63149
+
63150
+ // packages/kong-cli/src/services/registryClient.ts
63151
+ var RegistryClient = class {
63152
+ constructor(kongBaseUrl, requestConfigProvider2) {
63153
+ this.requestConfigProvider = requestConfigProvider2;
63154
+ this.baseUrl = joinUrlAndPath(kongBaseUrl, "/api/registry");
63155
+ }
63156
+ async getPublishDetails(appName) {
63157
+ const url2 = joinUrlAndPath(this.baseUrl, "v1/repository", appName, "publish/details");
63158
+ return (await axios_default.post(url2, {}, await this.requestConfigProvider())).data;
63159
+ }
63160
+ };
63161
+
63162
+ // packages/kong-cli/src/commands/publishVersionCommand.ts
63163
+ function extractJsonObject(text) {
63164
+ const start = text.indexOf("{");
63165
+ const end = text.lastIndexOf("}");
63166
+ return start >= 0 && end > start ? text.slice(start, end + 1) : text;
63167
+ }
63168
+ var PublishVersionCommand = class {
63169
+ constructor(profile, verbose = false, contractPath = null) {
63170
+ this.profile = profile;
63171
+ this.verbose = verbose;
63172
+ this.contractPath = contractPath;
63173
+ this.isWin = process.platform === "win32";
63174
+ this.defaultRendererOptions = {
63175
+ bottomBar: this.verbose ? Infinity : true,
63176
+ persistentOutput: true
63177
+ };
63178
+ const clientRequestConfigProvider = requestConfigProvider(profile);
63179
+ this.registryClient = new RegistryClient(profile.kongBaseUrl, clientRequestConfigProvider);
63180
+ this.managementClient = new ManagementClient(profile.kongBaseUrl, clientRequestConfigProvider);
63181
+ const dockerVersion = (0, import_child_process2.spawnSync)("docker", ["--version"]);
63182
+ this.hasDocker = !dockerVersion.error;
63183
+ }
63184
+ get wslPrefix() {
63185
+ return this.isWin && !this.hasDocker ? "wsl" : "";
63186
+ }
63187
+ // returns the published version number. `onStep` mirrors each task's
63188
+ // lifecycle so an embedding command (e.g. kong connect) can surface the same
63189
+ // progress without parsing the Listr output.
63190
+ async execute(appName, notes, onStep) {
63191
+ const tasks = [...this.flowFactory(appName, notes)].map(
63192
+ (definition) => {
63193
+ const title = String(definition.title);
63194
+ const original = definition.task;
63195
+ return {
63196
+ ...definition,
63197
+ task: async (ctx2, task) => {
63198
+ onStep?.(title, "pending");
63199
+ try {
63200
+ await original?.(ctx2, task);
63201
+ onStep?.(title, "succeeded");
63202
+ } catch (ex) {
63203
+ onStep?.(title, "failed");
63204
+ throw ex;
63205
+ }
63206
+ }
63207
+ };
63208
+ }
63209
+ );
63210
+ const ctx = await new Listr(tasks, {
63211
+ renderer: "default",
63212
+ rendererOptions: {
63213
+ logger: new ListrLogger({
63214
+ processOutput: new ProcessOutput(process.stderr, process.stderr)
63215
+ })
63216
+ }
63217
+ }).run();
63218
+ return Number(ctx.publishDetails?.imageVersion ?? NaN);
63219
+ }
63220
+ *flowFactory(appName, notes) {
63221
+ const kongJson = getKongJson();
63222
+ if (kongJson.sdk === "kotlin" && !this.contractPath) {
63223
+ yield {
63224
+ title: "build extension",
63225
+ task: async (ctx, task) => {
63226
+ const logger = new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */);
63227
+ const cmdText = this.getKotlinBuildCmdTask();
63228
+ const isPythonSdk = kongJson.sdk === "python";
63229
+ ctx.contractText = await spawnCommand(cmdText, logger, !isPythonSdk);
63230
+ },
63231
+ rendererOptions: this.defaultRendererOptions
63232
+ };
63233
+ }
63234
+ yield {
63235
+ title: "generate schema",
63236
+ task: async (ctx, task) => {
63237
+ const logger = new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */);
63238
+ if (this.contractPath) {
63239
+ const contract = getExtensionContract(this.contractPath);
63240
+ ctx.contractText = prettyJsonObject(contract);
63241
+ } else {
63242
+ const isPythonSdk = kongJson.sdk === "python";
63243
+ const cmdText = isPythonSdk ? this.getPythonSchemaCmdText() : this.getKotlinSchemaCmdTask();
63244
+ const raw = await spawnCommand(cmdText, logger, !isPythonSdk);
63245
+ ctx.contractText = isPythonSdk ? extractJsonObject(raw) : raw;
63246
+ }
63247
+ },
63248
+ rendererOptions: this.defaultRendererOptions
63249
+ };
63250
+ yield {
63251
+ title: "get publish details",
63252
+ task: async (ctx) => {
63253
+ ctx.publishDetails = await this.registryClient.getPublishDetails(appName);
63254
+ }
63255
+ };
63256
+ yield {
63257
+ title: "docker login",
63258
+ task: async (ctx, task) => {
63259
+ const publishDetails = ctx.publishDetails;
63260
+ const regUrl = this.resolveRegistryUrl(publishDetails.repoName);
63261
+ await spawnCommand(
63262
+ this.dockerLoginCmdText(publishDetails.userName, publishDetails.token, regUrl),
63263
+ new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63264
+ );
63265
+ },
63266
+ rendererOptions: this.defaultRendererOptions
63267
+ };
63268
+ yield {
63269
+ title: "docker build",
63270
+ task: async (ctx, task) => {
63271
+ const publishDetails = ctx.publishDetails;
63272
+ const regUrl = this.resolveRegistryUrl(publishDetails.repoName);
63273
+ ctx.fullImageName = `${regUrl}/${publishDetails.imageName}:${publishDetails.imageVersion}`;
63274
+ await spawnCommand(
63275
+ this.dockerBuildCmdText(ctx.fullImageName),
63276
+ new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63277
+ );
63278
+ },
63279
+ rendererOptions: this.defaultRendererOptions
63280
+ };
63281
+ yield {
63282
+ title: "docker push",
63283
+ task: async (ctx, task) => {
63284
+ const cmd = this.dockerPushCmdText(notNull(ctx.fullImageName));
63285
+ await spawnCommand(
63286
+ cmd,
63287
+ new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63288
+ );
63289
+ },
63290
+ rendererOptions: this.defaultRendererOptions
63291
+ };
63292
+ yield {
63293
+ title: "save publish details",
63294
+ task: async (ctx, task) => {
63295
+ const publishDetails = ctx.publishDetails;
63296
+ let autoGeneratedContract;
63297
+ try {
63298
+ const parsed = JSON.parse(ctx.contractText);
63299
+ if (!parsed || typeof parsed !== "object") {
63300
+ throw new AppError(`Expected object got ${parsed}`);
63301
+ }
63302
+ autoGeneratedContract = {
63303
+ input: parsed.input,
63304
+ output: parsed.output
63305
+ };
63306
+ } catch (ex) {
63307
+ console.warn("failed to auto-generate contract", ex);
63308
+ autoGeneratedContract = {
63309
+ input: null,
63310
+ output: null
63311
+ };
63312
+ }
63313
+ const inputSchema = kongJson.settings?.input?.schema ?? autoGeneratedContract.input;
63314
+ const outputSchema = kongJson.settings?.output?.schema ?? autoGeneratedContract.output;
63315
+ const metadata = JSON.parse(JSON.stringify(kongJson));
63316
+ if (inputSchema || outputSchema) {
63317
+ if (!metadata.settings) {
63318
+ metadata.settings = {};
63319
+ }
63320
+ if (inputSchema) {
63321
+ metadata.settings.input = {
63322
+ ...metadata.settings.input || {
63323
+ filter: jqFilter("")
63324
+ },
63325
+ schema: inputSchema
63326
+ };
63327
+ }
63328
+ if (outputSchema) {
63329
+ metadata.settings.output = {
63330
+ ...metadata.settings.output || {
63331
+ filter: jqFilter("")
63332
+ },
63333
+ schema: outputSchema
63334
+ };
63335
+ }
63336
+ }
63337
+ const snapshot = {
63338
+ extensionId: kongJson.id,
63339
+ extensionName: kongJson.name,
63340
+ sdk: kongJson.sdk.toLowerCase(),
63341
+ inputSchema,
63342
+ outputSchema,
63343
+ metadata,
63344
+ version: Number(publishDetails.imageVersion),
63345
+ notes,
63346
+ checkpoint: "",
63347
+ created: utcNow(DEFAULT_TIMEZONE),
63348
+ createdBy: ""
63349
+ };
63350
+ await this.managementClient.updateExtension({
63351
+ id: kongJson.id,
63352
+ name: kongJson.name,
63353
+ category: kongJson.category,
63354
+ deprecated: false,
63355
+ origin: "cli",
63356
+ checkpoint: void 0,
63357
+ createdBy: "",
63358
+ created: utcNow(DEFAULT_TIMEZONE),
63359
+ updated: utcNow(DEFAULT_TIMEZONE),
63360
+ updatedBy: ""
63361
+ });
63362
+ await this.managementClient.createExtensionSnapshot(kongJson.id, snapshot);
63363
+ task.output = [
63364
+ `the version ${publishDetails.imageVersion} has been successfully published!`
63365
+ ].join("\n");
63366
+ },
63367
+ rendererOptions: this.defaultRendererOptions
63368
+ };
63145
63369
  }
63146
- /** Returns whether this task has an actively retrying task going on. */
63147
- isRetrying() {
63148
- return this.state === "RETRY";
63370
+ resolveRegistryUrl(repoName) {
63371
+ return repoName === "docker-registry:5000" ? "localhost:5000" : repoName;
63149
63372
  }
63150
- /** Returns whether this task has some kind of reset like retry and rollback going on. */
63151
- hasReset() {
63152
- return this.state === "RETRY" || this.state === "ROLLING_BACK";
63373
+ dockerBuildCmdText(imageName) {
63374
+ return `${this.wslPrefix} docker build --network=host -t ${imageName} -f Dockerfile .`;
63153
63375
  }
63154
- /** Returns whether enabled function resolves to true. */
63155
- isEnabled() {
63156
- return this.enabled;
63376
+ dockerPushCmdText(imageName) {
63377
+ return `${this.wslPrefix} docker push ${imageName}`;
63157
63378
  }
63158
- /** Returns whether this task actually has a title. */
63159
- hasTitle() {
63160
- return typeof this?.title === "string";
63379
+ dockerLoginCmdText(username, password, registry3) {
63380
+ return !this.isWin || this.wslPrefix ? `${this.wslPrefix} /bin/bash -c 'echo ${password} |docker login -u ${username} --password-stdin ${registry3}'` : `docker login -u ${username} -p ${password} ${registry3}"`;
63161
63381
  }
63162
- /** Returns whether this task has a prompt inside. */
63163
- isPrompt() {
63164
- return this.state === "PROMPT";
63382
+ getPythonSchemaCmdText() {
63383
+ const engine = this.isWin ? ".\\.venv\\Scripts\\python.exe" : "./.venv/bin/python";
63384
+ const mainPyPath = resolveProjectPath("src/main.py");
63385
+ return `${engine} ${escapePathSpaces(mainPyPath)} --schema`;
63165
63386
  }
63166
- /** Returns whether this task is currently paused. */
63167
- isPaused() {
63168
- return this.state === "PAUSED";
63387
+ getKotlinBuildCmdTask() {
63388
+ return `${this.wslPrefix} ./gradlew build -x test -Dquarkus.package.main-class=io.kong.sdk.function.template.QuarkusApp`;
63169
63389
  }
63170
- /** Returns whether this task is closed. */
63171
- isClosed() {
63172
- return this.closed;
63390
+ getKotlinSchemaCmdTask() {
63391
+ return `${this.wslPrefix} java -Dquarkus-profile=local -jar build/quarkus-app/quarkus-run.jar --schema`;
63173
63392
  }
63174
- /** Pause the given task for certain time. */
63175
- async pause(time) {
63176
- const state = this.state;
63177
- this.state$ = "PAUSED";
63178
- this.message$ = { paused: Date.now() + time };
63179
- await delay(time);
63180
- this.state$ = state;
63181
- this.message$ = { paused: null };
63393
+ };
63394
+
63395
+ // packages/kong-cli/src/commands/connectCommand.ts
63396
+ var ansi = {
63397
+ reset: "\x1B[0m",
63398
+ bold: "\x1B[1m",
63399
+ dim: "\x1B[2m",
63400
+ cyan: "\x1B[36m",
63401
+ green: "\x1B[32m",
63402
+ yellow: "\x1B[33m"
63403
+ };
63404
+ var DEPLOY_STEPS = [
63405
+ "install dependencies",
63406
+ "generate schema",
63407
+ "get publish details",
63408
+ "docker login",
63409
+ "docker build",
63410
+ "docker push",
63411
+ "save publish details"
63412
+ ];
63413
+ var ConnectCommand = class {
63414
+ constructor(profileName, profile) {
63415
+ this.profileName = profileName;
63416
+ this.profile = profile;
63417
+ this.isWin = process.platform === "win32";
63418
+ this.deployments = /* @__PURE__ */ new Map();
63419
+ // one scaffolded template per extension id, reused across requests so we do
63420
+ // not pay the `kong generate` cost on every test/deploy of the same extension
63421
+ this.templates = /* @__PURE__ */ new Map();
63422
+ // project operations chdir into a temp workspace, so they must not overlap
63423
+ this.lock = Promise.resolve();
63182
63424
  }
63183
- /** Run the current task. */
63184
- async run(context, wrapper) {
63185
- const handleResult = (result) => {
63186
- if (result instanceof Listr) {
63187
- result.options = {
63188
- ...this.options,
63189
- ...result.options
63190
- };
63191
- result.rendererClass = getRendererClass("silent");
63192
- this.subtasks = result.tasks;
63193
- result.errors = this.listr.errors;
63194
- this.emit("SUBTASK", this.subtasks);
63195
- result = result.run(context);
63196
- } else if (result instanceof Promise) result = result.then(handleResult);
63197
- else if (isReadable(result)) result = new Promise((resolve2, reject) => {
63198
- result.on("data", (data) => {
63199
- this.output$ = data.toString();
63200
- });
63201
- result.on("error", (error) => reject(error));
63202
- result.on("end", () => resolve2(null));
63203
- });
63204
- else if (isObservable(result)) result = new Promise((resolve2, reject) => {
63205
- result.subscribe({
63206
- next: (data) => {
63207
- this.output$ = data;
63208
- },
63209
- error: reject,
63210
- complete: resolve2
63211
- });
63425
+ async execute() {
63426
+ const server = import_http4.default.createServer((request, response) => {
63427
+ this.handle(request, response).catch((ex) => {
63428
+ console.error("request failed", ex);
63429
+ if (!response.headersSent) {
63430
+ this.json(response, 500, { error: String(ex) });
63431
+ }
63212
63432
  });
63213
- return result;
63214
- };
63215
- const startTime = Date.now();
63216
- this.state$ = "STARTED";
63217
- const skipped = await assertFunctionOrSelf(this.task?.skip ?? false, context);
63218
- if (skipped) {
63219
- if (typeof skipped === "string") this.message$ = { skip: skipped };
63220
- else if (this.hasTitle()) this.message$ = { skip: this.title };
63221
- else this.message$ = { skip: "Skipped task without a title." };
63222
- this.state$ = "SKIPPED";
63433
+ });
63434
+ const cleanup = () => this.cleanupTemplates();
63435
+ process.on("exit", cleanup);
63436
+ process.on("SIGINT", () => process.exit(0));
63437
+ process.on("SIGTERM", () => process.exit(0));
63438
+ server.listen(APP_CONNECT_PORT, () => {
63439
+ const { bold, dim, cyan, green, yellow, reset } = ansi;
63440
+ console.info();
63441
+ console.info(`${green}${bold}\u2714 kong connect is ready${reset}`);
63442
+ console.info(
63443
+ `${dim} profile ${reset}${cyan}${this.profileName}${reset}${dim} \xB7 ${reset}${cyan}${this.profile.kongBaseUrl}${reset}`
63444
+ );
63445
+ console.info(`${dim} listening on ${reset}${cyan}http://localhost:${APP_CONNECT_PORT}${reset}`);
63446
+ console.info();
63447
+ console.info(
63448
+ `${yellow}\u279C${reset} ${bold}keep this terminal open${reset} ${dim}while working in the kong ui \xB7 ctrl+c to stop${reset}`
63449
+ );
63450
+ console.info();
63451
+ });
63452
+ }
63453
+ async handle(request, response) {
63454
+ response.setHeader("Access-Control-Allow-Origin", "*");
63455
+ response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
63456
+ response.setHeader("Access-Control-Allow-Headers", "Content-Type");
63457
+ if (request.method === "OPTIONS") {
63458
+ response.writeHead(204);
63459
+ response.end();
63223
63460
  return;
63224
63461
  }
63225
- try {
63226
- const retryCount = typeof this.task?.retry === "number" && this.task.retry > 0 ? this.task.retry + 1 : typeof this.task?.retry === "object" && this.task.retry.tries > 0 ? this.task.retry.tries + 1 : 1;
63227
- const retryDelay = typeof this.task.retry === "object" && this.task.retry.delay;
63228
- for (let retries = 1; retries <= retryCount; retries++) try {
63229
- await handleResult(this.taskFn(context, wrapper));
63230
- break;
63231
- } catch (err) {
63232
- if (retries !== retryCount) {
63233
- this.retry = {
63234
- count: retries,
63235
- error: err
63236
- };
63237
- this.message$ = { retry: this.retry };
63238
- this.title$ = this.initialTitle;
63239
- this.output = void 0;
63240
- wrapper.report(err, "WILL_RETRY");
63241
- this.state$ = "RETRY";
63242
- if (retryDelay) await this.pause(retryDelay);
63243
- } else throw err;
63244
- }
63245
- if (this.isStarted() || this.isRetrying()) {
63246
- this.message$ = { duration: Date.now() - startTime };
63247
- this.state$ = "COMPLETED";
63248
- }
63249
- } catch (error) {
63250
- if (this.prompt instanceof PromptError) error = this.prompt;
63251
- if (this.task?.rollback) {
63252
- wrapper.report(error, "WILL_ROLLBACK");
63253
- try {
63254
- this.state$ = "ROLLING_BACK";
63255
- await this.task.rollback(context, wrapper);
63256
- this.message$ = { rollback: this.title };
63257
- this.state$ = "ROLLED_BACK";
63258
- } catch (err) {
63259
- this.state$ = "FAILED";
63260
- wrapper.report(err, "HAS_FAILED_TO_ROLLBACK");
63261
- this.close();
63262
- throw err;
63263
- }
63264
- if (this.listr.options?.exitAfterRollback !== false) {
63265
- this.close();
63266
- throw error;
63267
- }
63268
- } else {
63269
- this.state$ = "FAILED";
63270
- if (this.listr.options.exitOnError !== false && await assertFunctionOrSelf(this.task?.exitOnError, context) !== false) {
63271
- wrapper.report(error, "HAS_FAILED");
63272
- this.close();
63273
- throw error;
63274
- } else if (!this.hasSubtasks()) wrapper.report(error, "HAS_FAILED_WITHOUT_ERROR");
63275
- }
63276
- } finally {
63277
- this.close();
63462
+ const url2 = new URL(request.url ?? "/", `http://localhost:${APP_CONNECT_PORT}`);
63463
+ if (request.method === "GET" && url2.pathname === "/v1/profile") {
63464
+ this.json(response, 200, this.profileInfo());
63465
+ return;
63278
63466
  }
63279
- }
63280
- close() {
63281
- this.emit("CLOSED");
63282
- this.listr.events.emit("SHOUD_REFRESH_RENDER");
63283
- this.complete();
63284
- }
63285
- };
63286
- var ListrEventManager = class extends EventManager {
63287
- };
63288
- var Listr = class {
63289
- task;
63290
- options;
63291
- parentTask;
63292
- tasks = [];
63293
- errors = [];
63294
- ctx;
63295
- events;
63296
- path = [];
63297
- rendererClass;
63298
- rendererClassOptions;
63299
- rendererSelection;
63300
- boundSignalHandler;
63301
- concurrency;
63302
- renderer;
63303
- constructor(task, options, parentTask) {
63304
- this.task = task;
63305
- this.options = options;
63306
- this.parentTask = parentTask;
63307
- this.options = {
63308
- concurrent: false,
63309
- renderer: "default",
63310
- fallbackRenderer: "simple",
63311
- exitOnError: true,
63312
- exitAfterRollback: true,
63313
- collectErrors: false,
63314
- registerSignalListeners: true,
63315
- ...this.parentTask?.options ?? {},
63316
- ...options
63317
- };
63318
- if (this.options.concurrent === true) this.options.concurrent = Infinity;
63319
- else if (typeof this.options.concurrent !== "number") this.options.concurrent = 1;
63320
- this.concurrency = new Concurrency({ concurrency: this.options.concurrent });
63321
- if (parentTask) {
63322
- this.path = [...parentTask.listr.path, parentTask.title];
63323
- this.errors = parentTask.listr.errors;
63467
+ if (request.method === "POST" && url2.pathname === "/v1/tests") {
63468
+ const body = await this.readBody(request);
63469
+ this.json(response, 200, await this.runTests(body));
63470
+ return;
63324
63471
  }
63325
- if (this.parentTask?.listr.events instanceof ListrEventManager) this.events = this.parentTask.listr.events;
63326
- else this.events = new ListrEventManager();
63327
- if (this.options?.forceTTY || process.env["LISTR_FORCE_TTY"]) {
63328
- process.stdout.isTTY = true;
63329
- process.stderr.isTTY = true;
63472
+ if (request.method === "POST" && url2.pathname === "/v1/deployments") {
63473
+ const body = await this.readBody(request);
63474
+ this.json(response, 200, this.startDeployment(body));
63475
+ return;
63330
63476
  }
63331
- if (this.options?.forceUnicode) process.env["LISTR_FORCE_UNICODE"] = "1";
63332
- const renderer = getRenderer({
63333
- renderer: this.options.renderer,
63334
- rendererOptions: this.options.rendererOptions,
63335
- fallbackRenderer: this.options.fallbackRenderer,
63336
- fallbackRendererOptions: this.options.fallbackRendererOptions,
63337
- fallbackRendererCondition: this.options?.fallbackRendererCondition,
63338
- silentRendererCondition: this.options?.silentRendererCondition
63339
- });
63340
- this.rendererClass = renderer.renderer;
63341
- this.rendererClassOptions = renderer.options;
63342
- this.rendererSelection = renderer.selection;
63343
- this.add(task ?? []);
63344
- if (this.options.registerSignalListeners) {
63345
- this.boundSignalHandler = this.signalHandler.bind(this);
63346
- process.once("SIGINT", this.boundSignalHandler).setMaxListeners(0);
63477
+ const statusMatch = url2.pathname.match(/^\/v1\/deployments\/([A-Za-z0-9-]+)$/);
63478
+ if (request.method === "GET" && statusMatch) {
63479
+ const job = this.deployments.get(statusMatch[1]);
63480
+ if (!job) {
63481
+ this.json(response, 404, { error: `unknown deployment ${statusMatch[1]}` });
63482
+ return;
63483
+ }
63484
+ this.json(response, 200, job);
63485
+ return;
63347
63486
  }
63487
+ this.json(response, 404, { error: `unknown route ${request.method} ${url2.pathname}` });
63348
63488
  }
63349
- /**
63350
- * Whether this is the root task.
63351
- */
63352
- isRoot() {
63353
- return !this.parentTask;
63489
+ profileInfo() {
63490
+ return {
63491
+ profile: this.profileName,
63492
+ baseUrl: this.profile.kongBaseUrl,
63493
+ userName: this.profile.userName,
63494
+ docker: !(0, import_child_process3.spawnSync)("docker", ["--version"]).error,
63495
+ python: !(0, import_child_process3.spawnSync)(this.pythonBin(), ["--version"]).error
63496
+ };
63354
63497
  }
63355
- /**
63356
- * Whether this is a subtask of another task list.
63357
- */
63358
- isSubtask() {
63359
- return !!this.parentTask;
63498
+ /** Scaffolds the template, installs its deps and runs src/main_test.py. */
63499
+ async runTests(request) {
63500
+ return this.runExclusive(async () => {
63501
+ console.info(`
63502
+ ${ansi.cyan}\u25B6 running tests for ${request.extensionName}${ansi.reset}`);
63503
+ const { projectRoot } = await this.prepareTemplate(
63504
+ request.files,
63505
+ request.extensionId,
63506
+ request.extensionName
63507
+ );
63508
+ const previousCwd = process.cwd();
63509
+ try {
63510
+ process.chdir(projectRoot);
63511
+ await new InstallCommand(true).execute(projectRoot);
63512
+ const result = await this.run(
63513
+ this.venvPython(projectRoot),
63514
+ ["-m", "pytest", import_path6.default.join("src", "main_test.py"), "-v"],
63515
+ projectRoot
63516
+ );
63517
+ return { passed: result.exitCode === 0, output: extractTestReport(result.output) };
63518
+ } finally {
63519
+ process.chdir(previousCwd);
63520
+ }
63521
+ });
63360
63522
  }
63361
63523
  /**
63362
- * Add tasks to current task list.
63363
- *
63364
- * @see {@link https://listr2.kilic.dev/task/task.html}
63365
- */
63366
- add(tasks) {
63367
- this.tasks.push(...this.generate(tasks));
63524
+ * Deployments are asynchronous: the ui polls GET /v1/deployments/{id} and
63525
+ * renders the steps in the same progress dialog as the kong-build path.
63526
+ */
63527
+ startDeployment(request) {
63528
+ const deploymentId = generateShortId2();
63529
+ const job = {
63530
+ status: "pending",
63531
+ steps: DEPLOY_STEPS.map((name) => ({ name, status: "idle" })),
63532
+ output: ""
63533
+ };
63534
+ this.deployments.set(deploymentId, job);
63535
+ this.deploy(request, job).catch((ex) => {
63536
+ job.status = "failed";
63537
+ job.error = ex.message;
63538
+ for (const step of job.steps) {
63539
+ if (step.status === "pending") {
63540
+ step.status = "failed";
63541
+ }
63542
+ }
63543
+ });
63544
+ return { deploymentId };
63368
63545
  }
63369
63546
  /**
63370
- * Run the task list.
63371
- *
63372
- * @see {@link https://listr2.kilic.dev/listr/listr.html#run-the-generated-task-list}
63373
- */
63374
- async run(context) {
63375
- if (!this.renderer) this.renderer = new this.rendererClass(this.tasks, this.rendererClassOptions, this.events);
63376
- await this.renderer.render();
63377
- this.ctx = this.options?.ctx ?? context ?? {};
63378
- try {
63379
- await Promise.all(this.tasks.map((task) => task.check(this.ctx)));
63380
- await Promise.all(this.tasks.map((task) => this.concurrency.add(() => this.runTask(task))));
63381
- this.renderer.end();
63382
- this.removeSignalHandler();
63383
- } catch (err) {
63384
- if (this.options.exitOnError !== false) {
63385
- this.renderer.end(err);
63386
- this.removeSignalHandler();
63387
- throw err;
63547
+ * Scaffolds the cli template, swaps in the bundle and reuses kong install +
63548
+ * kong publish-version (docker build/push + schema + snapshot save), mirroring
63549
+ * their progress into the deployment status the ui polls.
63550
+ */
63551
+ async deploy(request, job) {
63552
+ await this.runExclusive(async () => {
63553
+ console.info(`
63554
+ ${ansi.cyan}\u25B6 deploying ${request.extensionName}${ansi.reset}`);
63555
+ const tenant = parseTenant(this.profile.kongBaseUrl);
63556
+ const { projectRoot } = await this.prepareTemplate(
63557
+ request.files,
63558
+ request.extensionId,
63559
+ request.extensionName
63560
+ );
63561
+ const previousCwd = process.cwd();
63562
+ try {
63563
+ this.setStep(job, "install dependencies", "pending");
63564
+ process.chdir(projectRoot);
63565
+ await new InstallCommand(true).execute(projectRoot);
63566
+ this.setStep(job, "install dependencies", "succeeded");
63567
+ const version = await new PublishVersionCommand(this.profile, true).execute(
63568
+ `${tenant}-k-extension-${request.extensionId}`,
63569
+ request.notes ?? "",
63570
+ (step, status) => this.setStep(job, step, status)
63571
+ );
63572
+ job.version = version;
63573
+ job.status = "succeeded";
63574
+ job.output = `${job.output}the version ${version} has been successfully published!
63575
+ `;
63576
+ } finally {
63577
+ process.chdir(previousCwd);
63388
63578
  }
63389
- }
63390
- return this.ctx;
63391
- }
63392
- generate(tasks) {
63393
- tasks = Array.isArray(tasks) ? tasks : [tasks];
63394
- return tasks.map((task) => {
63395
- let rendererTaskOptions;
63396
- if (this.rendererSelection === "PRIMARY") rendererTaskOptions = task.rendererOptions;
63397
- else if (this.rendererSelection === "SECONDARY") rendererTaskOptions = task.fallbackRendererOptions;
63398
- return new Task(this, task, this.options, this.rendererClassOptions, rendererTaskOptions);
63399
63579
  });
63400
63580
  }
63401
- async runTask(task) {
63402
- if (!await task.check(this.ctx)) return;
63403
- return new TaskWrapper(task).run(this.ctx);
63404
- }
63405
- signalHandler() {
63406
- this.tasks?.forEach(async (task) => {
63407
- if (task.isPending()) task.state$ = "FAILED";
63408
- });
63409
- if (this.isRoot()) {
63410
- this.renderer?.end(/* @__PURE__ */ new Error("Interrupted."));
63411
- process.exit(127);
63581
+ /**
63582
+ * Returns the (cached) scaffolded template for the extension, generating it
63583
+ * once with `kong generate` and only swapping in the ui bundle's src folder
63584
+ * and requirements.txt on subsequent calls. kong.json is patched so the
63585
+ * publish saves the snapshot under the real extension.
63586
+ */
63587
+ async prepareTemplate(files, extensionId, extensionName) {
63588
+ const template2 = this.templates.get(extensionId) ?? await this.scaffold(extensionName);
63589
+ this.templates.set(extensionId, template2);
63590
+ const { projectRoot } = template2;
63591
+ import_fs5.default.rmSync(import_path6.default.join(projectRoot, "src"), { recursive: true, force: true });
63592
+ for (const file of files) {
63593
+ const target = import_path6.default.resolve(projectRoot, file.name);
63594
+ if (!target.startsWith(projectRoot)) {
63595
+ continue;
63596
+ }
63597
+ import_fs5.default.mkdirSync(import_path6.default.dirname(target), { recursive: true });
63598
+ import_fs5.default.writeFileSync(
63599
+ target,
63600
+ file.binary === true ? Buffer.from(file.content, "base64") : file.content
63601
+ );
63412
63602
  }
63603
+ const kongJsonPath = import_path6.default.join(projectRoot, "kong.json");
63604
+ if (import_fs5.default.existsSync(kongJsonPath)) {
63605
+ const kongJson = JSON.parse(import_fs5.default.readFileSync(kongJsonPath, "utf-8"));
63606
+ kongJson.id = extensionId;
63607
+ kongJson.name = extensionName;
63608
+ import_fs5.default.writeFileSync(kongJsonPath, JSON.stringify(kongJson, null, 2));
63609
+ }
63610
+ return template2;
63413
63611
  }
63414
- removeSignalHandler() {
63415
- if (this.boundSignalHandler) process.removeListener("SIGINT", this.boundSignalHandler);
63416
- }
63417
- };
63418
-
63419
- // packages/kong-cli/src/commands/installCommand.ts
63420
- var import_path5 = __toESM(require("path"));
63421
-
63422
- // packages/kong-cli/src/common/listrTaskLogger.ts
63423
- var ListrTaskLogger = class {
63424
- constructor(task, logLevel = 0 /* INFO */) {
63425
- this.task = task;
63426
- this.logLevel = logLevel;
63427
- }
63428
- info(message2) {
63429
- this.task.output = message2;
63430
- }
63431
- debug(message2) {
63432
- if (this.logLevel === 3 /* DEBUG */) {
63433
- this.task.output = message2;
63612
+ /** Runs `kong generate` into a fresh temp workspace and locates its root. */
63613
+ async scaffold(extensionName) {
63614
+ const parent = import_fs5.default.mkdtempSync(import_path6.default.join(import_os3.default.tmpdir(), `kong-connect-${generateShortId2()}-`));
63615
+ const previousCwd = process.cwd();
63616
+ try {
63617
+ process.chdir(parent);
63618
+ await new GenerateCommand().execute(extensionName, "python", getPresetVersion(), "basic");
63619
+ } finally {
63620
+ process.chdir(previousCwd);
63434
63621
  }
63622
+ const scaffold = import_fs5.default.readdirSync(parent, { withFileTypes: true }).find((entry) => entry.isDirectory());
63623
+ if (!scaffold) {
63624
+ throw new Error("kong generate did not produce a project");
63625
+ }
63626
+ return { parent, projectRoot: import_path6.default.join(parent, scaffold.name) };
63435
63627
  }
63436
- error(message2) {
63437
- if (this.logLevel >= 2 /* ERROR */) {
63438
- this.task.output = message2;
63628
+ cleanupTemplates() {
63629
+ for (const { parent } of this.templates.values()) {
63630
+ import_fs5.default.rmSync(parent, { recursive: true, force: true });
63439
63631
  }
63632
+ this.templates.clear();
63440
63633
  }
63441
- warn(message2) {
63442
- if (this.logLevel >= 1 /* WARN */) {
63443
- this.task.output = message2;
63634
+ setStep(job, name, status) {
63635
+ const step = job.steps.find((item) => item.name === name);
63636
+ if (step) {
63637
+ step.status = status;
63444
63638
  }
63639
+ job.output = `${job.output}${name}: ${status}
63640
+ `;
63445
63641
  }
63446
- };
63447
-
63448
- // packages/kong-cli/src/commands/installCommand.ts
63449
- var InstallCommand = class {
63450
- constructor(verbose) {
63451
- this.verbose = verbose;
63642
+ runExclusive(action) {
63643
+ const result = this.lock.then(action, action);
63644
+ this.lock = result.then(
63645
+ () => void 0,
63646
+ () => void 0
63647
+ );
63648
+ return result;
63452
63649
  }
63453
- async execute(workspaceDirectory) {
63454
- await new Listr([
63455
- {
63456
- title: "installing dependencies with pip",
63457
- task: async (_2, task) => {
63458
- const scriptPath = this.scriptPath();
63459
- await spawnCommandWithArgs(
63460
- escapePathSpaces(scriptPath),
63461
- [escapePathSpaces(workspaceDirectory)],
63462
- new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */),
63463
- true
63464
- );
63465
- },
63466
- rendererOptions: {
63467
- bottomBar: this.verbose ? Infinity : true,
63468
- persistentOutput: true
63469
- }
63650
+ pythonBin() {
63651
+ return (0, import_child_process3.spawnSync)("python", ["--version"]).error ? "python3" : "python";
63652
+ }
63653
+ venvPython(workDir) {
63654
+ return this.isWin ? import_path6.default.join(workDir, ".venv", "Scripts", "python.exe") : import_path6.default.join(workDir, ".venv", "bin", "python");
63655
+ }
63656
+ // runs a child process, echoing its output to this terminal (so the operator
63657
+ // sees what is going on) while also capturing it for the ui response
63658
+ run(command, args, cwd, stdin) {
63659
+ return new Promise((resolve2) => {
63660
+ const child = (0, import_child_process3.spawn)(command, args, { cwd });
63661
+ const chunks = [];
63662
+ child.stdout.on("data", (data) => {
63663
+ chunks.push(String(data));
63664
+ process.stdout.write(data);
63665
+ });
63666
+ child.stderr.on("data", (data) => {
63667
+ chunks.push(String(data));
63668
+ process.stderr.write(data);
63669
+ });
63670
+ child.on("error", (error) => resolve2({ exitCode: -1, output: String(error) }));
63671
+ child.on("close", (exitCode) => resolve2({ exitCode: exitCode ?? -1, output: chunks.join("") }));
63672
+ if (stdin !== void 0) {
63673
+ child.stdin.write(stdin);
63470
63674
  }
63471
- ]).run();
63675
+ child.stdin.end();
63676
+ });
63472
63677
  }
63473
- scriptPath() {
63474
- const scriptName = "python-install";
63475
- if (process.platform === "win32") {
63476
- return import_path5.default.join(__dirname, "assets", `${scriptName}.bat`);
63477
- }
63478
- return import_path5.default.join(__dirname, "assets", `${scriptName}.sh`);
63678
+ readBody(request) {
63679
+ return new Promise((resolve2, reject) => {
63680
+ const chunks = [];
63681
+ request.on("data", (chunk) => chunks.push(chunk));
63682
+ request.on("error", reject);
63683
+ request.on("end", () => {
63684
+ try {
63685
+ resolve2(JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}"));
63686
+ } catch (ex) {
63687
+ reject(ex instanceof Error ? ex : new Error(String(ex)));
63688
+ }
63689
+ });
63690
+ });
63691
+ }
63692
+ json(response, status, body) {
63693
+ response.writeHead(status, { "Content-Type": "application/json" });
63694
+ response.end(JSON.stringify(body));
63479
63695
  }
63480
63696
  };
63697
+ function extractTestReport(output) {
63698
+ const marker = output.indexOf("test session starts");
63699
+ if (marker < 0) {
63700
+ return output.trim();
63701
+ }
63702
+ const lineStart = output.lastIndexOf("\n", marker);
63703
+ return output.slice(lineStart < 0 ? 0 : lineStart + 1).trim();
63704
+ }
63481
63705
 
63482
63706
  // packages/kong-cli/src/commands/listAliasesCommand.ts
63483
63707
  var ListAliasesCommand = class {
@@ -63574,227 +63798,6 @@ var ListVersionsCommand = class {
63574
63798
  }
63575
63799
  };
63576
63800
 
63577
- // packages/kong-cli/src/commands/publishVersionCommand.ts
63578
- var import_child_process3 = require("child_process");
63579
-
63580
- // packages/kong-cli/src/common/extensionContract.ts
63581
- var import__ = __toESM(require__());
63582
- var ajv2 = new import__.default();
63583
- function getExtensionContract(filePath) {
63584
- const contract = loadJsonFile(filePath);
63585
- if (contract.input) {
63586
- ajv2.compile(contract.input);
63587
- }
63588
- if (contract.output) {
63589
- ajv2.compile(contract.output);
63590
- }
63591
- return contract;
63592
- }
63593
-
63594
- // packages/kong-cli/src/commands/publishVersionCommand.ts
63595
- var PublishVersionCommand = class {
63596
- constructor(profile, verbose = false, contractPath = null) {
63597
- this.profile = profile;
63598
- this.verbose = verbose;
63599
- this.contractPath = contractPath;
63600
- this.isWin = process.platform === "win32";
63601
- this.defaultRendererOptions = {
63602
- bottomBar: this.verbose ? Infinity : true,
63603
- persistentOutput: true
63604
- };
63605
- const clientRequestConfigProvider = requestConfigProvider(profile);
63606
- this.registryClient = new RegistryClient(profile.kongBaseUrl, clientRequestConfigProvider);
63607
- this.managementClient = new ManagementClient(profile.kongBaseUrl, clientRequestConfigProvider);
63608
- const dockerVersion = (0, import_child_process3.spawnSync)("docker", ["--version"]);
63609
- this.hasDocker = !dockerVersion.error;
63610
- }
63611
- get wslPrefix() {
63612
- return this.isWin && !this.hasDocker ? "wsl" : "";
63613
- }
63614
- async execute(appName, notes) {
63615
- await new Listr([...this.flowFactory(appName, notes)], {
63616
- renderer: "default",
63617
- rendererOptions: {
63618
- logger: new ListrLogger({
63619
- processOutput: new ProcessOutput(process.stderr, process.stderr)
63620
- })
63621
- }
63622
- }).run();
63623
- }
63624
- *flowFactory(appName, notes) {
63625
- const kongJson = getKongJson();
63626
- if (kongJson.sdk === "kotlin" && !this.contractPath) {
63627
- yield {
63628
- title: "build extension",
63629
- task: async (ctx, task) => {
63630
- const logger = new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */);
63631
- const cmdText = this.getKotlinBuildCmdTask();
63632
- const isPythonSdk = kongJson.sdk === "python";
63633
- ctx.contractText = await spawnCommand(cmdText, logger, !isPythonSdk);
63634
- },
63635
- rendererOptions: this.defaultRendererOptions
63636
- };
63637
- }
63638
- yield {
63639
- title: "generate schema",
63640
- task: async (ctx, task) => {
63641
- const logger = new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */);
63642
- if (this.contractPath) {
63643
- const contract = getExtensionContract(this.contractPath);
63644
- ctx.contractText = prettyJsonObject(contract);
63645
- } else {
63646
- const isPythonSdk = kongJson.sdk === "python";
63647
- const cmdText = isPythonSdk ? this.getPythonSchemaCmdText() : this.getKotlinSchemaCmdTask();
63648
- ctx.contractText = await spawnCommand(cmdText, logger, !isPythonSdk);
63649
- }
63650
- },
63651
- rendererOptions: this.defaultRendererOptions
63652
- };
63653
- yield {
63654
- title: "get publish details",
63655
- task: async (ctx) => {
63656
- ctx.publishDetails = await this.registryClient.getPublishDetails(appName);
63657
- }
63658
- };
63659
- yield {
63660
- title: "docker login",
63661
- task: async (ctx, task) => {
63662
- const publishDetails = ctx.publishDetails;
63663
- const regUrl = this.resolveRegistryUrl(publishDetails.repoName);
63664
- await spawnCommand(
63665
- this.dockerLoginCmdText(publishDetails.userName, publishDetails.token, regUrl),
63666
- new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63667
- );
63668
- },
63669
- rendererOptions: this.defaultRendererOptions
63670
- };
63671
- yield {
63672
- title: "docker build",
63673
- task: async (ctx, task) => {
63674
- const publishDetails = ctx.publishDetails;
63675
- const regUrl = this.resolveRegistryUrl(publishDetails.repoName);
63676
- ctx.fullImageName = `${regUrl}/${publishDetails.imageName}:${publishDetails.imageVersion}`;
63677
- await spawnCommand(
63678
- this.dockerBuildCmdText(ctx.fullImageName),
63679
- new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63680
- );
63681
- },
63682
- rendererOptions: this.defaultRendererOptions
63683
- };
63684
- yield {
63685
- title: "docker push",
63686
- task: async (ctx, task) => {
63687
- const cmd = this.dockerPushCmdText(ctx.fullImageName);
63688
- await spawnCommand(
63689
- cmd,
63690
- new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
63691
- );
63692
- },
63693
- rendererOptions: this.defaultRendererOptions
63694
- };
63695
- yield {
63696
- title: "save publish details",
63697
- task: async (ctx, task) => {
63698
- const publishDetails = ctx.publishDetails;
63699
- let autoGeneratedContract;
63700
- try {
63701
- const parsed = JSON.parse(ctx.contractText);
63702
- if (!parsed || typeof parsed !== "object") {
63703
- throw new AppError(`Expected object got ${parsed}`);
63704
- }
63705
- autoGeneratedContract = {
63706
- input: parsed.input,
63707
- output: parsed.output
63708
- };
63709
- } catch (ex) {
63710
- console.warn("failed to auto-generate contract", ex);
63711
- autoGeneratedContract = {
63712
- input: null,
63713
- output: null
63714
- };
63715
- }
63716
- const inputSchema = kongJson.settings?.input?.schema ?? autoGeneratedContract.input;
63717
- const outputSchema = kongJson.settings?.output?.schema ?? autoGeneratedContract.output;
63718
- const metadata = JSON.parse(JSON.stringify(kongJson));
63719
- if (inputSchema || outputSchema) {
63720
- if (!metadata.settings) {
63721
- metadata.settings = {};
63722
- }
63723
- if (inputSchema) {
63724
- metadata.settings.input = {
63725
- ...metadata.settings.input || {
63726
- filter: jqFilter("")
63727
- },
63728
- schema: inputSchema
63729
- };
63730
- }
63731
- if (outputSchema) {
63732
- metadata.settings.output = {
63733
- ...metadata.settings.output || {
63734
- filter: jqFilter("")
63735
- },
63736
- schema: outputSchema
63737
- };
63738
- }
63739
- }
63740
- const snapshot = {
63741
- extensionId: kongJson.id,
63742
- extensionName: kongJson.name,
63743
- sdk: kongJson.sdk.toLowerCase(),
63744
- inputSchema,
63745
- outputSchema,
63746
- metadata,
63747
- version: Number(publishDetails.imageVersion),
63748
- notes,
63749
- checkpoint: "",
63750
- created: utcNow(DEFAULT_TIMEZONE),
63751
- createdBy: ""
63752
- };
63753
- await this.managementClient.updateExtension({
63754
- id: kongJson.id,
63755
- name: kongJson.name,
63756
- category: kongJson.category,
63757
- deprecated: false,
63758
- origin: "cli",
63759
- checkpoint: void 0,
63760
- createdBy: "",
63761
- created: utcNow(DEFAULT_TIMEZONE),
63762
- updated: utcNow(DEFAULT_TIMEZONE),
63763
- updatedBy: ""
63764
- });
63765
- await this.managementClient.createExtensionSnapshot(kongJson.id, snapshot);
63766
- task.output = [
63767
- `the version ${publishDetails.imageVersion} has been successfully published!`
63768
- ].join("\n");
63769
- },
63770
- rendererOptions: this.defaultRendererOptions
63771
- };
63772
- }
63773
- resolveRegistryUrl(repoName) {
63774
- return repoName === "docker-registry:5000" ? "localhost:5000" : repoName;
63775
- }
63776
- dockerBuildCmdText(imageName) {
63777
- return `${this.wslPrefix} docker build --network=host -t ${imageName} -f Dockerfile .`;
63778
- }
63779
- dockerPushCmdText(imageName) {
63780
- return `${this.wslPrefix} docker push ${imageName}`;
63781
- }
63782
- dockerLoginCmdText(username, password, registry3) {
63783
- return !this.isWin || this.wslPrefix ? `${this.wslPrefix} /bin/bash -c 'echo ${password} |docker login -u ${username} --password-stdin ${registry3}'` : `docker login -u ${username} -p ${password} ${registry3}"`;
63784
- }
63785
- getPythonSchemaCmdText() {
63786
- const engine = this.isWin ? ".\\.venv\\Scripts\\python.exe" : "./.venv/bin/python";
63787
- const mainPyPath = resolveProjectPath("src/main.py");
63788
- return `${engine} ${escapePathSpaces(mainPyPath)} --schema`;
63789
- }
63790
- getKotlinBuildCmdTask() {
63791
- return `${this.wslPrefix} ./gradlew build -x test -Dquarkus.package.main-class=io.kong.sdk.function.template.QuarkusApp`;
63792
- }
63793
- getKotlinSchemaCmdTask() {
63794
- return `${this.wslPrefix} java -Dquarkus-profile=local -jar build/quarkus-app/quarkus-run.jar --schema`;
63795
- }
63796
- };
63797
-
63798
63801
  // packages/kong-cli/src/common/deployment.ts
63799
63802
  var DEPLOY_SUCCESS_ACTIONS = /* @__PURE__ */ new Set(["deployment completed"]);
63800
63803
  var DEPLOY_FAILURE_ACTIONS = /* @__PURE__ */ new Set(["deployment failed"]);
@@ -64081,17 +64084,6 @@ var SetAliasCommand = class {
64081
64084
  }
64082
64085
  };
64083
64086
 
64084
- // packages/kong-cli/src/common/cli.ts
64085
- var import_fs5 = __toESM(require("fs"));
64086
- var import_path6 = __toESM(require("path"));
64087
- function getPresetVersion() {
64088
- const packageJsonPath = import_path6.default.join(__dirname, "package.json");
64089
- if (!import_fs5.default.existsSync(packageJsonPath)) {
64090
- throw new AppError(`package.json file was not found at path: ${packageJsonPath}`);
64091
- }
64092
- return require(packageJsonPath).version;
64093
- }
64094
-
64095
64087
  // packages/kong-cli/src/index.ts
64096
64088
  import_dotenv_expand.default.expand(import_dotenv.default.config({ path: import_path7.default.join(__dirname, ".env"), quiet: true }));
64097
64089
  async function main() {