@ones-open/cli 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/index.cjs +632 -91
  2. package/dist/index.js +633 -92
  3. package/dist/types/actions/app/resolve.d.ts +10 -0
  4. package/dist/types/actions/app/resolve.d.ts.map +1 -0
  5. package/dist/types/actions/dev/index.d.ts.map +1 -1
  6. package/dist/types/actions/disable/index.d.ts.map +1 -1
  7. package/dist/types/actions/disable/normalize.d.ts.map +1 -1
  8. package/dist/types/actions/enable/index.d.ts.map +1 -1
  9. package/dist/types/actions/enable/normalize.d.ts.map +1 -1
  10. package/dist/types/actions/index.d.ts +2 -0
  11. package/dist/types/actions/index.d.ts.map +1 -1
  12. package/dist/types/actions/install/index.d.ts.map +1 -1
  13. package/dist/types/actions/install/install.d.ts +2 -1
  14. package/dist/types/actions/install/install.d.ts.map +1 -1
  15. package/dist/types/actions/install/normalize.d.ts.map +1 -1
  16. package/dist/types/actions/logs/index.d.ts +4 -0
  17. package/dist/types/actions/logs/index.d.ts.map +1 -0
  18. package/dist/types/actions/logs/normalize.d.ts +11 -0
  19. package/dist/types/actions/logs/normalize.d.ts.map +1 -0
  20. package/dist/types/actions/specs-fetch/index.d.ts +4 -0
  21. package/dist/types/actions/specs-fetch/index.d.ts.map +1 -0
  22. package/dist/types/actions/specs-fetch/normalize.d.ts +6 -0
  23. package/dist/types/actions/specs-fetch/normalize.d.ts.map +1 -0
  24. package/dist/types/actions/uninstall/index.d.ts.map +1 -1
  25. package/dist/types/actions/uninstall/normalize.d.ts.map +1 -1
  26. package/dist/types/cli/index.d.ts.map +1 -1
  27. package/dist/types/command/app/index.d.ts.map +1 -1
  28. package/dist/types/command/disable/index.d.ts +1 -1
  29. package/dist/types/command/disable/index.d.ts.map +1 -1
  30. package/dist/types/command/enable/index.d.ts +1 -1
  31. package/dist/types/command/enable/index.d.ts.map +1 -1
  32. package/dist/types/command/index.d.ts +3 -0
  33. package/dist/types/command/index.d.ts.map +1 -1
  34. package/dist/types/command/install/index.d.ts +1 -1
  35. package/dist/types/command/install/index.d.ts.map +1 -1
  36. package/dist/types/command/logs/index.d.ts +10 -0
  37. package/dist/types/command/logs/index.d.ts.map +1 -0
  38. package/dist/types/command/specs/index.d.ts +4 -0
  39. package/dist/types/command/specs/index.d.ts.map +1 -0
  40. package/dist/types/command/specs-fetch/index.d.ts +13 -0
  41. package/dist/types/command/specs-fetch/index.d.ts.map +1 -0
  42. package/dist/types/command/uninstall/index.d.ts +1 -1
  43. package/dist/types/command/uninstall/index.d.ts.map +1 -1
  44. package/dist/types/common/error/enums.d.ts +5 -1
  45. package/dist/types/common/error/enums.d.ts.map +1 -1
  46. package/dist/types/common/locales/en/index.d.ts +18 -0
  47. package/dist/types/common/locales/en/index.d.ts.map +1 -1
  48. package/dist/types/common/package/utils.d.ts +1 -0
  49. package/dist/types/common/package/utils.d.ts.map +1 -1
  50. package/dist/types/common/request/consts.d.ts +1 -0
  51. package/dist/types/common/request/consts.d.ts.map +1 -1
  52. package/dist/types/common/request/fetch.d.ts +2 -1
  53. package/dist/types/common/request/fetch.d.ts.map +1 -1
  54. package/dist/types/common/request/types.d.ts +20 -7
  55. package/dist/types/common/request/types.d.ts.map +1 -1
  56. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -3,13 +3,14 @@ import { Command } from "commander";
3
3
  import { ErrorCode as ErrorCode$1, AppPackageJSONSchema, throwError, AppManifestJSONSchema, getPublicPath, PUBLIC_FILENAME, AppRcJSONSchema, AppManifestStrictJSONSchema, getCommandOptions, HostedTokenScope, addCommandUsage, addCommandOutput, $create as $create$1, setContext } from "create-ones-app";
4
4
  import { dirname, join, resolve, basename } from "node:path";
5
5
  import { spawnSync, spawn } from "node:child_process";
6
- import { readFileSync, createWriteStream } from "node:fs";
6
+ import { readFileSync, createWriteStream, createReadStream } from "node:fs";
7
7
  import fse from "fs-extra";
8
8
  import archiver from "archiver";
9
9
  import { get, merge, random, noop } from "lodash-es";
10
10
  import process$1, { cwd } from "node:process";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import { cosmiconfig } from "cosmiconfig";
13
+ import { createConnection } from "node:net";
13
14
  import getPort from "get-port";
14
15
  import envPaths from "env-paths";
15
16
  import { z } from "zod";
@@ -21,6 +22,9 @@ import http from "node:http";
21
22
  import open from "open";
22
23
  import { v4 } from "uuid";
23
24
  import PKCEChallenge from "pkce-challenge";
25
+ import { createHash } from "node:crypto";
26
+ import { pipeline } from "node:stream/promises";
27
+ import { homedir } from "node:os";
24
28
  const en = {
25
29
  "desc.ones": "ONES CLI/{env}",
26
30
  "desc.build": "Build your ONES App",
@@ -37,10 +41,21 @@ const en = {
37
41
  "desc.logout": "Log out of your ONES account",
38
42
  "desc.whoami": "Display the account information of the logged in user",
39
43
  "desc.app": "Manage app installations",
44
+ "desc.specs": "Manage ONES app specs resources to build your ONES App",
45
+ "desc.specs.fetch": "Fetch ONES app specs (download, checksum verify, and extract by default)",
46
+ "desc.specs.fetch.baseUrl": "Specify the base URL for specs resources",
47
+ "desc.specs.fetch.dir": "Specify the base directory (specs saved to <dir>/.ones/ones-app-specs)",
48
+ "desc.specs.fetch.noExtract": "Download only, do not extract archive automatically",
49
+ "desc.specs.fetch.json": "Output result in JSON format",
50
+ "desc.specs.fetch.force": "Force fetch even when local checksum is already up to date",
40
51
  "desc.install": "Install your ONES App",
41
52
  "desc.enable": "Enable your ONES App",
42
53
  "desc.disable": "Disable your ONES App",
43
54
  "desc.uninstall": "Uninstall your ONES App",
55
+ "desc.app.appId": "Specify app id",
56
+ "desc.logs": "View runtime logs for your ONES App",
57
+ "desc.logs.fromOpkxJson": "Read app id from local opkx.json when app id is not provided",
58
+ "desc.logs.tail": "Specify latest log lines to fetch (default 100)",
44
59
  "desc.legacy": "Legacy command",
45
60
  "desc.legacy.create": "Create a new ONES plugin",
46
61
  "desc.legacy.create.projectPath": "Specify the project path",
@@ -58,7 +73,14 @@ const en = {
58
73
  "error.store.permission": 'Permission denied, please check the file permission with "{filePath}"',
59
74
  "error.hostedToken.requestFailed": "Failed to request hosted token",
60
75
  "error.hostedToken.empty": "Hosted token is empty",
61
- "error.legacy.create.missingProjectPath": "Project path is required"
76
+ "error.legacy.create.missingProjectPath": "Project path is required",
77
+ "error.specs.fetch.incorrectBaseURL": "Incorrect specs base URL",
78
+ "error.specs.fetch.fetchChecksumFailed": 'Failed to fetch checksum file from "{url}"',
79
+ "error.specs.fetch.incorrectChecksum": 'Invalid checksum content. Please provide a correct base URL that serves "ones-app-specs.sha256" in format "<sha256> <zip-file>". Received: "{preview}"',
80
+ "error.specs.fetch.downloadFailed": 'Failed to download specs archive from "{url}"',
81
+ "error.specs.fetch.extractFailed": 'Failed to extract archive "{file}": {reason}',
82
+ "error.specs.fetch.cleanupFailed": 'Failed to cleanup archive "{file}": {reason}',
83
+ "error.specs.fetch.verifyChecksumFailed": 'SHA256 verification failed, expected "{expected}" but got "{actual}"'
62
84
  };
63
85
  const map = {
64
86
  en
@@ -105,6 +127,10 @@ var ErrorCode = ((ErrorCode2) => {
105
127
  ErrorCode2["HOSTED_TOKEN_EMPTY"] = "E14";
106
128
  ErrorCode2["INCORRECT_DEV_COMMAND"] = "E15";
107
129
  ErrorCode2["INCORRECT_BUILD_COMMAND"] = "E16";
130
+ ErrorCode2["INCORRECT_SPECS_BASE_URL"] = "E17";
131
+ ErrorCode2["INCORRECT_SPECS_CHECKSUM"] = "E18";
132
+ ErrorCode2["SPECS_FETCH_FAILED"] = "E19";
133
+ ErrorCode2["SPECS_CHECKSUM_MISMATCH"] = "E20";
108
134
  return ErrorCode2;
109
135
  })(ErrorCode || {});
110
136
  const getPackageJSONPath = () => {
@@ -158,6 +184,18 @@ const getAppManifestJSON = () => {
158
184
  return throwError(ErrorCode.APP_MANIFEST_JSON_PARSE_ERROR, `${i18n.t("error.schema.app.manifest.parseError")}: ${details}`);
159
185
  }
160
186
  };
187
+ const tryGetAppManifestJSON = function() {
188
+ let path = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getAppManifestJSONPath();
189
+ try {
190
+ const string = readFileSync(path, {
191
+ encoding: "utf8"
192
+ });
193
+ const json = JSON.parse(string);
194
+ return AppManifestJSONSchema.parse(json);
195
+ } catch (error) {
196
+ return null;
197
+ }
198
+ };
161
199
  const validateAppManifestJSON = () => {
162
200
  const appManifestJSON = getAppManifestJSON();
163
201
  try {
@@ -209,7 +247,7 @@ const getAppRcJSON = async () => {
209
247
  };
210
248
  const isOPKXFilename = /\.opkx$/;
211
249
  const defaultOutputPath = "";
212
- const normalize$a = async (options) => {
250
+ const normalize$c = async (options) => {
213
251
  var _options$output, _options$command;
214
252
  let output = resolve(cwd(), (_options$output = options.output) !== null && _options$output !== void 0 ? _options$output : defaultOutputPath);
215
253
  const command = (_options$command = options.command) !== null && _options$command !== void 0 ? _options$command : "";
@@ -228,7 +266,7 @@ const normalize$a = async (options) => {
228
266
  };
229
267
  const {
230
268
  existsSync,
231
- ensureDirSync
269
+ ensureDirSync: ensureDirSync$1
232
270
  } = fse;
233
271
  const build = async function() {
234
272
  var _appRcJSON$dev, _defaultAppRcJSON$dev, _appRcJSON$build$comm, _appRcJSON$build, _currentCommand$, _appRcJSON$build$comp, _appRcJSON$build2;
@@ -238,7 +276,7 @@ const build = async function() {
238
276
  const {
239
277
  options
240
278
  } = getCommandOptions(args, buildCommandArguments);
241
- const normalizedOptions = await normalize$a(options);
279
+ const normalizedOptions = await normalize$c(options);
242
280
  const appManifestJSON = getAppManifestJSON();
243
281
  const appRcJSON = await getAppRcJSON();
244
282
  const correctCommand = normalizedOptions.command || ((_appRcJSON$dev = appRcJSON.dev) === null || _appRcJSON$dev === void 0 || (_appRcJSON$dev = _appRcJSON$dev.command) === null || _appRcJSON$dev === void 0 ? void 0 : _appRcJSON$dev[0]) || ((_defaultAppRcJSON$dev = defaultAppRcJSON.dev) === null || _defaultAppRcJSON$dev === void 0 || (_defaultAppRcJSON$dev = _defaultAppRcJSON$dev.command) === null || _defaultAppRcJSON$dev === void 0 ? void 0 : _defaultAppRcJSON$dev[0]) || "";
@@ -286,7 +324,7 @@ const build = async function() {
286
324
  const outputPath = normalizedOptions.output;
287
325
  const outputDir = dirname(outputPath);
288
326
  const outputFilename = basename(outputPath);
289
- ensureDirSync(outputDir);
327
+ ensureDirSync$1(outputDir);
290
328
  const outputStream = createWriteStream(outputPath);
291
329
  const files = (_appRcJSON$build$comp = (_appRcJSON$build2 = appRcJSON.build) === null || _appRcJSON$build2 === void 0 || (_appRcJSON$build2 = _appRcJSON$build2.compress) === null || _appRcJSON$build2 === void 0 ? void 0 : _appRcJSON$build2.files) !== null && _appRcJSON$build$comp !== void 0 ? _appRcJSON$build$comp : [];
292
330
  const archive = archiver("zip", {
@@ -460,6 +498,7 @@ const API = {
460
498
  APP_ENABLE: "/platform/api/app/:installation_id/enable",
461
499
  APP_DISABLE: "/platform/api/app/:installation_id/disable",
462
500
  OAUTH_TOKEN: "/identity/oauth/token",
501
+ APP_RUNTIME_LOGS: "/platform/runtime_manager/app/runtime/logs",
463
502
  REFRESH_TOKEN: "/identity/oauth/token"
464
503
  };
465
504
  const REQUEST_TIMEOUT = 1e4;
@@ -650,12 +689,36 @@ const fetchHostedAbilityStorageDevDeclare = async (appID, data) => {
650
689
  data
651
690
  }).catch(handleError);
652
691
  };
653
- const fetchAppInstall = async (data) => {
654
- var _appList$data$0$insta, _appList$data;
655
- const appID = getAppManifestJSON().app.id;
692
+ const getAppInstallation = async (appID) => {
693
+ var _appList$data$, _appList$data, _appData$installation, _appData$app_env;
656
694
  const appList = await fetchAppList(appID);
657
- const installationID = (_appList$data$0$insta = (_appList$data = appList.data) === null || _appList$data === void 0 || (_appList$data = _appList$data[0]) === null || _appList$data === void 0 ? void 0 : _appList$data.installation_id) !== null && _appList$data$0$insta !== void 0 ? _appList$data$0$insta : "";
695
+ const appData = (_appList$data$ = (_appList$data = appList.data) === null || _appList$data === void 0 ? void 0 : _appList$data[0]) !== null && _appList$data$ !== void 0 ? _appList$data$ : {};
696
+ return {
697
+ installationID: (_appData$installation = appData.installation_id) !== null && _appData$installation !== void 0 ? _appData$installation : "",
698
+ appEnv: (_appData$app_env = appData.app_env) !== null && _appData$app_env !== void 0 ? _appData$app_env : "development"
699
+ };
700
+ };
701
+ const consoleProductionNotAllowedMessage = (operation) => {
702
+ console.log(`Cannot run "${operation}" in "production" environment`);
703
+ process.exit(1);
704
+ };
705
+ const getDisplayAppEnv = (appEnv) => {
706
+ return appEnv === "production" ? "production" : "development";
707
+ };
708
+ const consoleAppEnvMessage = (operation, appEnv) => {
709
+ console.log(`Operating "${operation}" in "${appEnv}" environment`);
710
+ };
711
+ const fetchAppInstall = async (appID, data) => {
712
+ const {
713
+ installationID,
714
+ appEnv
715
+ } = await getAppInstallation(appID);
658
716
  if (installationID) {
717
+ if (appEnv === "production") {
718
+ consoleProductionNotAllowedMessage("install");
719
+ }
720
+ const displayAppEnv = getDisplayAppEnv(appEnv);
721
+ consoleAppEnvMessage("install", displayAppEnv);
659
722
  return await fetchAppBase({
660
723
  url: API.APP_UPGRADE,
661
724
  method: "POST",
@@ -665,18 +728,24 @@ const fetchAppInstall = async (data) => {
665
728
  data
666
729
  }).catch(handleError);
667
730
  }
731
+ consoleAppEnvMessage("install", "development");
668
732
  return await fetchAppBase({
669
733
  url: API.APP_INSTALL,
670
734
  method: "POST",
671
735
  data
672
736
  }).catch(handleError);
673
737
  };
674
- const fetchAppUninstall = async () => {
675
- var _appList$data$0$insta2, _appList$data2;
676
- const appID = getAppManifestJSON().app.id;
677
- const appList = await fetchAppList(appID);
678
- const installationID = (_appList$data$0$insta2 = (_appList$data2 = appList.data) === null || _appList$data2 === void 0 || (_appList$data2 = _appList$data2[0]) === null || _appList$data2 === void 0 ? void 0 : _appList$data2.installation_id) !== null && _appList$data$0$insta2 !== void 0 ? _appList$data$0$insta2 : "";
738
+ const fetchAppUninstall = async (appID) => {
739
+ const {
740
+ installationID,
741
+ appEnv
742
+ } = await getAppInstallation(appID);
679
743
  if (installationID) {
744
+ if (appEnv === "production") {
745
+ consoleProductionNotAllowedMessage("uninstall");
746
+ }
747
+ const displayAppEnv = getDisplayAppEnv(appEnv);
748
+ consoleAppEnvMessage("uninstall", displayAppEnv);
680
749
  return await fetchAppBase({
681
750
  url: API.APP_UNINSTALL,
682
751
  method: "POST",
@@ -688,12 +757,14 @@ const fetchAppUninstall = async () => {
688
757
  consoleAppNotInstalledMessage();
689
758
  process.exit(1);
690
759
  };
691
- const fetchAppEnable = async () => {
692
- var _appList$data$0$insta3, _appList$data3;
693
- const appID = getAppManifestJSON().app.id;
694
- const appList = await fetchAppList(appID);
695
- const installationID = (_appList$data$0$insta3 = (_appList$data3 = appList.data) === null || _appList$data3 === void 0 || (_appList$data3 = _appList$data3[0]) === null || _appList$data3 === void 0 ? void 0 : _appList$data3.installation_id) !== null && _appList$data$0$insta3 !== void 0 ? _appList$data$0$insta3 : "";
760
+ const fetchAppEnable = async (appID) => {
761
+ const {
762
+ installationID,
763
+ appEnv
764
+ } = await getAppInstallation(appID);
696
765
  if (installationID) {
766
+ const displayAppEnv = getDisplayAppEnv(appEnv);
767
+ consoleAppEnvMessage("enable", displayAppEnv);
697
768
  return await fetchAppBase({
698
769
  url: API.APP_ENABLE,
699
770
  method: "POST",
@@ -705,12 +776,14 @@ const fetchAppEnable = async () => {
705
776
  consoleAppNotInstalledMessage();
706
777
  process.exit(1);
707
778
  };
708
- const fetchAppDisable = async () => {
709
- var _appList$data$0$insta4, _appList$data4;
710
- const appID = getAppManifestJSON().app.id;
711
- const appList = await fetchAppList(appID);
712
- const installationID = (_appList$data$0$insta4 = (_appList$data4 = appList.data) === null || _appList$data4 === void 0 || (_appList$data4 = _appList$data4[0]) === null || _appList$data4 === void 0 ? void 0 : _appList$data4.installation_id) !== null && _appList$data$0$insta4 !== void 0 ? _appList$data$0$insta4 : "";
779
+ const fetchAppDisable = async (appID) => {
780
+ const {
781
+ installationID,
782
+ appEnv
783
+ } = await getAppInstallation(appID);
713
784
  if (installationID) {
785
+ const displayAppEnv = getDisplayAppEnv(appEnv);
786
+ consoleAppEnvMessage("disable", displayAppEnv);
714
787
  return await fetchAppBase({
715
788
  url: API.APP_DISABLE,
716
789
  method: "POST",
@@ -722,6 +795,13 @@ const fetchAppDisable = async () => {
722
795
  consoleAppNotInstalledMessage();
723
796
  process.exit(1);
724
797
  };
798
+ const fetchAppRuntimeLogs = async (data) => {
799
+ return await fetchAppBase({
800
+ url: API.APP_RUNTIME_LOGS,
801
+ method: "POST",
802
+ data
803
+ }).catch(handleError);
804
+ };
725
805
  const checkTokenInfo = async () => {
726
806
  let boolean = true;
727
807
  const regionURL = await getRegionURL().catch(() => "");
@@ -738,8 +818,28 @@ const checkTokenInfo = async () => {
738
818
  }
739
819
  return boolean;
740
820
  };
821
+ const resolveAppInfo = (input) => {
822
+ var _input$appID;
823
+ const appIDFromArgument = (_input$appID = input.appID) !== null && _input$appID !== void 0 ? _input$appID : "";
824
+ if (appIDFromArgument) {
825
+ return {
826
+ appID: appIDFromArgument,
827
+ appName: appIDFromArgument
828
+ };
829
+ }
830
+ const appManifestPath = input.opkxPath ? resolve(cwd(), input.opkxPath) : getAppManifestJSONPath();
831
+ const appManifestJSON = tryGetAppManifestJSON(appManifestPath);
832
+ if (appManifestJSON) {
833
+ return {
834
+ appID: appManifestJSON.app.id,
835
+ appName: appManifestJSON.app.name
836
+ };
837
+ }
838
+ console.log('Cannot read local "opkx.json". Please ensure "opkx.json" exists in the current directory, or provide an app ID.');
839
+ process.exit(1);
840
+ };
741
841
  const isPortNumber = /^[1-9]\d{0,4}$/;
742
- const normalize$9 = async (options) => {
842
+ const normalize$b = async (options) => {
743
843
  var _options$clearStorage;
744
844
  const portInput = options.port;
745
845
  if (portInput)
@@ -1103,7 +1203,7 @@ const tunnel = async function() {
1103
1203
  const {
1104
1204
  options
1105
1205
  } = getCommandOptions(args, tunnelCommandArguments);
1106
- const normalizedOptions = await normalize$9(options);
1206
+ const normalizedOptions = await normalize$b(options);
1107
1207
  const port = Number(normalizedOptions.port);
1108
1208
  const cancelWaiting = startWaiting();
1109
1209
  await invokeTunnel(port, {
@@ -1115,9 +1215,12 @@ const tunnel = async function() {
1115
1215
  const tunnelUrl = await buildTunnelUrl();
1116
1216
  console.log(`Relay endpoint: ${tunnelUrl}`);
1117
1217
  };
1118
- const normalize$8 = async (options) => {
1218
+ const normalize$a = async (options) => {
1219
+ var _options$appID;
1119
1220
  noop(options);
1120
- return {};
1221
+ return {
1222
+ appID: (_options$appID = options.appID) !== null && _options$appID !== void 0 ? _options$appID : ""
1223
+ };
1121
1224
  };
1122
1225
  const displayAppDetail = async (installationID) => {
1123
1226
  var _tokenInfo$org$uuid, _tokenInfo$org, _tokenInfo$teams$0$uu, _tokenInfo$teams, _tokenInfo$org$visibi, _tokenInfo$org2;
@@ -1135,14 +1238,10 @@ const displayAppDetail = async (installationID) => {
1135
1238
  console.log(`See App detail: ${url}`);
1136
1239
  }
1137
1240
  };
1138
- const invokeInstall = async (manifestUrl) => {
1139
- const {
1140
- app
1141
- } = getAppManifestJSON();
1142
- const appName = app.name;
1143
- const appID = app.id;
1241
+ const invokeInstall = async (manifestUrl, appInfo) => {
1242
+ const appID = appInfo.appID;
1144
1243
  const cancelWaiting = startWaiting();
1145
- const result = await fetchAppInstall({
1244
+ const result = await fetchAppInstall(appID, {
1146
1245
  manifest_url: manifestUrl,
1147
1246
  options: {
1148
1247
  enable: true
@@ -1151,7 +1250,7 @@ const invokeInstall = async (manifestUrl) => {
1151
1250
  cancelWaiting();
1152
1251
  if (result.code === "OK") {
1153
1252
  var _appList$data$0$insta, _appList$data;
1154
- console.log(`App "${appName}" installed successfully!`);
1253
+ console.log(`App "${appID}" installed successfully!`);
1155
1254
  const appList = await fetchAppList(appID);
1156
1255
  const installationID = (_appList$data$0$insta = (_appList$data = appList.data) === null || _appList$data === void 0 || (_appList$data = _appList$data[0]) === null || _appList$data === void 0 ? void 0 : _appList$data.installation_id) !== null && _appList$data$0$insta !== void 0 ? _appList$data$0$insta : "";
1157
1256
  if (installationID) {
@@ -1159,7 +1258,7 @@ const invokeInstall = async (manifestUrl) => {
1159
1258
  }
1160
1259
  return true;
1161
1260
  } else {
1162
- console.log(`App "${appName}" installed failed!`);
1261
+ console.log(`App "${appID}" installed failed!`);
1163
1262
  console.error(JSON.stringify(result, null, 2));
1164
1263
  }
1165
1264
  return false;
@@ -1199,19 +1298,19 @@ const install = async function() {
1199
1298
  const {
1200
1299
  options
1201
1300
  } = getCommandOptions(args, installCommandArguments);
1202
- const normalizedOptions = await normalize$8(options);
1301
+ const normalizedOptions = await normalize$a(options);
1203
1302
  noop(normalizedOptions);
1204
- const {
1205
- app
1206
- } = getAppManifestJSON();
1207
- const appName = app.name;
1303
+ const appInfo = resolveAppInfo({
1304
+ appID: options.appID
1305
+ });
1306
+ const appID = appInfo.appID;
1208
1307
  const manifestUrl = await getManifestUrl();
1209
1308
  if (!manifestUrl) {
1210
- console.log(`App "${appName}" server not available!`);
1309
+ console.log(`App "${appID}" server not available!`);
1211
1310
  console.log('Use "ones dev" command or "ones tunnel" command to start the server first');
1212
1311
  process.exit(1);
1213
1312
  }
1214
- await invokeInstall(manifestUrl);
1313
+ await invokeInstall(manifestUrl, appInfo);
1215
1314
  };
1216
1315
  var InstallOptions = /* @__PURE__ */ ((InstallOptions2) => {
1217
1316
  InstallOptions2["AUTO"] = "auto";
@@ -1226,7 +1325,7 @@ var DevCommandScripts = /* @__PURE__ */ ((DevCommandScripts2) => {
1226
1325
  return DevCommandScripts2;
1227
1326
  })(DevCommandScripts || {});
1228
1327
  const defaultInstall = InstallOptions.AUTO;
1229
- const normalize$7 = async (options) => {
1328
+ const normalize$9 = async (options) => {
1230
1329
  var _options$install, _options$command, _options$clearStorage;
1231
1330
  let install2 = (_options$install = options.install) !== null && _options$install !== void 0 ? _options$install : defaultInstall;
1232
1331
  const command = (_options$command = options.command) !== null && _options$command !== void 0 ? _options$command : "";
@@ -1248,6 +1347,47 @@ const normalize$7 = async (options) => {
1248
1347
  };
1249
1348
  };
1250
1349
  const IDLE_MS = 2e3;
1350
+ const WAIT_PORT_TIMEOUT_MS = 12e4;
1351
+ const WAIT_PORT_INTERVAL_MS = 500;
1352
+ const WAIT_PORT_CONNECT_TIMEOUT_MS = 1e3;
1353
+ const sleep$1 = (ms) => {
1354
+ return new Promise((resolve2) => {
1355
+ setTimeout(resolve2, ms);
1356
+ });
1357
+ };
1358
+ const canConnectPort = (port) => {
1359
+ return new Promise((resolve2) => {
1360
+ let settled = false;
1361
+ const socket = createConnection({
1362
+ host: "127.0.0.1",
1363
+ port
1364
+ });
1365
+ const done = (result) => {
1366
+ if (settled)
1367
+ return;
1368
+ settled = true;
1369
+ socket.removeAllListeners();
1370
+ socket.destroy();
1371
+ resolve2(result);
1372
+ };
1373
+ socket.setTimeout(WAIT_PORT_CONNECT_TIMEOUT_MS);
1374
+ socket.on("connect", () => done(true));
1375
+ socket.on("timeout", () => done(false));
1376
+ socket.on("error", () => done(false));
1377
+ });
1378
+ };
1379
+ const waitForPortReady = async function(port) {
1380
+ let timeoutMs = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : WAIT_PORT_TIMEOUT_MS;
1381
+ const startedAt = Date.now();
1382
+ while (Date.now() - startedAt < timeoutMs) {
1383
+ const connected = await canConnectPort(port);
1384
+ if (connected) {
1385
+ return true;
1386
+ }
1387
+ await sleep$1(WAIT_PORT_INTERVAL_MS);
1388
+ }
1389
+ return false;
1390
+ };
1251
1391
  const dev = async function() {
1252
1392
  var _appRcJSON$dev, _defaultAppRcJSON$dev, _appRcJSON$dev$comman, _appRcJSON$dev2, _currentCommand$;
1253
1393
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -1256,7 +1396,7 @@ const dev = async function() {
1256
1396
  const {
1257
1397
  options
1258
1398
  } = getCommandOptions(args, devCommandArguments);
1259
- const normalizedOptions = await normalize$7(options);
1399
+ const normalizedOptions = await normalize$9(options);
1260
1400
  const appRcJSON = await getAppRcJSON();
1261
1401
  const correctCommand = normalizedOptions.command || ((_appRcJSON$dev = appRcJSON.dev) === null || _appRcJSON$dev === void 0 || (_appRcJSON$dev = _appRcJSON$dev.command) === null || _appRcJSON$dev === void 0 ? void 0 : _appRcJSON$dev[0]) || ((_defaultAppRcJSON$dev = defaultAppRcJSON.dev) === null || _defaultAppRcJSON$dev === void 0 || (_defaultAppRcJSON$dev = _defaultAppRcJSON$dev.command) === null || _defaultAppRcJSON$dev === void 0 ? void 0 : _defaultAppRcJSON$dev[0]) || "";
1262
1402
  if (!correctCommand) {
@@ -1290,6 +1430,10 @@ const dev = async function() {
1290
1430
  app
1291
1431
  } = appManifestJSON;
1292
1432
  const appID = app.id;
1433
+ const appInfo = {
1434
+ appID: app.id,
1435
+ appName: app.name
1436
+ };
1293
1437
  const config2 = getConfig();
1294
1438
  const ONES_HOSTED_PORT = await getPort({
1295
1439
  port: config2.defaultPort.hosted
@@ -1346,7 +1490,7 @@ const dev = async function() {
1346
1490
  if (enableTunnel) {
1347
1491
  switch (normalizedOptions.install) {
1348
1492
  case InstallOptions.TRUE:
1349
- await invokeInstall(manifestUrl);
1493
+ await invokeInstall(manifestUrl, appInfo);
1350
1494
  break;
1351
1495
  case InstallOptions.AUTO:
1352
1496
  {
@@ -1356,7 +1500,7 @@ const dev = async function() {
1356
1500
  if (installationID) {
1357
1501
  await displayAppDetail(installationID);
1358
1502
  } else {
1359
- await invokeInstall(manifestUrl);
1503
+ await invokeInstall(manifestUrl, appInfo);
1360
1504
  }
1361
1505
  }
1362
1506
  break;
@@ -1375,6 +1519,28 @@ const dev = async function() {
1375
1519
  const createReadyStatusPipes = (onReady2) => {
1376
1520
  let readyTimer = null;
1377
1521
  let summaryPrinted = false;
1522
+ let readyInProgress = false;
1523
+ const printReady = async () => {
1524
+ if (summaryPrinted || readyInProgress) {
1525
+ return;
1526
+ }
1527
+ readyInProgress = true;
1528
+ try {
1529
+ if (templateCommand) {
1530
+ const ready = await waitForPortReady(ONES_HOSTED_PORT);
1531
+ if (!ready) {
1532
+ console.error(`Timed out waiting for local app server to listen on port ${ONES_HOSTED_PORT}.`);
1533
+ return;
1534
+ }
1535
+ }
1536
+ if (!summaryPrinted) {
1537
+ summaryPrinted = true;
1538
+ await onReady2();
1539
+ }
1540
+ } finally {
1541
+ readyInProgress = false;
1542
+ }
1543
+ };
1378
1544
  const scheduleReady = () => {
1379
1545
  if (summaryPrinted)
1380
1546
  return;
@@ -1382,10 +1548,9 @@ const dev = async function() {
1382
1548
  clearTimeout(readyTimer);
1383
1549
  readyTimer = setTimeout(() => {
1384
1550
  readyTimer = null;
1385
- if (!summaryPrinted) {
1386
- summaryPrinted = true;
1387
- onReady2();
1388
- }
1551
+ printReady().catch((error) => {
1552
+ console.error(error);
1553
+ });
1389
1554
  }, IDLE_MS);
1390
1555
  };
1391
1556
  const pipe2 = (stream, isStderr) => {
@@ -1457,7 +1622,7 @@ const sleep = (number) => {
1457
1622
  };
1458
1623
  const isURL = /^https?:\/\//;
1459
1624
  const HostBlackList = ["ones.cn", "www.ones.cn", "ones.com", "www.ones.com"];
1460
- const normalize$6 = async (options) => {
1625
+ const normalize$8 = async (options) => {
1461
1626
  const baseURLInput = options.baseURL;
1462
1627
  if (baseURLInput)
1463
1628
  ;
@@ -1495,7 +1660,7 @@ const login = async function() {
1495
1660
  const {
1496
1661
  options
1497
1662
  } = getCommandOptions(args, loginCommandArguments);
1498
- const normalizedOptions = await normalize$6(options);
1663
+ const normalizedOptions = await normalize$8(options);
1499
1664
  const {
1500
1665
  code_verifier,
1501
1666
  code_challenge
@@ -1648,7 +1813,7 @@ const login = async function() {
1648
1813
  return throwError(ErrorCode.INCORRECT_BASE_URL, i18n.t("error.login.incorrectBaseURL"));
1649
1814
  }
1650
1815
  };
1651
- const normalize$5 = async (options) => {
1816
+ const normalize$7 = async (options) => {
1652
1817
  noop(options);
1653
1818
  return {};
1654
1819
  };
@@ -1659,12 +1824,12 @@ const logout = async function() {
1659
1824
  const {
1660
1825
  options
1661
1826
  } = getCommandOptions(args, logoutCommandArguments);
1662
- const normalizedOptions = await normalize$5(options);
1827
+ const normalizedOptions = await normalize$7(options);
1663
1828
  noop(normalizedOptions);
1664
1829
  await setStore({});
1665
1830
  console.log("Logged out successfully!");
1666
1831
  };
1667
- const normalize$4 = async (options) => {
1832
+ const normalize$6 = async (options) => {
1668
1833
  noop(options);
1669
1834
  return {};
1670
1835
  };
@@ -1676,7 +1841,7 @@ const whoami = async function() {
1676
1841
  const {
1677
1842
  options
1678
1843
  } = getCommandOptions(args, whoamiCommandArguments);
1679
- const normalizedOptions = await normalize$4(options);
1844
+ const normalizedOptions = await normalize$6(options);
1680
1845
  noop(normalizedOptions);
1681
1846
  const baseURL = await getBaseURL();
1682
1847
  const cancelWaiting = startWaiting();
@@ -1692,9 +1857,12 @@ const whoami = async function() {
1692
1857
  consoleUnauthorizedMessage();
1693
1858
  }
1694
1859
  };
1695
- const normalize$3 = async (options) => {
1860
+ const normalize$5 = async (options) => {
1861
+ var _options$appID;
1696
1862
  noop(options);
1697
- return {};
1863
+ return {
1864
+ appID: (_options$appID = options.appID) !== null && _options$appID !== void 0 ? _options$appID : ""
1865
+ };
1698
1866
  };
1699
1867
  const enable = async function() {
1700
1868
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -1703,22 +1871,28 @@ const enable = async function() {
1703
1871
  const {
1704
1872
  options
1705
1873
  } = getCommandOptions(args, enableCommandArguments);
1706
- const normalizedOptions = await normalize$3(options);
1874
+ const normalizedOptions = await normalize$5(options);
1707
1875
  noop(normalizedOptions);
1708
- const appName = getAppManifestJSON().app.name;
1876
+ const appInfo = resolveAppInfo({
1877
+ appID: options.appID
1878
+ });
1879
+ const appID = appInfo.appID;
1709
1880
  const cancelWaiting = startWaiting();
1710
- const result = await fetchAppEnable();
1881
+ const result = await fetchAppEnable(appID);
1711
1882
  cancelWaiting();
1712
1883
  if (result.code === "OK") {
1713
- console.log(`App "${appName}" enabled successfully!`);
1884
+ console.log(`App "${appID}" enabled successfully!`);
1714
1885
  } else {
1715
- console.log(`App "${appName}" enabled failed!`);
1886
+ console.log(`App "${appID}" enabled failed!`);
1716
1887
  console.error(JSON.stringify(result, null, 2));
1717
1888
  }
1718
1889
  };
1719
- const normalize$2 = async (options) => {
1890
+ const normalize$4 = async (options) => {
1891
+ var _options$appID;
1720
1892
  noop(options);
1721
- return {};
1893
+ return {
1894
+ appID: (_options$appID = options.appID) !== null && _options$appID !== void 0 ? _options$appID : ""
1895
+ };
1722
1896
  };
1723
1897
  const disable = async function() {
1724
1898
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -1727,22 +1901,28 @@ const disable = async function() {
1727
1901
  const {
1728
1902
  options
1729
1903
  } = getCommandOptions(args, disableCommandArguments);
1730
- const normalizedOptions = await normalize$2(options);
1904
+ const normalizedOptions = await normalize$4(options);
1731
1905
  noop(normalizedOptions);
1732
- const appName = getAppManifestJSON().app.name;
1906
+ const appInfo = resolveAppInfo({
1907
+ appID: options.appID
1908
+ });
1909
+ const appID = appInfo.appID;
1733
1910
  const cancelWaiting = startWaiting();
1734
- const result = await fetchAppDisable();
1911
+ const result = await fetchAppDisable(appID);
1735
1912
  cancelWaiting();
1736
1913
  if (result.code === "OK") {
1737
- console.log(`App "${appName}" disabled successfully!`);
1914
+ console.log(`App "${appID}" disabled successfully!`);
1738
1915
  } else {
1739
- console.log(`App "${appName}" disabled failed!`);
1916
+ console.log(`App "${appID}" disabled failed!`);
1740
1917
  console.error(JSON.stringify(result, null, 2));
1741
1918
  }
1742
1919
  };
1743
- const normalize$1 = async (options) => {
1920
+ const normalize$3 = async (options) => {
1921
+ var _options$appID;
1744
1922
  noop(options);
1745
- return {};
1923
+ return {
1924
+ appID: (_options$appID = options.appID) !== null && _options$appID !== void 0 ? _options$appID : ""
1925
+ };
1746
1926
  };
1747
1927
  const uninstall = async function() {
1748
1928
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -1751,18 +1931,97 @@ const uninstall = async function() {
1751
1931
  const {
1752
1932
  options
1753
1933
  } = getCommandOptions(args, uninstallCommandArguments);
1754
- const normalizedOptions = await normalize$1(options);
1934
+ const normalizedOptions = await normalize$3(options);
1755
1935
  noop(normalizedOptions);
1756
- const appName = getAppManifestJSON().app.name;
1936
+ const appInfo = resolveAppInfo({
1937
+ appID: options.appID
1938
+ });
1939
+ const appID = appInfo.appID;
1757
1940
  const cancelWaiting = startWaiting();
1758
- const result = await fetchAppUninstall();
1941
+ const result = await fetchAppUninstall(appID);
1759
1942
  cancelWaiting();
1760
1943
  if (result.code === "OK") {
1761
- console.log(`App "${appName}" uninstalled successfully!`);
1944
+ console.log(`App "${appID}" uninstalled successfully!`);
1762
1945
  } else {
1763
- console.log(`App "${appName}" uninstalled failed!`);
1946
+ console.log(`App "${appID}" uninstalled failed!`);
1947
+ console.error(JSON.stringify(result, null, 2));
1948
+ }
1949
+ };
1950
+ const defaultTail = 100;
1951
+ const normalize$2 = async (options) => {
1952
+ var _options$appID, _options$fromOpkxJson, _options$tail;
1953
+ const appID = (_options$appID = options.appID) !== null && _options$appID !== void 0 ? _options$appID : "";
1954
+ const fromOpkxJSON = (_options$fromOpkxJson = options.fromOpkxJson) !== null && _options$fromOpkxJson !== void 0 ? _options$fromOpkxJson : false;
1955
+ if (!appID && !fromOpkxJSON) {
1956
+ console.log('App id is required, use "ones app logs <app-id>" or "--from-opkx-json"');
1957
+ process.exit(1);
1958
+ }
1959
+ const appInfo = appID ? resolveAppInfo({
1960
+ appID
1961
+ }) : resolveAppInfo({});
1962
+ const tailString = (_options$tail = options.tail) !== null && _options$tail !== void 0 ? _options$tail : `${defaultTail}`;
1963
+ const tail = Number(tailString);
1964
+ if (!Number.isInteger(tail) || tail <= 0) {
1965
+ console.log("Tail should be a positive integer");
1966
+ process.exit(1);
1967
+ }
1968
+ return {
1969
+ appID: appInfo.appID,
1970
+ appName: appInfo.appName,
1971
+ tail
1972
+ };
1973
+ };
1974
+ const displayLogs = (data) => {
1975
+ if (Array.isArray(data)) {
1976
+ data.forEach((line) => {
1977
+ if (typeof line === "string") {
1978
+ console.log(line);
1979
+ } else {
1980
+ console.log(JSON.stringify(line, null, 2));
1981
+ }
1982
+ });
1983
+ return;
1984
+ }
1985
+ if (typeof data === "string") {
1986
+ console.log(data);
1987
+ return;
1988
+ }
1989
+ console.log(JSON.stringify(data !== null && data !== void 0 ? data : {}, null, 2));
1990
+ };
1991
+ const logs = async function() {
1992
+ var _appList$data;
1993
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1994
+ args[_key] = arguments[_key];
1995
+ }
1996
+ const {
1997
+ options
1998
+ } = getCommandOptions(args, logsCommandArguments);
1999
+ const normalizedOptions = await normalize$2(options);
2000
+ const {
2001
+ appID,
2002
+ tail
2003
+ } = normalizedOptions;
2004
+ const cancelWaiting = startWaiting();
2005
+ const appList = await fetchAppList(appID);
2006
+ const productionInstallation = (_appList$data = appList.data) === null || _appList$data === void 0 ? void 0 : _appList$data.find((item) => {
2007
+ return item.installation_id && item.app_env === "production";
2008
+ });
2009
+ if (!productionInstallation) {
2010
+ cancelWaiting();
2011
+ console.log(`App "${appID}" is not installed in production environment`);
2012
+ process.exit(1);
2013
+ }
2014
+ const result = await fetchAppRuntimeLogs({
2015
+ app_id: appID,
2016
+ tail
2017
+ });
2018
+ cancelWaiting();
2019
+ if (result.code && result.code !== "OK") {
2020
+ console.log(`App "${appID}" fetch logs failed!`);
1764
2021
  console.error(JSON.stringify(result, null, 2));
2022
+ return;
1765
2023
  }
2024
+ displayLogs(result.data);
1766
2025
  };
1767
2026
  const getTemplatePath = () => {
1768
2027
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -1771,7 +2030,7 @@ const getTemplatePath = () => {
1771
2030
  const getTemplateLegacy = () => {
1772
2031
  return "legacy";
1773
2032
  };
1774
- const normalize = async (options) => {
2033
+ const normalize$1 = async (options) => {
1775
2034
  const projectPathInput = options.projectPath;
1776
2035
  if (projectPathInput)
1777
2036
  ;
@@ -1794,7 +2053,7 @@ const legacy = async function() {
1794
2053
  const {
1795
2054
  options
1796
2055
  } = getCommandOptions(args, legacyCommandArguments);
1797
- const normalizedOptions = await normalize(options);
2056
+ const normalizedOptions = await normalize$1(options);
1798
2057
  const {
1799
2058
  projectPath
1800
2059
  } = normalizedOptions;
@@ -1809,6 +2068,274 @@ const legacy = async function() {
1809
2068
  });
1810
2069
  console.log("Plugin created successfully!");
1811
2070
  };
2071
+ const defaultBaseURL = "https://open.ones.cn/";
2072
+ const defaultDir = "~/.ones/ones-app-specs";
2073
+ const expandHomeDirectory = (dir) => {
2074
+ if (dir === "~") {
2075
+ return homedir();
2076
+ }
2077
+ if (dir.startsWith("~/")) {
2078
+ return resolve(homedir(), dir.slice(2));
2079
+ }
2080
+ return dir;
2081
+ };
2082
+ const normalizeBaseURL = (baseURLInput) => {
2083
+ let url;
2084
+ try {
2085
+ url = new URL(baseURLInput);
2086
+ } catch (error) {
2087
+ return throwError(ErrorCode.INCORRECT_SPECS_BASE_URL, i18n.t("error.specs.fetch.incorrectBaseURL"));
2088
+ }
2089
+ if (url.protocol === "http:" || url.protocol === "https:")
2090
+ ;
2091
+ else {
2092
+ return throwError(ErrorCode.INCORRECT_SPECS_BASE_URL, i18n.t("error.specs.fetch.incorrectBaseURL"));
2093
+ }
2094
+ url.search = "";
2095
+ url.hash = "";
2096
+ if (!url.pathname.endsWith("/")) {
2097
+ url.pathname = `${url.pathname}/`;
2098
+ }
2099
+ return url.toString();
2100
+ };
2101
+ const normalize = async (options) => {
2102
+ var _options$baseUrl, _options$extract, _context, _options$json, _options$force;
2103
+ const baseUrl = normalizeBaseURL((_options$baseUrl = options.baseUrl) !== null && _options$baseUrl !== void 0 ? _options$baseUrl : defaultBaseURL);
2104
+ const dir = options.dir ? resolve(cwd(), expandHomeDirectory(options.dir), ".ones", "ones-app-specs") : resolve(cwd(), expandHomeDirectory(defaultDir));
2105
+ const extractString = `${(_options$extract = options.extract) !== null && _options$extract !== void 0 ? _options$extract : "true"}`.toLowerCase();
2106
+ const extract = _includesInstanceProperty(_context = ["false", "0", "no"]).call(_context, extractString) ? false : true;
2107
+ const json = (_options$json = options.json) !== null && _options$json !== void 0 ? _options$json : false;
2108
+ const force = (_options$force = options.force) !== null && _options$force !== void 0 ? _options$force : false;
2109
+ return {
2110
+ baseUrl,
2111
+ dir,
2112
+ extract,
2113
+ json,
2114
+ force
2115
+ };
2116
+ };
2117
+ const {
2118
+ ensureDirSync,
2119
+ writeFile,
2120
+ remove,
2121
+ pathExists,
2122
+ readFile
2123
+ } = fse;
2124
+ const CHECKSUM_FILENAME = "ones-app-specs.sha256";
2125
+ const DEFAULT_ARCHIVE_FILENAME = "ones-app-specs.zip";
2126
+ const DOWNLOAD_TIMEOUT = 6e4;
2127
+ const getShellSafePath = (value) => {
2128
+ return `'${value.replace(/'/g, `'\\''`)}'`;
2129
+ };
2130
+ const getExtractErrorOutput = (result) => {
2131
+ var _result$error;
2132
+ const output = [result.stderr, result.stdout].map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean).join("\n");
2133
+ if ((_result$error = result.error) !== null && _result$error !== void 0 && _result$error.message) {
2134
+ return result.error.message;
2135
+ }
2136
+ return output || "unknown error";
2137
+ };
2138
+ const extractArchive = (archivePath, dir) => {
2139
+ if (process.platform === "win32") {
2140
+ const powershellEscape = (value) => value.replace(/'/g, "''");
2141
+ const command = `Expand-Archive -LiteralPath '${powershellEscape(archivePath)}' -DestinationPath '${powershellEscape(dir)}' -Force`;
2142
+ const result2 = spawnSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", command], {
2143
+ encoding: "utf8"
2144
+ });
2145
+ if (result2.status === 0 && !result2.error) {
2146
+ return;
2147
+ }
2148
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.extractFailed", {
2149
+ file: archivePath,
2150
+ reason: getExtractErrorOutput(result2)
2151
+ }));
2152
+ }
2153
+ const result = spawnSync("unzip", ["-oq", archivePath, "-d", dir], {
2154
+ encoding: "utf8"
2155
+ });
2156
+ if (result.status === 0 && !result.error) {
2157
+ return;
2158
+ }
2159
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.extractFailed", {
2160
+ file: archivePath,
2161
+ reason: getExtractErrorOutput(result)
2162
+ }));
2163
+ };
2164
+ const parseChecksumValue = (text) => {
2165
+ var _match$;
2166
+ const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
2167
+ if (!firstLine) {
2168
+ return null;
2169
+ }
2170
+ const match = firstLine.match(/^([a-fA-F0-9]{64})(?:\s+\*?(.+))?$/);
2171
+ if (!match) {
2172
+ return null;
2173
+ }
2174
+ const checksum = match[1].toLowerCase();
2175
+ const archiveFilenameInput = ((_match$ = match[2]) !== null && _match$ !== void 0 ? _match$ : DEFAULT_ARCHIVE_FILENAME).trim();
2176
+ const archiveFilename = basename(archiveFilenameInput);
2177
+ if (!archiveFilename || archiveFilename !== archiveFilenameInput) {
2178
+ return null;
2179
+ }
2180
+ return {
2181
+ checksum,
2182
+ archiveFilename
2183
+ };
2184
+ };
2185
+ const parseChecksum = (text) => {
2186
+ var _text$split$find$trim, _text$split$find;
2187
+ const parsed = parseChecksumValue(text);
2188
+ if (parsed) {
2189
+ return parsed;
2190
+ }
2191
+ const firstLine = (_text$split$find$trim = (_text$split$find = text.split(/\r?\n/).find(Boolean)) === null || _text$split$find === void 0 ? void 0 : _text$split$find.trim()) !== null && _text$split$find$trim !== void 0 ? _text$split$find$trim : "";
2192
+ const preview = firstLine.slice(0, 120) || "<empty>";
2193
+ return throwError(ErrorCode.INCORRECT_SPECS_CHECKSUM, i18n.t("error.specs.fetch.incorrectChecksum", {
2194
+ preview
2195
+ }));
2196
+ };
2197
+ const getSHA256 = async (filePath) => {
2198
+ const hash = createHash("sha256");
2199
+ const stream = createReadStream(filePath);
2200
+ for await (const chunk of stream) {
2201
+ hash.update(chunk);
2202
+ }
2203
+ return hash.digest("hex");
2204
+ };
2205
+ const specsFetch = async function() {
2206
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
2207
+ args[_key] = arguments[_key];
2208
+ }
2209
+ const {
2210
+ options
2211
+ } = getCommandOptions(args, specsFetchCommandArguments);
2212
+ const normalizedOptions = await normalize(options);
2213
+ const baseURL = normalizedOptions.baseUrl;
2214
+ const dir = normalizedOptions.dir;
2215
+ const onesDir = dirname(dir);
2216
+ const shouldExtract = normalizedOptions.extract;
2217
+ const useJSONOutput = normalizedOptions.json;
2218
+ const forceFetch = normalizedOptions.force;
2219
+ ensureDirSync(dir);
2220
+ const checksumURL = new URL(CHECKSUM_FILENAME, baseURL).toString();
2221
+ const checksumText = await axios.get(checksumURL, {
2222
+ responseType: "text",
2223
+ timeout: REQUEST_TIMEOUT
2224
+ }).then((response2) => {
2225
+ var _response2$data;
2226
+ return `${(_response2$data = response2.data) !== null && _response2$data !== void 0 ? _response2$data : ""}`;
2227
+ }).catch(() => {
2228
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.fetchChecksumFailed", {
2229
+ url: checksumURL
2230
+ }));
2231
+ });
2232
+ const parsedChecksum = parseChecksum(checksumText);
2233
+ const archiveURL = new URL(parsedChecksum.archiveFilename, baseURL).toString();
2234
+ const archivePath = join(dir, parsedChecksum.archiveFilename);
2235
+ const checksumPath = join(dir, CHECKSUM_FILENAME);
2236
+ const localChecksum = await pathExists(checksumPath).then(async (exists) => {
2237
+ if (!exists) {
2238
+ return null;
2239
+ }
2240
+ const content = await readFile(checksumPath, "utf8");
2241
+ return parseChecksumValue(content);
2242
+ }).catch(() => null);
2243
+ if (!forceFetch && (localChecksum === null || localChecksum === void 0 ? void 0 : localChecksum.checksum) === parsedChecksum.checksum) {
2244
+ if (useJSONOutput) {
2245
+ console.log(JSON.stringify({
2246
+ status: "up_to_date",
2247
+ base_url: baseURL,
2248
+ download_dir: dir,
2249
+ specs_dir: dir,
2250
+ checksum_url: checksumURL,
2251
+ sha256: parsedChecksum.checksum,
2252
+ force: false,
2253
+ message: "Local ones-app-specs is already up to date."
2254
+ }, null, 2));
2255
+ return;
2256
+ }
2257
+ console.log("Local ones-app-specs is already up to date.");
2258
+ console.log(`SHA256: ${parsedChecksum.checksum}`);
2259
+ console.log(`Specs directory: ${dir}`);
2260
+ return;
2261
+ }
2262
+ const response = await axios({
2263
+ url: archiveURL,
2264
+ method: "GET",
2265
+ responseType: "stream",
2266
+ timeout: DOWNLOAD_TIMEOUT
2267
+ }).catch(() => {
2268
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.downloadFailed", {
2269
+ url: archiveURL
2270
+ }));
2271
+ });
2272
+ await pipeline(response.data, createWriteStream(archivePath)).catch(async () => {
2273
+ await remove(archivePath).catch(() => void 0);
2274
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.downloadFailed", {
2275
+ url: archiveURL
2276
+ }));
2277
+ });
2278
+ const actualChecksum = await getSHA256(archivePath);
2279
+ if (actualChecksum === parsedChecksum.checksum)
2280
+ ;
2281
+ else {
2282
+ await remove(archivePath).catch(() => void 0);
2283
+ return throwError(ErrorCode.SPECS_CHECKSUM_MISMATCH, i18n.t("error.specs.fetch.verifyChecksumFailed", {
2284
+ expected: parsedChecksum.checksum,
2285
+ actual: actualChecksum
2286
+ }));
2287
+ }
2288
+ const verifyCommand = `sha256sum -c ${getShellSafePath(checksumPath)}`;
2289
+ if (shouldExtract) {
2290
+ try {
2291
+ ensureDirSync(onesDir);
2292
+ extractArchive(archivePath, onesDir);
2293
+ await writeFile(checksumPath, `${parsedChecksum.checksum} ${parsedChecksum.archiveFilename}
2294
+ `, "utf8");
2295
+ await remove(archivePath).catch(() => void 0);
2296
+ } catch (error) {
2297
+ return throwError(ErrorCode.SPECS_FETCH_FAILED, i18n.t("error.specs.fetch.cleanupFailed", {
2298
+ file: archivePath,
2299
+ reason: `${error}`
2300
+ }));
2301
+ }
2302
+ } else {
2303
+ await writeFile(checksumPath, `${parsedChecksum.checksum} ${parsedChecksum.archiveFilename}
2304
+ `, "utf8");
2305
+ }
2306
+ if (useJSONOutput) {
2307
+ console.log(JSON.stringify({
2308
+ status: "success",
2309
+ base_url: baseURL,
2310
+ download_dir: dir,
2311
+ specs_dir: dir,
2312
+ checksum_url: checksumURL,
2313
+ archive_url: archiveURL,
2314
+ archive_path: archivePath,
2315
+ checksum_path: checksumPath,
2316
+ sha256: actualChecksum,
2317
+ force: forceFetch,
2318
+ extract: shouldExtract,
2319
+ archive_removed: shouldExtract,
2320
+ verify_command: shouldExtract ? null : verifyCommand
2321
+ }, null, 2));
2322
+ return;
2323
+ }
2324
+ console.log("ONES specs fetched successfully!");
2325
+ console.log(`SHA256: ${actualChecksum}`);
2326
+ console.log(`Specs directory: ${dir}`);
2327
+ console.log(`Base URL: ${baseURL}`);
2328
+ console.log(`Checksum URL: ${checksumURL}`);
2329
+ console.log(`Archive URL: ${archiveURL}`);
2330
+ console.log(`Archive path: ${archivePath}`);
2331
+ if (shouldExtract) {
2332
+ console.log("Archive extracted successfully!");
2333
+ console.log("Archive cleanup: enabled (source zip removed)");
2334
+ } else {
2335
+ console.log("Archive extraction: skipped");
2336
+ console.log(`Verify command: ${verifyCommand}`);
2337
+ }
2338
+ };
1812
2339
  const buildCommandArguments = [];
1813
2340
  const $build = new Command("build").description(i18n.t("desc.build")).option("-o, --output [file-path]", i18n.t("desc.build.output")).option("-c, --command [string]", i18n.t("desc.build.command")).action(build);
1814
2341
  addCommandUsage($build);
@@ -1833,26 +2360,40 @@ const whoamiCommandArguments = [];
1833
2360
  const $whoami = new Command("whoami").description(i18n.t("desc.whoami")).action(whoami);
1834
2361
  addCommandUsage($whoami);
1835
2362
  addCommandOutput($whoami);
1836
- const installCommandArguments = [];
1837
- const $install = new Command("install").description(i18n.t("desc.install")).action(install);
2363
+ const installCommandArguments = ["appID"];
2364
+ const $install = new Command("install").description(i18n.t("desc.install")).argument("[app-id]", i18n.t("desc.app.appId")).action(install);
1838
2365
  addCommandUsage($install);
1839
2366
  addCommandOutput($install);
1840
- const enableCommandArguments = [];
1841
- const $enable = new Command("enable").description(i18n.t("desc.enable")).action(enable);
2367
+ const enableCommandArguments = ["appID"];
2368
+ const $enable = new Command("enable").description(i18n.t("desc.enable")).argument("[app-id]", i18n.t("desc.app.appId")).action(enable);
1842
2369
  addCommandUsage($enable);
1843
2370
  addCommandOutput($enable);
1844
- const disableCommandArguments = [];
1845
- const $disable = new Command("disable").description(i18n.t("desc.disable")).action(disable);
2371
+ const disableCommandArguments = ["appID"];
2372
+ const $disable = new Command("disable").description(i18n.t("desc.disable")).argument("[app-id]", i18n.t("desc.app.appId")).action(disable);
1846
2373
  addCommandUsage($disable);
1847
2374
  addCommandOutput($disable);
1848
- const uninstallCommandArguments = [];
1849
- const $uninstall = new Command("uninstall").description(i18n.t("desc.uninstall")).action(uninstall);
2375
+ const uninstallCommandArguments = ["appID"];
2376
+ const $uninstall = new Command("uninstall").description(i18n.t("desc.uninstall")).argument("[app-id]", i18n.t("desc.app.appId")).action(uninstall);
1850
2377
  addCommandUsage($uninstall);
1851
2378
  addCommandOutput($uninstall);
2379
+ const logsCommandArguments = ["appID"];
2380
+ const $logs = new Command("logs").description(i18n.t("desc.logs")).argument("[app-id]", i18n.t("desc.app.appId")).option("--from-opkx-json", i18n.t("desc.logs.fromOpkxJson")).option("-t, --tail [number]", i18n.t("desc.logs.tail")).action(logs);
2381
+ addCommandUsage($logs);
2382
+ addCommandOutput($logs);
1852
2383
  const $app = new Command("app").description(i18n.t("desc.app"));
1853
- $app.addCommand($install).addCommand($enable).addCommand($disable).addCommand($uninstall);
2384
+ $app.addCommand($install).addCommand($enable).addCommand($disable).addCommand($uninstall).addCommand($logs);
1854
2385
  addCommandUsage($app);
1855
2386
  addCommandOutput($app);
2387
+ const specsFetchCommandArguments = [];
2388
+ const $fetch = new Command("fetch").description(i18n.t("desc.specs.fetch")).option("-u, --base-url <url>", i18n.t("desc.specs.fetch.baseUrl")).option("-d, --dir <directory>", i18n.t("desc.specs.fetch.dir")).option("--no-extract", i18n.t("desc.specs.fetch.noExtract")).option("--json", i18n.t("desc.specs.fetch.json")).option("--force", i18n.t("desc.specs.fetch.force")).action(specsFetch);
2389
+ $fetch.addHelpText("after", ["", "Examples:", " ones specs fetch", " ones specs fetch --json", " ones specs fetch --no-extract", " ones specs fetch --force", " ones specs fetch --base-url http://open-preview.myones.net/ --dir /path/to/project"].join("\n"));
2390
+ addCommandUsage($fetch);
2391
+ addCommandOutput($fetch);
2392
+ const $specs = new Command("specs").description(i18n.t("desc.specs"));
2393
+ $specs.addCommand($fetch);
2394
+ $specs.addHelpText("after", ["", "Examples:", " ones specs fetch", " ones specs fetch --json", " ones specs fetch --no-extract", " ones specs fetch --force", " ones specs fetch --base-url https://docs.ones.com/developer/ --dir /path/to/project"].join("\n"));
2395
+ addCommandUsage($specs);
2396
+ addCommandOutput($specs);
1856
2397
  const legacyCommandArguments = ["projectPath"];
1857
2398
  const $create = new Command("create").description(i18n.t("desc.legacy.create")).argument("<project-path>", i18n.t("desc.legacy.create.projectPath")).action(legacy);
1858
2399
  addCommandUsage($create);
@@ -1866,7 +2407,7 @@ const version = `${getPackageJSON().version}`;
1866
2407
  const env = `${version} Node/${process.version}`;
1867
2408
  ones.description(i18n.t("desc.ones", {
1868
2409
  env
1869
- })).addCommand($create$1).addCommand($build).addCommand($dev).addCommand($tunnel).addCommand($app).addCommand($login).addCommand($logout).addCommand($whoami).addCommand($legacy).configureHelp({
2410
+ })).addCommand($create$1).addCommand($build).addCommand($dev).addCommand($tunnel).addCommand($app).addCommand($login).addCommand($logout).addCommand($whoami).addCommand($specs).addCommand($legacy).configureHelp({
1870
2411
  visibleCommands: (cmd) => {
1871
2412
  const blackList = ["legacy"];
1872
2413
  return cmd.commands.filter((command) => !_includesInstanceProperty(blackList).call(blackList, command.name()));