@devkong/cli 0.0.67-alpha.26 → 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,645 +60902,209 @@ 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})`);
60963
- }
60964
- }
60965
-
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
61006
- });
61007
- const response = await axios_default.post(url2, params, {
61008
- headers: {
61009
- "Content-Type": "application/x-www-form-urlencoded"
61010
- }
61011
- });
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
- }
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 }
61066
- });
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;
61080
- }
61081
- };
61082
-
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
61104
-
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 ConnectCommand = class {
61113
- constructor(profileName, profile) {
61114
- this.profileName = profileName;
61115
- this.profile = profile;
61116
- this.isWin = process.platform === "win32";
61117
- const provider = requestConfigProvider(profile);
61118
- this.registryClient = new RegistryClient(profile.kongBaseUrl, provider);
61119
- this.managementClient = new ManagementClient(profile.kongBaseUrl, provider);
61120
- }
61121
- async execute() {
61122
- const server = import_http4.default.createServer((request, response) => {
61123
- this.handle(request, response).catch((ex) => {
61124
- console.error("request failed", ex);
61125
- if (!response.headersSent) {
61126
- this.json(response, 500, { error: String(ex) });
61127
- }
61128
- });
61129
- });
61130
- server.listen(KONG_CONNECT_PORT, () => {
61131
- console.info(
61132
- `kong connect is listening on http://localhost:${KONG_CONNECT_PORT} (profile=${this.profileName}, baseUrl=${this.profile.kongBaseUrl})`
61133
- );
61134
- console.info("keep this terminal open while working in the kong ui; ctrl+c to stop");
61135
- });
61136
- }
61137
- async handle(request, response) {
61138
- response.setHeader("Access-Control-Allow-Origin", "*");
61139
- response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
61140
- response.setHeader("Access-Control-Allow-Headers", "Content-Type");
61141
- if (request.method === "OPTIONS") {
61142
- response.writeHead(204);
61143
- response.end();
61144
- return;
61145
- }
61146
- const url2 = new URL(request.url ?? "/", `http://localhost:${KONG_CONNECT_PORT}`);
61147
- if (request.method === "GET" && url2.pathname === "/v1/profile") {
61148
- this.json(response, 200, this.profileInfo());
61149
- return;
61150
- }
61151
- if (request.method === "POST" && url2.pathname === "/v1/tests") {
61152
- const body = await this.readBody(request);
61153
- this.json(response, 200, await this.runTests(body));
61154
- return;
61155
- }
61156
- if (request.method === "POST" && url2.pathname === "/v1/deployments") {
61157
- const body = await this.readBody(request);
61158
- this.json(response, 200, await this.deploy(body));
61159
- return;
61160
- }
61161
- this.json(response, 404, { error: `unknown route ${request.method} ${url2.pathname}` });
61162
- }
61163
- profileInfo() {
61164
- return {
61165
- profile: this.profileName,
61166
- baseUrl: this.profile.kongBaseUrl,
61167
- userName: this.profile.userName,
61168
- docker: !(0, import_child_process2.spawnSync)("docker", ["--version"]).error,
61169
- python: !(0, import_child_process2.spawnSync)(this.pythonBin(), ["--version"]).error
61170
- };
61171
- }
61172
- /** Runs only src/main_test.py in a fresh venv and returns the raw output. */
61173
- async runTests(request) {
61174
- const workDir = this.materialize(request.files);
61175
- try {
61176
- const log = [];
61177
- const prepared = await this.prepareVenv(workDir, log);
61178
- if (prepared.exitCode !== 0) {
61179
- return { passed: false, output: log.join("\n") };
61180
- }
61181
- const result = await this.run(
61182
- this.venvPython(workDir),
61183
- ["-m", "pytest", import_path4.default.join("src", "main_test.py"), "-v"],
61184
- workDir
61185
- );
61186
- log.push(result.output);
61187
- return { passed: result.exitCode === 0, output: log.join("\n") };
61188
- } finally {
61189
- import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61190
- }
61191
- }
61192
- /**
61193
- * The client-side twin of the kong-build pipeline: docker build + push from
61194
- * this machine (requirements.txt applied), schema generated locally with
61195
- * `main.py --schema`, then the snapshot registered in kong-management.
61196
- */
61197
- async deploy(request) {
61198
- const workDir = this.materialize(request.files);
61199
- try {
61200
- const log = [];
61201
- import_fs3.default.writeFileSync(import_path4.default.join(workDir, "Dockerfile"), DOCKERFILE);
61202
- const prepared = await this.prepareVenv(workDir, log);
61203
- if (prepared.exitCode !== 0) {
61204
- throw new Error(`dependency install failed:
61205
- ${log.join("\n")}`);
61206
- }
61207
- const schema = await this.run(
61208
- this.venvPython(workDir),
61209
- [import_path4.default.join("src", "main.py"), "--schema"],
61210
- workDir
61211
- );
61212
- if (schema.exitCode !== 0) {
61213
- throw new Error(`schema generation failed:
61214
- ${schema.output}`);
61215
- }
61216
- const contract = JSON.parse(schema.output);
61217
- const tenant = parseTenant(this.profile.kongBaseUrl);
61218
- const publishDetails = await this.registryClient.getPublishDetails(
61219
- `${tenant}-k-extension-${request.extensionId}`
61220
- );
61221
- const registryUrl = publishDetails.repoName === "docker-registry:5000" ? "localhost:5000" : publishDetails.repoName;
61222
- const imageName = `${registryUrl}/${publishDetails.imageName}:${publishDetails.imageVersion}`;
61223
- for (const step of [
61224
- {
61225
- title: "docker login",
61226
- command: "docker",
61227
- args: ["login", "-u", publishDetails.userName, "--password-stdin", registryUrl],
61228
- stdin: publishDetails.token
61229
- },
61230
- {
61231
- title: "docker build",
61232
- command: "docker",
61233
- args: ["build", "--network=host", "-t", imageName, "-f", "Dockerfile", "."]
61234
- },
61235
- { title: "docker push", command: "docker", args: ["push", imageName] }
61236
- ]) {
61237
- log.push(`> ${step.title}`);
61238
- const result = await this.run(step.command, step.args, workDir, step.stdin);
61239
- log.push(result.output);
61240
- if (result.exitCode !== 0) {
61241
- throw new Error(`${step.title} failed:
61242
- ${log.join("\n")}`);
61243
- }
61244
- }
61245
- const version = Number(publishDetails.imageVersion);
61246
- await this.managementClient.createExtensionSnapshot(
61247
- request.extensionId,
61248
- this.snapshotFor(request, version, contract)
61249
- );
61250
- log.push(`the version ${version} has been successfully published!`);
61251
- return { version, output: log.join("\n") };
61252
- } finally {
61253
- import_fs3.default.rmSync(workDir, { recursive: true, force: true });
61254
- }
61255
- }
61256
- snapshotFor(request, version, contract) {
61257
- return {
61258
- extensionId: request.extensionId,
61259
- extensionName: request.extensionName,
61260
- sdk: "python",
61261
- inputSchema: contract.input,
61262
- outputSchema: contract.output,
61263
- metadata: {
61264
- id: request.extensionId,
61265
- name: request.extensionName,
61266
- sdk: "python",
61267
- settings: {
61268
- input: { filter: jqFilter(""), schema: contract.input },
61269
- output: { filter: jqFilter(""), schema: contract.output }
61270
- }
61271
- },
61272
- version,
61273
- notes: request.notes ?? "",
61274
- checkpoint: "",
61275
- created: utcNow(DEFAULT_TIMEZONE),
61276
- createdBy: ""
61277
- };
61278
- }
61279
- /** Writes the bundle to a fresh temp folder, decoding binary entries. */
61280
- materialize(files) {
61281
- const workDir = import_fs3.default.mkdtempSync(import_path4.default.join(import_os2.default.tmpdir(), `kong-connect-${generateShortId()}-`));
61282
- for (const file of files) {
61283
- const target = import_path4.default.resolve(workDir, file.name);
61284
- if (!target.startsWith(workDir)) {
61285
- continue;
61286
- }
61287
- import_fs3.default.mkdirSync(import_path4.default.dirname(target), { recursive: true });
61288
- import_fs3.default.writeFileSync(
61289
- target,
61290
- file.binary === true ? Buffer.from(file.content, "base64") : file.content
61291
- );
61292
- }
61293
- import_fs3.default.writeFileSync(import_path4.default.join(workDir, "pyproject.toml"), PYPROJECT);
61294
- return workDir;
61295
- }
61296
- async prepareVenv(workDir, log) {
61297
- const venv = await this.run(this.pythonBin(), ["-m", "venv", "--clear", ".venv"], workDir);
61298
- log.push(venv.output);
61299
- if (venv.exitCode !== 0) {
61300
- return venv;
61301
- }
61302
- const install = await this.run(
61303
- this.venvPython(workDir),
61304
- [
61305
- "-m",
61306
- "pip",
61307
- "install",
61308
- "--default-timeout=120",
61309
- "-r",
61310
- "requirements.txt",
61311
- ...TEST_DEPENDENCIES
61312
- ],
61313
- workDir
61314
- );
61315
- log.push(install.output);
61316
- return install;
61317
- }
61318
- pythonBin() {
61319
- return (0, import_child_process2.spawnSync)("python", ["--version"]).error ? "python3" : "python";
61320
- }
61321
- venvPython(workDir) {
61322
- return this.isWin ? import_path4.default.join(workDir, ".venv", "Scripts", "python.exe") : import_path4.default.join(workDir, ".venv", "bin", "python");
61323
- }
61324
- run(command, args, cwd, stdin) {
61325
- return new Promise((resolve2) => {
61326
- const child = (0, import_child_process2.spawn)(command, args, { cwd });
61327
- const chunks = [];
61328
- child.stdout.on("data", (data) => chunks.push(String(data)));
61329
- child.stderr.on("data", (data) => chunks.push(String(data)));
61330
- child.on("error", (error) => resolve2({ exitCode: -1, output: String(error) }));
61331
- child.on("close", (exitCode) => resolve2({ exitCode: exitCode ?? -1, output: chunks.join("") }));
61332
- if (stdin !== void 0) {
61333
- child.stdin.write(stdin);
61334
- }
61335
- child.stdin.end();
61336
- });
61337
- }
61338
- readBody(request) {
61339
- return new Promise((resolve2, reject) => {
61340
- const chunks = [];
61341
- request.on("data", (chunk) => chunks.push(chunk));
61342
- request.on("error", reject);
61343
- request.on("end", () => {
61344
- try {
61345
- resolve2(JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}"));
61346
- } catch (ex) {
61347
- reject(ex instanceof Error ? ex : new Error(String(ex)));
61348
- }
61349
- });
61350
- });
61351
- }
61352
- json(response, status, body) {
61353
- response.writeHead(status, { "Content-Type": "application/json" });
61354
- response.end(JSON.stringify(body));
61355
- }
61356
- };
61357
-
61358
- // packages/kong-cli/src/commands/generateCommand.ts
61359
- var import_create_nx_workspace = require("create-nx-workspace");
61360
-
61361
- // packages/kong-cli/src/common/kongJson.ts
61362
- var import_ajv = __toESM(require_ajv());
61363
- var import_fs4 = __toESM(require("fs"));
61364
-
61365
- // packages/kong-cli/src/common/kongJsonSchema.ts
61366
- var KONG_JSON_SCHEMA = {
61367
- $schema: "http://json-schema.org/draft-07/schema#",
61368
- type: "object",
61369
- properties: {
61370
- id: {
61371
- type: "string"
61372
- },
61373
- name: {
61374
- type: "string"
61375
- },
61376
- sdk: {
61377
- type: "string",
61378
- enum: ["python", "kotlin"]
61379
- },
61380
- category: {
61381
- type: "string"
61382
- },
61383
- settings: {
61384
- type: "object",
61385
- properties: {
61386
- input: {
61387
- type: "object",
61388
- properties: {
61389
- filter: {
61390
- type: "string"
61391
- },
61392
- schema: {
61393
- $ref: "http://json-schema.org/draft-07/schema#"
61394
- }
61395
- },
61396
- required: ["schema", "filter"]
61397
- },
61398
- output: {
61399
- type: "object",
61400
- properties: {
61401
- filter: {
61402
- type: "string"
61403
- },
61404
- schema: {
61405
- $ref: "http://json-schema.org/draft-07/schema#"
61406
- }
61407
- },
61408
- required: ["schema", "filter"]
61409
- },
61410
- invoke: {
61411
- type: "object",
61412
- properties: {
61413
- prefix: {
61414
- type: "string"
61415
- },
61416
- cache: {
61417
- type: "object",
61418
- properties: {
61419
- enabled: {
61420
- type: "boolean"
61421
- },
61422
- key: {
61423
- type: ["string"]
61424
- },
61425
- ttl: {
61426
- type: "string"
61427
- },
61428
- onFailure: {
61429
- type: "string",
61430
- enum: ["skip", "retry"]
61431
- }
61432
- },
61433
- required: ["enabled", "key", "ttl", "onFailure"]
61434
- },
61435
- retry: {
61436
- type: "object",
61437
- properties: {
61438
- maxAttempts: {
61439
- type: "number"
61440
- },
61441
- attemptDelay: {
61442
- type: "string"
61443
- },
61444
- attemptTimeout: {
61445
- type: "string"
61446
- }
61447
- },
61448
- required: ["maxAttempts", "attemptDelay", "attemptTimeout"]
61449
- },
61450
- circuitBreaker: {
61451
- type: "object",
61452
- properties: {
61453
- enabled: {
61454
- type: "boolean"
61455
- },
61456
- requestVolumeThreshold: {
61457
- type: "number"
61458
- },
61459
- failureRatio: {
61460
- type: "number"
61461
- },
61462
- successThreshold: {
61463
- type: "number"
61464
- }
61465
- },
61466
- required: ["enabled", "requestVolumeThreshold", "failureRatio", "successThreshold"]
61467
- }
61468
- }
61469
- }
61470
- },
61471
- additionalProperties: false
61472
- }
61473
- },
61474
- additionalProperties: false,
61475
- required: ["id", "name", "sdk", "category"]
61476
- };
61477
-
61478
- // packages/kong-cli/src/common/kongJson.ts
61479
- var ajv = new import_ajv.default();
61480
- var validate2 = ajv.compile(KONG_JSON_SCHEMA);
61481
- var SUPPORTED_SDK = ["kotlin", "python"];
61482
- function validateKongJson(kongJson) {
61483
- if (isEmpty(kongJson.id)) {
61484
- throw new AppError(
61485
- "The `id` field should not be empty. Please provide a valid identifier in kong.json."
61486
- );
61487
- }
61488
- if (isEmpty(kongJson.category)) {
61489
- throw new AppError(
61490
- "The `category` field should not be empty. Please provide a category value in kong.json."
61491
- );
61492
- }
61493
- if (!/^[a-z][a-z0-9]{11}$/.test(kongJson.id)) {
61494
- throw new AppError(
61495
- "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"
61496
- );
61497
- }
61498
- if (!SUPPORTED_SDK.includes(kongJson.sdk)) {
61499
- throw new AppError(
61500
- `Unexpected SDK value: ${kongJson.sdk}. Supported SDK: ${SUPPORTED_SDK}.Please provide a valid identifier in kong.json.`
61501
- );
61502
- }
61503
- if (isEmpty(kongJson.name)) {
61504
- throw new AppError(
61505
- "The `name` field should not be empty. Please provide a valid name in kong.json."
61506
- );
61507
- }
61508
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(kongJson.name)) {
61509
- throw new AppError(
61510
- "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."
61511
- );
61512
- }
61513
- const isValid2 = validate2(kongJson);
61514
- if (!isValid2) {
61515
- throw new AppError(
61516
- "The provided `kong.json` does not follow the expected JSON schema. Errors: \n" + prettyJsonObject(validate2.errors || [])
61517
- );
61518
- }
61519
- return kongJson;
61520
- }
61521
- function getKongJson() {
61522
- const kongJsonPath = resolveProjectPath("kong.json");
61523
- try {
61524
- const fileContent = import_fs4.default.readFileSync(kongJsonPath, "utf-8");
61525
- const kongJson = JSON.parse(fileContent);
61526
- return validateKongJson(kongJson);
61527
- } catch (ex) {
61528
- if (ex instanceof SyntaxError) {
61529
- throw new AppError(`Error parsing kong.json: ${ex.message}`);
61530
- }
61531
- throw ex;
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;
61532
61101
  }
61533
61102
  }
61534
61103
 
61535
61104
  // packages/kong-cli/src/commands/generateCommand.ts
61536
61105
  var GenerateCommand = class {
61537
61106
  async execute(extensionName, sdk, presetVersion, template2) {
61538
- const id = generateShortId();
61107
+ const id = generateShortId2();
61539
61108
  const variant = sdk === "python" ? template2 ?? await this.promptTemplate() : "basic";
61540
61109
  validateKongJson({
61541
61110
  id,
@@ -61586,7 +61155,7 @@ var eventemitter3_default = import_index.default;
61586
61155
  // node_modules/listr2/dist/index.mjs
61587
61156
  var import_node_util11 = require("node:util");
61588
61157
  var import_util4 = require("util");
61589
- var import_os3 = require("os");
61158
+ var import_os2 = require("os");
61590
61159
  var import_string_decoder = require("string_decoder");
61591
61160
  var import_stream5 = require("stream");
61592
61161
  var import_rfdc = __toESM(require_rfdc(), 1);
@@ -61778,12 +61347,12 @@ var ListrLogger = class {
61778
61347
  }
61779
61348
  format(level, message2, options) {
61780
61349
  if (!Array.isArray(message2)) message2 = [message2];
61781
- message2 = this.splat(message2.shift(), ...message2).toString().split(import_os3.EOL).filter((m) => !m || m.trim() !== "").map((m) => {
61350
+ message2 = this.splat(message2.shift(), ...message2).toString().split(import_os2.EOL).filter((m) => !m || m.trim() !== "").map((m) => {
61782
61351
  return this.style(level, this.fields(m, {
61783
61352
  prefix: Array.isArray(options?.prefix) ? options.prefix : [options?.prefix],
61784
61353
  suffix: Array.isArray(options?.suffix) ? options.suffix : [options?.suffix]
61785
61354
  }));
61786
- }).join(import_os3.EOL);
61355
+ }).join(import_os2.EOL);
61787
61356
  return message2;
61788
61357
  }
61789
61358
  style(level, message2) {
@@ -61899,20 +61468,20 @@ var ProcessOutput = class {
61899
61468
  };
61900
61469
  }).filter((message2) => message2.entry);
61901
61470
  if (output.length > 0) {
61902
- if (this.options.leaveEmptyLine) this.stdout.write(import_os3.EOL);
61471
+ if (this.options.leaveEmptyLine) this.stdout.write(import_os2.EOL);
61903
61472
  output.forEach((message2) => {
61904
- (message2.stream ?? this.stdout).write(message2.entry + import_os3.EOL);
61473
+ (message2.stream ?? this.stdout).write(message2.entry + import_os2.EOL);
61905
61474
  });
61906
61475
  }
61907
61476
  this.stream.stdout.write(ANSI_ESCAPE_CODES.CURSOR_SHOW);
61908
61477
  this.active = false;
61909
61478
  }
61910
61479
  toStdout(buffer, eol = true) {
61911
- if (eol) buffer = buffer + import_os3.EOL;
61480
+ if (eol) buffer = buffer + import_os2.EOL;
61912
61481
  return this.stream.stdout.write(buffer);
61913
61482
  }
61914
61483
  toStderr(buffer, eol = true) {
61915
- if (eol) buffer = buffer + import_os3.EOL;
61484
+ if (eol) buffer = buffer + import_os2.EOL;
61916
61485
  return this.stream.stderr.write(buffer);
61917
61486
  }
61918
61487
  };
@@ -62124,7 +61693,7 @@ var DefaultRenderer = class DefaultRenderer2 {
62124
61693
  if (render.length > 0) render.push("");
62125
61694
  render.push(...renderPrompt);
62126
61695
  }
62127
- return render.join(import_os3.EOL);
61696
+ return render.join(import_os2.EOL);
62128
61697
  }
62129
61698
  style(task, output = false) {
62130
61699
  const rendererOptions = this.cache.rendererOptions.get(task.id);
@@ -62157,7 +61726,7 @@ var DefaultRenderer = class DefaultRenderer2 {
62157
61726
  const columns = (process.stdout.columns ?? 80) - level * this.options.indentation - 2;
62158
61727
  switch (this.options.formatOutput) {
62159
61728
  case "truncate":
62160
- parsed = message2.split(import_os3.EOL).map((s, i) => {
61729
+ parsed = message2.split(import_os2.EOL).map((s, i) => {
62161
61730
  return this.truncate(this.indent(s, i), columns);
62162
61731
  });
62163
61732
  break;
@@ -62165,7 +61734,7 @@ var DefaultRenderer = class DefaultRenderer2 {
62165
61734
  parsed = this.wrap(message2, columns, {
62166
61735
  hard: true,
62167
61736
  trim: false
62168
- }).split(import_os3.EOL).map((s, i) => this.indent(s, i));
61737
+ }).split(import_os2.EOL).map((s, i) => this.indent(s, i));
62169
61738
  break;
62170
61739
  default:
62171
61740
  throw new ListrRendererError("Format option for the renderer is wrong.");
@@ -62284,7 +61853,7 @@ var DefaultRenderer = class DefaultRenderer2 {
62284
61853
  this.buffer.bottom.set(task.id, new ProcessOutputBuffer({ limit: typeof rendererTaskOptions.bottomBar === "number" ? rendererTaskOptions.bottomBar : 1 }));
62285
61854
  task.on("OUTPUT", (output) => {
62286
61855
  const data = this.dump(task, -1, "OUTPUT", output);
62287
- this.buffer.bottom.get(task.id).write(data.join(import_os3.EOL));
61856
+ this.buffer.bottom.get(task.id).write(data.join(import_os2.EOL));
62288
61857
  });
62289
61858
  task.on("STATE", (state) => {
62290
61859
  switch (state) {
@@ -63356,144 +62925,49 @@ var ListrTaskLogger = class {
63356
62925
  this.task.output = message2;
63357
62926
  }
63358
62927
  }
63359
- warn(message2) {
63360
- if (this.logLevel >= 1 /* WARN */) {
63361
- this.task.output = message2;
63362
- }
63363
- }
63364
- };
63365
-
63366
- // packages/kong-cli/src/commands/installCommand.ts
63367
- var InstallCommand = class {
63368
- constructor(verbose) {
63369
- this.verbose = verbose;
63370
- }
63371
- async execute(workspaceDirectory) {
63372
- await new Listr([
63373
- {
63374
- title: "installing dependencies with pip",
63375
- task: async (_2, task) => {
63376
- const scriptPath = this.scriptPath();
63377
- await spawnCommandWithArgs(
63378
- escapePathSpaces(scriptPath),
63379
- [escapePathSpaces(workspaceDirectory)],
63380
- new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */),
63381
- true
63382
- );
63383
- },
63384
- rendererOptions: {
63385
- bottomBar: this.verbose ? Infinity : true,
63386
- persistentOutput: true
63387
- }
63388
- }
63389
- ]).run();
63390
- }
63391
- scriptPath() {
63392
- const scriptName = "python-install";
63393
- if (process.platform === "win32") {
63394
- return import_path5.default.join(__dirname, "assets", `${scriptName}.bat`);
63395
- }
63396
- return import_path5.default.join(__dirname, "assets", `${scriptName}.sh`);
63397
- }
63398
- };
63399
-
63400
- // packages/kong-cli/src/commands/listAliasesCommand.ts
63401
- var ListAliasesCommand = class {
63402
- constructor(profile, verbose) {
63403
- this.profile = profile;
63404
- this.verbose = verbose;
63405
- this.managementClient = new ManagementClient(
63406
- this.profile.kongBaseUrl,
63407
- requestConfigProvider(profile)
63408
- );
63409
- }
63410
- async execute(processId) {
63411
- await new Listr(
63412
- [
63413
- {
63414
- title: processId ? `list process aliases (${processId})` : "list extension aliases",
63415
- task: async (ctx, task) => {
63416
- const aliases = processId ? await this.managementClient.getProcessAliases(processId) : await this.managementClient.getExtensionSnapshotAliases(getKongJson().id);
63417
- if (aliases.length === 0) {
63418
- task.output = "no aliases available";
63419
- } else {
63420
- const result = [];
63421
- for (const alias of aliases) {
63422
- for (const item of alias.use) {
63423
- result.push(
63424
- `${alias.name}, ${item.snapshot.version}, ${item.balance ? `${item.balance}%` : "shadow"}`
63425
- );
63426
- }
63427
- }
63428
- task.output = result.join("\n");
63429
- }
63430
- },
63431
- rendererOptions: {
63432
- persistentOutput: true
63433
- }
63434
- }
63435
- ],
63436
- {
63437
- renderer: "default",
63438
- rendererOptions: {
63439
- logger: new ListrLogger({
63440
- processOutput: new ProcessOutput(process.stderr, process.stderr)
63441
- })
63442
- }
63443
- }
63444
- ).run();
63445
- }
62928
+ warn(message2) {
62929
+ if (this.logLevel >= 1 /* WARN */) {
62930
+ this.task.output = message2;
62931
+ }
62932
+ }
63446
62933
  };
63447
62934
 
63448
- // packages/kong-cli/src/commands/listVersionsCommand.ts
63449
- var ListVersionsCommand = class {
63450
- constructor(profile, verbose) {
62935
+ // packages/kong-cli/src/commands/installCommand.ts
62936
+ var InstallCommand = class {
62937
+ constructor(verbose) {
63451
62938
  this.verbose = verbose;
63452
- this.managementClient = new ManagementClient(
63453
- profile.kongBaseUrl,
63454
- requestConfigProvider(profile)
63455
- );
63456
62939
  }
63457
- async execute(processId) {
63458
- await new Listr(
63459
- [
63460
- {
63461
- title: processId ? `list process snapshot versions (${processId})` : "list extension snapshot versions",
63462
- task: async (ctx, task) => {
63463
- const versions = processId ? await this.managementClient.getDocumentSnapshotVersions(
63464
- processId
63465
- ) : await this.managementClient.getExtensionSnapshotVersions(getKongJson().id);
63466
- if (versions.length === 0) {
63467
- task.output = "no versions available";
63468
- } else {
63469
- const result = [];
63470
- for (const ver of versions) {
63471
- result.push(
63472
- `${ver.version}, ${ver.created}, ${ver.createdBy}, ${ver.notes || "no notes"}`
63473
- );
63474
- }
63475
- task.output = result.join("\n");
63476
- }
63477
- },
63478
- rendererOptions: {
63479
- persistentOutput: true
63480
- }
63481
- }
63482
- ],
62940
+ async execute(workspaceDirectory) {
62941
+ await new Listr([
63483
62942
  {
63484
- renderer: "default",
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
+ },
63485
62953
  rendererOptions: {
63486
- logger: new ListrLogger({
63487
- processOutput: new ProcessOutput(process.stderr, process.stderr)
63488
- })
62954
+ bottomBar: this.verbose ? Infinity : true,
62955
+ persistentOutput: true
63489
62956
  }
63490
62957
  }
63491
- ).run();
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`);
63492
62966
  }
63493
62967
  };
63494
62968
 
63495
62969
  // packages/kong-cli/src/commands/publishVersionCommand.ts
63496
- var import_child_process3 = require("child_process");
62970
+ var import_child_process2 = require("child_process");
63497
62971
 
63498
62972
  // packages/kong-cli/src/common/extensionContract.ts
63499
62973
  var import__ = __toESM(require__());
@@ -63509,7 +62983,188 @@ function getExtensionContract(filePath) {
63509
62983
  return contract;
63510
62984
  }
63511
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
+
63512
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
+ }
63513
63168
  var PublishVersionCommand = class {
63514
63169
  constructor(profile, verbose = false, contractPath = null) {
63515
63170
  this.profile = profile;
@@ -63523,14 +63178,36 @@ var PublishVersionCommand = class {
63523
63178
  const clientRequestConfigProvider = requestConfigProvider(profile);
63524
63179
  this.registryClient = new RegistryClient(profile.kongBaseUrl, clientRequestConfigProvider);
63525
63180
  this.managementClient = new ManagementClient(profile.kongBaseUrl, clientRequestConfigProvider);
63526
- const dockerVersion = (0, import_child_process3.spawnSync)("docker", ["--version"]);
63181
+ const dockerVersion = (0, import_child_process2.spawnSync)("docker", ["--version"]);
63527
63182
  this.hasDocker = !dockerVersion.error;
63528
63183
  }
63529
63184
  get wslPrefix() {
63530
63185
  return this.isWin && !this.hasDocker ? "wsl" : "";
63531
63186
  }
63532
- async execute(appName, notes) {
63533
- await new Listr([...this.flowFactory(appName, notes)], {
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, {
63534
63211
  renderer: "default",
63535
63212
  rendererOptions: {
63536
63213
  logger: new ListrLogger({
@@ -63538,6 +63215,7 @@ var PublishVersionCommand = class {
63538
63215
  })
63539
63216
  }
63540
63217
  }).run();
63218
+ return Number(ctx.publishDetails?.imageVersion ?? NaN);
63541
63219
  }
63542
63220
  *flowFactory(appName, notes) {
63543
63221
  const kongJson = getKongJson();
@@ -63563,7 +63241,8 @@ var PublishVersionCommand = class {
63563
63241
  } else {
63564
63242
  const isPythonSdk = kongJson.sdk === "python";
63565
63243
  const cmdText = isPythonSdk ? this.getPythonSchemaCmdText() : this.getKotlinSchemaCmdTask();
63566
- ctx.contractText = await spawnCommand(cmdText, logger, !isPythonSdk);
63244
+ const raw = await spawnCommand(cmdText, logger, !isPythonSdk);
63245
+ ctx.contractText = isPythonSdk ? extractJsonObject(raw) : raw;
63567
63246
  }
63568
63247
  },
63569
63248
  rendererOptions: this.defaultRendererOptions
@@ -63602,7 +63281,7 @@ var PublishVersionCommand = class {
63602
63281
  yield {
63603
63282
  title: "docker push",
63604
63283
  task: async (ctx, task) => {
63605
- const cmd = this.dockerPushCmdText(ctx.fullImageName);
63284
+ const cmd = this.dockerPushCmdText(notNull(ctx.fullImageName));
63606
63285
  await spawnCommand(
63607
63286
  cmd,
63608
63287
  new ListrTaskLogger(task, this.verbose ? 3 /* DEBUG */ : 0 /* INFO */)
@@ -63713,6 +63392,412 @@ var PublishVersionCommand = class {
63713
63392
  }
63714
63393
  };
63715
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();
63424
+ }
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
+ }
63432
+ });
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();
63460
+ return;
63461
+ }
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;
63466
+ }
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;
63471
+ }
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;
63476
+ }
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;
63486
+ }
63487
+ this.json(response, 404, { error: `unknown route ${request.method} ${url2.pathname}` });
63488
+ }
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
+ };
63497
+ }
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
+ });
63522
+ }
63523
+ /**
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 };
63545
+ }
63546
+ /**
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);
63578
+ }
63579
+ });
63580
+ }
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
+ );
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;
63611
+ }
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);
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) };
63627
+ }
63628
+ cleanupTemplates() {
63629
+ for (const { parent } of this.templates.values()) {
63630
+ import_fs5.default.rmSync(parent, { recursive: true, force: true });
63631
+ }
63632
+ this.templates.clear();
63633
+ }
63634
+ setStep(job, name, status) {
63635
+ const step = job.steps.find((item) => item.name === name);
63636
+ if (step) {
63637
+ step.status = status;
63638
+ }
63639
+ job.output = `${job.output}${name}: ${status}
63640
+ `;
63641
+ }
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;
63649
+ }
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);
63674
+ }
63675
+ child.stdin.end();
63676
+ });
63677
+ }
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));
63695
+ }
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
+ }
63705
+
63706
+ // packages/kong-cli/src/commands/listAliasesCommand.ts
63707
+ var ListAliasesCommand = class {
63708
+ constructor(profile, verbose) {
63709
+ this.profile = profile;
63710
+ this.verbose = verbose;
63711
+ this.managementClient = new ManagementClient(
63712
+ this.profile.kongBaseUrl,
63713
+ requestConfigProvider(profile)
63714
+ );
63715
+ }
63716
+ async execute(processId) {
63717
+ await new Listr(
63718
+ [
63719
+ {
63720
+ title: processId ? `list process aliases (${processId})` : "list extension aliases",
63721
+ task: async (ctx, task) => {
63722
+ const aliases = processId ? await this.managementClient.getProcessAliases(processId) : await this.managementClient.getExtensionSnapshotAliases(getKongJson().id);
63723
+ if (aliases.length === 0) {
63724
+ task.output = "no aliases available";
63725
+ } else {
63726
+ const result = [];
63727
+ for (const alias of aliases) {
63728
+ for (const item of alias.use) {
63729
+ result.push(
63730
+ `${alias.name}, ${item.snapshot.version}, ${item.balance ? `${item.balance}%` : "shadow"}`
63731
+ );
63732
+ }
63733
+ }
63734
+ task.output = result.join("\n");
63735
+ }
63736
+ },
63737
+ rendererOptions: {
63738
+ persistentOutput: true
63739
+ }
63740
+ }
63741
+ ],
63742
+ {
63743
+ renderer: "default",
63744
+ rendererOptions: {
63745
+ logger: new ListrLogger({
63746
+ processOutput: new ProcessOutput(process.stderr, process.stderr)
63747
+ })
63748
+ }
63749
+ }
63750
+ ).run();
63751
+ }
63752
+ };
63753
+
63754
+ // packages/kong-cli/src/commands/listVersionsCommand.ts
63755
+ var ListVersionsCommand = class {
63756
+ constructor(profile, verbose) {
63757
+ this.verbose = verbose;
63758
+ this.managementClient = new ManagementClient(
63759
+ profile.kongBaseUrl,
63760
+ requestConfigProvider(profile)
63761
+ );
63762
+ }
63763
+ async execute(processId) {
63764
+ await new Listr(
63765
+ [
63766
+ {
63767
+ title: processId ? `list process snapshot versions (${processId})` : "list extension snapshot versions",
63768
+ task: async (ctx, task) => {
63769
+ const versions = processId ? await this.managementClient.getDocumentSnapshotVersions(
63770
+ processId
63771
+ ) : await this.managementClient.getExtensionSnapshotVersions(getKongJson().id);
63772
+ if (versions.length === 0) {
63773
+ task.output = "no versions available";
63774
+ } else {
63775
+ const result = [];
63776
+ for (const ver of versions) {
63777
+ result.push(
63778
+ `${ver.version}, ${ver.created}, ${ver.createdBy}, ${ver.notes || "no notes"}`
63779
+ );
63780
+ }
63781
+ task.output = result.join("\n");
63782
+ }
63783
+ },
63784
+ rendererOptions: {
63785
+ persistentOutput: true
63786
+ }
63787
+ }
63788
+ ],
63789
+ {
63790
+ renderer: "default",
63791
+ rendererOptions: {
63792
+ logger: new ListrLogger({
63793
+ processOutput: new ProcessOutput(process.stderr, process.stderr)
63794
+ })
63795
+ }
63796
+ }
63797
+ ).run();
63798
+ }
63799
+ };
63800
+
63716
63801
  // packages/kong-cli/src/common/deployment.ts
63717
63802
  var DEPLOY_SUCCESS_ACTIONS = /* @__PURE__ */ new Set(["deployment completed"]);
63718
63803
  var DEPLOY_FAILURE_ACTIONS = /* @__PURE__ */ new Set(["deployment failed"]);
@@ -63860,13 +63945,13 @@ function parseVersionWeightList(list) {
63860
63945
  }
63861
63946
  return uses;
63862
63947
  }
63863
- var DEPLOY_STEPS = [
63948
+ var DEPLOY_STEPS2 = [
63864
63949
  "create deployment",
63865
63950
  "save deployment details",
63866
63951
  "deployment completed"
63867
63952
  ];
63868
63953
  function createDeploySteps() {
63869
- return DEPLOY_STEPS.map((action) => {
63954
+ return DEPLOY_STEPS2.map((action) => {
63870
63955
  const handlers = {
63871
63956
  resolve: () => void 0,
63872
63957
  reject: () => void 0
@@ -63999,17 +64084,6 @@ var SetAliasCommand = class {
63999
64084
  }
64000
64085
  };
64001
64086
 
64002
- // packages/kong-cli/src/common/cli.ts
64003
- var import_fs5 = __toESM(require("fs"));
64004
- var import_path6 = __toESM(require("path"));
64005
- function getPresetVersion() {
64006
- const packageJsonPath = import_path6.default.join(__dirname, "package.json");
64007
- if (!import_fs5.default.existsSync(packageJsonPath)) {
64008
- throw new AppError(`package.json file was not found at path: ${packageJsonPath}`);
64009
- }
64010
- return require(packageJsonPath).version;
64011
- }
64012
-
64013
64087
  // packages/kong-cli/src/index.ts
64014
64088
  import_dotenv_expand.default.expand(import_dotenv.default.config({ path: import_path7.default.join(__dirname, ".env"), quiet: true }));
64015
64089
  async function main() {