@signageos/cli 2.8.0 → 2.9.0

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 (41) hide show
  1. package/README.md +0 -6
  2. package/dist/Applet/Build/appletBuildCommand.js +2 -0
  3. package/dist/Applet/Generate/appletGenerateCommand.js +1 -1
  4. package/dist/Applet/Start/appletStartCommand.js +3 -1
  5. package/dist/Applet/Test/Upload/appletTestRunCommand.js +9 -5
  6. package/dist/Applet/Test/Upload/appletTestUploadCommand.js +5 -3
  7. package/dist/Applet/Upload/appletUploadCommand.d.ts +15 -1
  8. package/dist/Applet/Upload/appletUploadCommand.js +82 -13
  9. package/dist/Applet/Upload/appletUploadCommandHelper.js +3 -3
  10. package/dist/Applet/Upload/appletUploadFacade.js +124 -52
  11. package/dist/Applet/Upload/appletUploadFacadeHelper.d.ts +1 -1
  12. package/dist/Applet/Upload/appletUploadFacadeHelper.js +3 -3
  13. package/dist/Applet/appletErrors.d.ts +3 -0
  14. package/dist/Applet/appletErrors.js +8 -1
  15. package/dist/Applet/appletFacade.js +9 -0
  16. package/dist/Applet/appletValidation.d.ts +17 -0
  17. package/dist/Applet/appletValidation.js +62 -0
  18. package/dist/Auth/loginCommand.js +30 -4
  19. package/dist/Command/commandProcessor.js +5 -0
  20. package/dist/Command/globalArgs.d.ts +21 -0
  21. package/dist/Command/globalArgs.js +30 -0
  22. package/dist/CommandLine/progressBarFactory.js +51 -10
  23. package/dist/CustomScript/Upload/customScriptUploadCommand.js +2 -2
  24. package/dist/Device/Content/setContentCommand.js +2 -2
  25. package/dist/Device/deviceFacade.js +8 -0
  26. package/dist/Emulator/emulatorFacade.js +7 -2
  27. package/dist/Firmware/Upload/firmwareUploadCommand.js +7 -10
  28. package/dist/Firmware/Upload/firmwareUploadFacade.js +15 -6
  29. package/dist/Organization/organizationFacade.d.ts +1 -1
  30. package/dist/Organization/organizationFacade.js +50 -13
  31. package/dist/Plugin/Upload/pluginUploadCommand.js +2 -1
  32. package/dist/RunControl/runControlHelper.d.ts +7 -1
  33. package/dist/RunControl/runControlHelper.js +19 -1
  34. package/dist/Runner/Upload/runnerUploadCommand.js +2 -1
  35. package/dist/Timing/List/timingListCommand.js +1 -3
  36. package/dist/helper.d.ts +18 -0
  37. package/dist/helper.js +31 -3
  38. package/dist/parameters.d.ts +0 -1
  39. package/dist/parameters.js +3 -6
  40. package/docs/applet/upload/index.md +15 -1
  41. package/package.json +11 -7
@@ -1,6 +1,12 @@
1
1
  import { IConfig } from '@signageos/sdk/dist/SosHelper/sosControlHelper';
2
2
  /** The same as loadConfig in SDK, but respect CLI --profile argument */
3
- export declare function loadConfig(): Promise<IConfig & Required<Pick<IConfig, "apiUrl">>>;
3
+ export declare function loadConfig(): Promise<{
4
+ apiUrl: string;
5
+ identification?: string;
6
+ apiSecurityToken?: string;
7
+ defaultOrganizationUid?: string;
8
+ emulatorUid?: string;
9
+ }>;
4
10
  /** The same as saveConfig in SDK, but respect CLI --profile argument */
5
11
  export declare function saveConfig(newConfig: IConfig): Promise<void>;
6
12
  /** The same as updateConfig in SDK, but respect CLI --profile argument */
@@ -18,7 +18,25 @@ const globalArgs_1 = require("../Command/globalArgs");
18
18
  function loadConfig() {
19
19
  return __awaiter(this, void 0, void 0, function* () {
20
20
  const profile = (0, globalArgs_1.getGlobalProfile)();
21
- return yield (0, sosControlHelper_1.loadConfig)({ profile });
21
+ const config = yield (0, sosControlHelper_1.loadConfig)({ profile });
22
+ // Override with environment variables if they exist.
23
+ // When --profile is explicitly given, skip the SOS_API_URL override so the
24
+ // profile's own apiUrl is used instead of the ambient environment variable.
25
+ const envOverride = {};
26
+ if (process.env.SOS_API_IDENTIFICATION) {
27
+ envOverride.identification = process.env.SOS_API_IDENTIFICATION;
28
+ }
29
+ if (process.env.SOS_API_SECURITY_TOKEN) {
30
+ envOverride.apiSecurityToken = process.env.SOS_API_SECURITY_TOKEN;
31
+ }
32
+ if (process.env.SOS_ORGANIZATION_UID) {
33
+ envOverride.defaultOrganizationUid = process.env.SOS_ORGANIZATION_UID;
34
+ }
35
+ if (process.env.SOS_API_URL && !profile) {
36
+ envOverride.apiUrl = process.env.SOS_API_URL;
37
+ }
38
+ const finalConfig = Object.assign(Object.assign({}, config), envOverride);
39
+ return finalConfig;
22
40
  });
23
41
  }
24
42
  /** The same as saveConfig in SDK, but respect CLI --profile argument */
@@ -60,7 +60,8 @@ exports.runnerUpload = (0, commandDefinition_1.createCommandDefinition)({
60
60
  run(options) {
61
61
  return __awaiter(this, void 0, void 0, function* () {
62
62
  const currentDirectory = process.cwd();
63
- const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options);
63
+ const skipPrompts = options.yes;
64
+ const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipPrompts);
64
65
  const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
65
66
  const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
66
67
  const config = yield (0, customScriptFacade_1.getConfig)(currentDirectory);
@@ -57,9 +57,7 @@ exports.timingList = (0, commandDefinition_1.createCommandDefinition)({
57
57
  const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
58
58
  const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
59
59
  const deviceUid = yield (0, deviceFacade_1.getDeviceUid)(restApi, options);
60
- const timings = yield restApi.timing.getList({
61
- deviceUid,
62
- });
60
+ const timings = yield restApi.timing.getList({ deviceUid });
63
61
  console.info(chalk_1.default.yellow(JSON.stringify(timings, undefined, 2)));
64
62
  });
65
63
  },
package/dist/helper.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import prompts from 'prompts';
1
2
  import RestApi from '@signageos/sdk/dist/RestApi/RestApi';
2
3
  import { ApiVersions } from '@signageos/sdk/dist/RestApi/apiVersions';
3
4
  import { IConfig } from '@signageos/sdk/dist/SosHelper/sosControlHelper';
@@ -33,4 +34,21 @@ export declare function putResource(options: IOptions, path: string, query?: any
33
34
  export declare function deleteResource(options: IOptions, path: string): Promise<Response>;
34
35
  export declare function deserializeJSON(_key: string, value: any): any;
35
36
  export declare function getErrorMessageFromUnknownError(error: unknown): unknown;
37
+ /**
38
+ * Custom suggest function for autocomplete prompts.
39
+ * Searches in both the title (display text) and value (actual value) fields.
40
+ * This allows users to search by UID even when it's shown in parentheses in the title.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const response = await prompts({
45
+ * type: 'autocomplete',
46
+ * name: 'deviceUid',
47
+ * message: 'Select device',
48
+ * choices: devices.map(d => ({ title: `${d.name} (${d.uid})`, value: d.uid })),
49
+ * suggest: autocompleteSuggest,
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function autocompleteSuggest<T extends prompts.Choice>(input: string, choices: T[]): Promise<T[]>;
36
54
  export {};
package/dist/helper.js CHANGED
@@ -26,6 +26,7 @@ exports.putResource = putResource;
26
26
  exports.deleteResource = deleteResource;
27
27
  exports.deserializeJSON = deserializeJSON;
28
28
  exports.getErrorMessageFromUnknownError = getErrorMessageFromUnknownError;
29
+ exports.autocompleteSuggest = autocompleteSuggest;
29
30
  const querystring_1 = require("querystring");
30
31
  const RestApi_1 = __importDefault(require("@signageos/sdk/dist/RestApi/RestApi"));
31
32
  const runControlHelper_1 = require("./RunControl/runControlHelper");
@@ -39,11 +40,18 @@ function loadApiUrl() {
39
40
  });
40
41
  }
41
42
  function getApiUrl(config) {
42
- const apiUrl = (0, globalArgs_1.getGlobalApiUrl)() || config.apiUrl;
43
- if (!apiUrl) {
43
+ // Precedence:
44
+ // 1. Explicit global CLI argument (--api-url)
45
+ // 2. Environment variable (SOS_API_URL) - for CI/CD and testing
46
+ // 3. Stored profile configuration (config.apiUrl from ~/.sosrc)
47
+ const cliUrl = (0, globalArgs_1.getGlobalApiUrl)();
48
+ const profileUrl = config.apiUrl;
49
+ const rawApiUrl = cliUrl || profileUrl;
50
+ if (!rawApiUrl) {
44
51
  throw new Error(`No API URL is defined. Please use --api-url or set SOS_API_URL environment variable.`);
45
52
  }
46
- return apiUrl;
53
+ // Normalize: remove trailing slashes to avoid double '//'
54
+ return rawApiUrl.replace(/\/+$/, '');
47
55
  }
48
56
  function createClientVersions() {
49
57
  return {
@@ -129,3 +137,23 @@ function getErrorMessageFromUnknownError(error) {
129
137
  return null;
130
138
  }
131
139
  }
140
+ /**
141
+ * Custom suggest function for autocomplete prompts.
142
+ * Searches in both the title (display text) and value (actual value) fields.
143
+ * This allows users to search by UID even when it's shown in parentheses in the title.
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const response = await prompts({
148
+ * type: 'autocomplete',
149
+ * name: 'deviceUid',
150
+ * message: 'Select device',
151
+ * choices: devices.map(d => ({ title: `${d.name} (${d.uid})`, value: d.uid })),
152
+ * suggest: autocompleteSuggest,
153
+ * });
154
+ * ```
155
+ */
156
+ function autocompleteSuggest(input, choices) {
157
+ const searchTerm = input.toLowerCase();
158
+ return Promise.resolve(choices.filter((choice) => { var _a, _b; return ((_a = choice.title) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(searchTerm)) || ((_b = choice.value) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(searchTerm)); }));
159
+ }
@@ -4,7 +4,6 @@ export declare const parameters: {
4
4
  version: any;
5
5
  profile: string | undefined;
6
6
  apiUrl: string;
7
- boxHost: string;
8
7
  forwardServerUrl: string | undefined;
9
8
  applet: {
10
9
  uid: string | undefined;
@@ -7,7 +7,9 @@ const dotenv = require('dotenv');
7
7
  const packageConfig = require('../package.json');
8
8
  const environment = process.env.NODE_ENV || 'dev';
9
9
  const rootPath = path.normalize(__dirname + '/..');
10
- dotenv.config({ path: path.join(rootPath, '.env') });
10
+ // Load environment-specific .env file
11
+ const envFile = environment === 'test' ? '.env.test' : '.env';
12
+ dotenv.config({ path: path.join(rootPath, envFile) });
11
13
  const configurableEnvVars = [
12
14
  'SOS_PROFILE',
13
15
  'SOS_API_IDENTIFICATION',
@@ -23,20 +25,15 @@ for (const envVar of configurableEnvVars) {
23
25
  }
24
26
  }
25
27
  const apiUrl = process.env.SOS_API_URL;
26
- const boxHost = process.env.SOS_BOX_HOST;
27
28
  if (!apiUrl) {
28
29
  throw new Error(`Environment variable SOS_API_URL is required`);
29
30
  }
30
- if (!boxHost) {
31
- throw new Error(`Environment variable SOS_BOX_HOST is required`);
32
- }
33
31
  exports.parameters = {
34
32
  environment,
35
33
  name: packageConfig.name,
36
34
  version: packageConfig.version,
37
35
  profile: process.env.SOS_PROFILE,
38
36
  apiUrl,
39
- boxHost,
40
37
  forwardServerUrl: process.env.SOS_FORWARD_SERVER_URL,
41
38
  applet: {
42
39
  uid: process.env.SOS_APPLET_UID,
@@ -51,14 +51,28 @@ sos applet upload --entry-file-path src/main.js
51
51
  # Upload with organization override
52
52
  sos applet upload --organization-uid abc123def456
53
53
 
54
- # Skip confirmation prompts
54
+ # Skip confirmation prompts (auto-selects if only 1 org available)
55
55
  sos applet upload --yes
56
56
 
57
+ # CI/CD: Non-interactive upload with specific organization
58
+ sos applet upload --yes --organization-uid abc123def456
59
+
57
60
  # Verbose output with detailed file information
58
61
  sos applet upload --verbose
59
62
 
60
63
  # Update package.json with new applet UID
61
64
  sos applet upload --update-package-config
65
+
66
+ # Complete CI/CD example
67
+ sos applet upload --yes --organization-uid abc123def456 --update-package-config
68
+ ```
69
+
70
+ **Note for CI/CD and --yes flag:**
71
+ When using `--yes` with multiple organizations:
72
+ - If you have only 1 organization: it will be auto-selected
73
+ - If you have multiple organizations: you MUST specify `--organization-uid`
74
+ - Alternative: Set a default organization with `sos organization set-default`
75
+
62
76
  ```
63
77
 
64
78
  ## Advanced Usage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signageos/cli",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "main": "./dist/index.js",
5
5
  "author": "signageOS.io <dev@signageos.io>",
6
6
  "files": [
@@ -21,13 +21,17 @@
21
21
  "clean-build": "npm run clean && npm run build",
22
22
  "watch": "tsc --watch",
23
23
  "check-types": "tsc --noEmit",
24
- "test": "env NODE_ENV=test mocha",
25
- "test:coverage": "c8 npm run test",
26
- "test:windows": "cross-env NODE_ENV=test mocha",
27
24
  "lint": "eslint",
28
25
  "lint:fix": "eslint --fix",
29
26
  "lint:prettier": "prettier \"(src|tests|tools)/**/*.+(ts|tsx|json|js)\" --check",
30
27
  "lint:prettier:fix": "prettier \"(src|tests|tools)/**/*.+(ts|tsx|json|js)\" --write",
28
+ "test": "npm run test:unit && npm run test:integration",
29
+ "test:coverage": "c8 npm run test:all",
30
+ "test:unit": "env NODE_ENV=test mocha",
31
+ "test:unit:windows": "cross-env NODE_ENV=test mocha",
32
+ "test:integration": "npm run clean-build && env NODE_ENV=test mocha --config .mocharc.integration.json",
33
+ "test:integration:windows": "npm run build && cross-env NODE_ENV=test mocha --config .mocharc.integration.json",
34
+ "test:integration:generate": "env NODE_ENV=test mocha --config .mocharc.integration.json --grep appletGenerateCommand",
31
35
  "test:node-versions": "./tests/integration/test-node-versions.sh",
32
36
  "test:integration:node-versions": "env NODE_ENV=test mocha --config .mocharc.node-versions.json",
33
37
  "generate:dummy-applet": "node ./tools/generate-dummy-applet.mjs",
@@ -49,7 +53,7 @@
49
53
  },
50
54
  "devDependencies": {
51
55
  "@istanbuljs/nyc-config-typescript": "1.0.2",
52
- "@signageos/codestyle": "2.0.3",
56
+ "@signageos/codestyle": "2.1.0",
53
57
  "@types/archiver": "6.0.3",
54
58
  "@types/child-process-promise": "2.2.6",
55
59
  "@types/cli-progress": "3.11.6",
@@ -81,7 +85,7 @@
81
85
  },
82
86
  "dependencies": {
83
87
  "@signageos/file": "2.0.1",
84
- "@signageos/sdk": "2.0.2",
88
+ "@signageos/sdk": "2.3.0",
85
89
  "archiver": "7.0.1",
86
90
  "chalk": "2.4.2",
87
91
  "child-process-promise": "2.1.3",
@@ -92,7 +96,7 @@
92
96
  "debug": "4.4.0",
93
97
  "dotenv": "16.5.0",
94
98
  "express": "5.1.0",
95
- "fs-extra": "11.3.0",
99
+ "fs-extra": "11.3.2",
96
100
  "internal-ip": "8.0.0",
97
101
  "markdown-table": "3.0.4",
98
102
  "mime": "2.4.4",