@signageos/cli 2.8.0 → 3.0.0-rc.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.
- package/README.md +0 -6
- package/dist/Applet/Build/appletBuildCommand.js +2 -0
- package/dist/Applet/Generate/appletGenerateCommand.js +51 -59
- package/dist/Applet/Start/appletStartCommand.js +3 -1
- package/dist/Applet/Test/Upload/appletTestRunCommand.js +11 -6
- package/dist/Applet/Test/Upload/appletTestUploadCommand.js +7 -4
- package/dist/Applet/Upload/appletUploadCommand.d.ts +15 -1
- package/dist/Applet/Upload/appletUploadCommand.js +82 -13
- package/dist/Applet/Upload/appletUploadCommandHelper.js +3 -3
- package/dist/Applet/Upload/appletUploadFacade.js +124 -52
- package/dist/Applet/Upload/appletUploadFacadeHelper.d.ts +1 -1
- package/dist/Applet/Upload/appletUploadFacadeHelper.js +4 -3
- package/dist/Applet/appletErrors.d.ts +3 -0
- package/dist/Applet/appletErrors.js +8 -1
- package/dist/Applet/appletFacade.js +13 -2
- package/dist/Applet/appletValidation.d.ts +17 -0
- package/dist/Applet/appletValidation.js +62 -0
- package/dist/Auth/loginCommand.js +30 -4
- package/dist/Command/commandProcessor.js +5 -0
- package/dist/Command/globalArgs.d.ts +21 -0
- package/dist/Command/globalArgs.js +30 -0
- package/dist/CommandLine/progressBarFactory.js +51 -10
- package/dist/CustomScript/Upload/customScriptUploadCommand.js +2 -2
- package/dist/Device/Content/setContentCommand.js +2 -2
- package/dist/Device/deviceFacade.js +10 -1
- package/dist/Emulator/emulatorFacade.js +9 -2
- package/dist/Organization/organizationFacade.d.ts +1 -1
- package/dist/Organization/organizationFacade.js +50 -13
- package/dist/Plugin/Upload/pluginUploadCommand.js +2 -1
- package/dist/RunControl/runControlHelper.d.ts +7 -1
- package/dist/RunControl/runControlHelper.js +19 -1
- package/dist/Runner/Upload/runnerUploadCommand.js +2 -1
- package/dist/Timing/List/timingListCommand.js +1 -3
- package/dist/helper/paginationHelper.d.ts +7 -0
- package/dist/helper/paginationHelper.js +32 -0
- package/dist/helper.d.ts +18 -1
- package/dist/helper.js +31 -23
- package/dist/index.js +1 -2
- package/dist/parameters.d.ts +0 -1
- package/dist/parameters.js +3 -6
- package/docs/applet/generate/index.md +1 -1
- package/docs/applet/upload/index.md +15 -1
- package/package.json +12 -11
- package/.env +0 -3
- package/dist/Firmware/Upload/firmwareUploadCommand.d.ts +0 -90
- package/dist/Firmware/Upload/firmwareUploadCommand.js +0 -210
- package/dist/Firmware/Upload/firmwareUploadFacade.d.ts +0 -10
- package/dist/Firmware/Upload/firmwareUploadFacade.js +0 -90
- package/dist/Firmware/Upload/firmwareUploadHelper.d.ts +0 -1
- package/dist/Firmware/Upload/firmwareUploadHelper.js +0 -48
- package/dist/Firmware/firmwareCommand.d.ts +0 -76
- package/dist/Firmware/firmwareCommand.js +0 -42
|
@@ -36,23 +36,64 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.createProgressBar = createProgressBar;
|
|
37
37
|
const cliProgress = __importStar(require("cli-progress"));
|
|
38
38
|
function createProgressBar() {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
// Create a MultiBar instance to manage multiple progress bars
|
|
40
|
+
const multiBar = new cliProgress.MultiBar({
|
|
41
|
+
format: '[{bar}] {name} {percentage}% | ETA: {eta}s | {valueKB}/{totalKB} kB',
|
|
42
|
+
forceRedraw: true, // Force redraw to ensure the display updates correctly
|
|
43
|
+
linewrap: false, // Disable line wrapping to keep the output clean
|
|
44
|
+
autopadding: true, // Automatically adjust padding for better alignment
|
|
45
|
+
etaBuffer: 5, // Reduced buffer for faster ETA calculation on small files
|
|
46
|
+
etaAsynchronousUpdate: false, // Disable asynchronous ETA updates to avoid NULL/Infinite states
|
|
41
47
|
}, cliProgress.Presets.rect);
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
// Keep track of all bars to clean up properly
|
|
49
|
+
const bars = new Map();
|
|
50
|
+
const barValues = new Map();
|
|
44
51
|
return {
|
|
45
52
|
init({ size, name }) {
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
// If a bar already exists with this name, stop and remove it
|
|
54
|
+
if (bars.has(name)) {
|
|
55
|
+
const existingBar = bars.get(name);
|
|
56
|
+
if (existingBar) {
|
|
57
|
+
existingBar.stop();
|
|
58
|
+
bars.delete(name);
|
|
59
|
+
barValues.delete(name);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Create a new bar for this file
|
|
63
|
+
const totalKB = Math.round((size / 1024) * 100) / 100; // Round to 2 decimal places
|
|
64
|
+
const bar = multiBar.create(size, 0, {
|
|
65
|
+
name,
|
|
66
|
+
totalKB: totalKB,
|
|
67
|
+
valueKB: 0,
|
|
68
|
+
});
|
|
69
|
+
bars.set(name, bar);
|
|
70
|
+
barValues.set(name, { current: 0, total: size });
|
|
48
71
|
},
|
|
49
72
|
update({ add, name }) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
73
|
+
if (name && bars.has(name)) {
|
|
74
|
+
const bar = bars.get(name);
|
|
75
|
+
const values = barValues.get(name);
|
|
76
|
+
if (bar && values) {
|
|
77
|
+
// Update tracked values
|
|
78
|
+
values.current += add;
|
|
79
|
+
// Calculate kB values
|
|
80
|
+
const valueKB = Math.round((values.current / 1024) * 100) / 100;
|
|
81
|
+
const totalKB = Math.round((values.total / 1024) * 100) / 100;
|
|
82
|
+
// Update bar with new values
|
|
83
|
+
bar.update(values.current, {
|
|
84
|
+
name,
|
|
85
|
+
totalKB: totalKB,
|
|
86
|
+
valueKB: valueKB,
|
|
87
|
+
});
|
|
88
|
+
// Force ETA update
|
|
89
|
+
bar.updateETA();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
53
92
|
},
|
|
54
93
|
end() {
|
|
55
|
-
|
|
94
|
+
multiBar.stop();
|
|
95
|
+
bars.clear();
|
|
96
|
+
barValues.clear();
|
|
56
97
|
},
|
|
57
98
|
};
|
|
58
99
|
}
|
|
@@ -68,11 +68,11 @@ exports.customScriptUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
68
68
|
run(options) {
|
|
69
69
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
70
|
const currentDirectory = process.cwd();
|
|
71
|
-
const
|
|
71
|
+
const skipConfirmation = options.yes;
|
|
72
|
+
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipConfirmation);
|
|
72
73
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
73
74
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
74
75
|
const config = yield (0, customScriptFacade_1.getConfig)(currentDirectory);
|
|
75
|
-
const skipConfirmation = options.yes;
|
|
76
76
|
const customScriptVersion = yield (0, customScriptFacade_1.ensureCustomScriptVersion)(restApi, config, skipConfirmation);
|
|
77
77
|
for (const platform of Object.keys(config.platforms)) {
|
|
78
78
|
const platformConfig = config.platforms[platform];
|
|
@@ -66,10 +66,10 @@ exports.setContent = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
66
66
|
commands: [],
|
|
67
67
|
run(options) {
|
|
68
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
-
const
|
|
69
|
+
const skipConfirmation = !!options.yes;
|
|
70
|
+
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipConfirmation);
|
|
70
71
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
71
72
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
72
|
-
const skipConfirmation = !!options.yes;
|
|
73
73
|
const appletUid = yield (0, appletFacade_1.getAppletUid)(restApi, options, skipConfirmation);
|
|
74
74
|
const appletVersion = yield (0, appletFacade_1.getAppletVersionFromApi)(restApi, appletUid, skipConfirmation);
|
|
75
75
|
const deviceUid = yield (0, deviceFacade_1.getDeviceUid)(restApi, options, skipConfirmation);
|
|
@@ -22,6 +22,7 @@ const helper_1 = require("../helper");
|
|
|
22
22
|
const IPowerAction_1 = require("@signageos/sdk/dist/RestApi/Device/PowerAction/IPowerAction");
|
|
23
23
|
const apiVersions_1 = require("@signageos/sdk/dist/RestApi/apiVersions");
|
|
24
24
|
const runControlHelper_1 = require("../RunControl/runControlHelper");
|
|
25
|
+
const paginationHelper_1 = require("../helper/paginationHelper");
|
|
25
26
|
const Debug = (0, debug_1.default)('@signageos/cli:Device:facade');
|
|
26
27
|
exports.typeMap = new Map([
|
|
27
28
|
['reboot', { name: 'Reboot Device', action: IPowerAction_1.DevicePowerAction.SystemReboot }],
|
|
@@ -43,7 +44,7 @@ function getDeviceUid(restApi_1, options_1) {
|
|
|
43
44
|
throw new Error('Device UID is required. Please specify --device-uid argument.');
|
|
44
45
|
}
|
|
45
46
|
else {
|
|
46
|
-
const devices = yield restApi.device.list();
|
|
47
|
+
const devices = yield (0, paginationHelper_1.getAllPages)(yield restApi.device.list());
|
|
47
48
|
const response = yield (0, prompts_1.default)({
|
|
48
49
|
type: 'autocomplete',
|
|
49
50
|
name: 'deviceUid',
|
|
@@ -55,7 +56,11 @@ function getDeviceUid(restApi_1, options_1) {
|
|
|
55
56
|
value: dev.uid,
|
|
56
57
|
});
|
|
57
58
|
}),
|
|
59
|
+
suggest: helper_1.autocompleteSuggest,
|
|
58
60
|
});
|
|
61
|
+
if (!response.deviceUid) {
|
|
62
|
+
throw new Error('Device selection was cancelled');
|
|
63
|
+
}
|
|
59
64
|
Debug('Device selected', response.deviceUid);
|
|
60
65
|
deviceUid = response.deviceUid;
|
|
61
66
|
}
|
|
@@ -78,7 +83,11 @@ function getActionType(options) {
|
|
|
78
83
|
title: item[1].name,
|
|
79
84
|
value: item[0],
|
|
80
85
|
})),
|
|
86
|
+
suggest: helper_1.autocompleteSuggest,
|
|
81
87
|
});
|
|
88
|
+
if (!response.type) {
|
|
89
|
+
throw new Error('Power action selection was cancelled');
|
|
90
|
+
}
|
|
82
91
|
action = response.type;
|
|
83
92
|
}
|
|
84
93
|
if (!action) {
|
|
@@ -21,6 +21,7 @@ const AuthenticationError_1 = __importDefault(require("@signageos/sdk/dist/RestA
|
|
|
21
21
|
const apiVersions_1 = require("@signageos/sdk/dist/RestApi/apiVersions");
|
|
22
22
|
const helper_1 = require("../helper");
|
|
23
23
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
24
|
+
const paginationHelper_1 = require("../helper/paginationHelper");
|
|
24
25
|
const createRestApi = (config) => {
|
|
25
26
|
var _a, _b;
|
|
26
27
|
const options = {
|
|
@@ -37,7 +38,9 @@ const createRestApi = (config) => {
|
|
|
37
38
|
function getListOfEmulators(restApi, organizationUid) {
|
|
38
39
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
40
|
try {
|
|
40
|
-
|
|
41
|
+
// Fetch all pages to ensure we get all emulators
|
|
42
|
+
const emulators = yield (0, paginationHelper_1.getAllPages)(yield restApi.emulator.list({ organizationUid }));
|
|
43
|
+
return emulators;
|
|
41
44
|
}
|
|
42
45
|
catch (e) {
|
|
43
46
|
if (e instanceof AuthenticationError_1.default) {
|
|
@@ -84,14 +87,18 @@ function loadEmulatorOrCreateNewAndReturnUid(organizationUid) {
|
|
|
84
87
|
}
|
|
85
88
|
else if (listOfEmulatorsResponse.length > 1) {
|
|
86
89
|
const selectedEmulator = yield (0, prompts_1.default)({
|
|
87
|
-
type: '
|
|
90
|
+
type: 'autocomplete',
|
|
88
91
|
name: 'duid',
|
|
89
92
|
message: 'Select emulator to use',
|
|
90
93
|
choices: listOfEmulatorsResponse.map((emu) => ({
|
|
91
94
|
title: `${emu.name} (${emu.duid})`,
|
|
92
95
|
value: emu.duid,
|
|
93
96
|
})),
|
|
97
|
+
suggest: helper_1.autocompleteSuggest,
|
|
94
98
|
});
|
|
99
|
+
if (!selectedEmulator.duid) {
|
|
100
|
+
throw new Error('Emulator selection was cancelled');
|
|
101
|
+
}
|
|
95
102
|
emulatorUid = selectedEmulator.duid;
|
|
96
103
|
}
|
|
97
104
|
else {
|
|
@@ -26,7 +26,7 @@ export declare const ORGANIZATION_OPTIONS: ({
|
|
|
26
26
|
readonly type: BooleanConstructor;
|
|
27
27
|
readonly description: "Prevent using the defaultOrganizationUid from ~/.sosrc";
|
|
28
28
|
})[];
|
|
29
|
-
export declare function getOrganizationUidOrDefaultOrSelect(options: CommandLineOptions<[typeof ORGANIZATION_UID_OPTION, typeof NO_DEFAULT_ORGANIZATION_OPTION]
|
|
29
|
+
export declare function getOrganizationUidOrDefaultOrSelect(options: CommandLineOptions<[typeof ORGANIZATION_UID_OPTION, typeof NO_DEFAULT_ORGANIZATION_OPTION]>, skipPrompts?: boolean): Promise<string>;
|
|
30
30
|
export declare function selectOrganizationUid(options: CommandLineOptions<[typeof ORGANIZATION_UID_OPTION]>): Promise<string>;
|
|
31
31
|
export declare function getOrganizations(): Promise<IOrganization[]>;
|
|
32
32
|
export declare function getOrganization(organizationUid: string): Promise<IOrganization>;
|
|
@@ -31,26 +31,59 @@ exports.NO_DEFAULT_ORGANIZATION_OPTION = {
|
|
|
31
31
|
description: 'Prevent using the defaultOrganizationUid from ~/.sosrc',
|
|
32
32
|
};
|
|
33
33
|
exports.ORGANIZATION_OPTIONS = [exports.ORGANIZATION_UID_OPTION, exports.NO_DEFAULT_ORGANIZATION_OPTION];
|
|
34
|
-
function getOrganizationUidOrDefaultOrSelect(
|
|
35
|
-
return __awaiter(this,
|
|
34
|
+
function getOrganizationUidOrDefaultOrSelect(options_1) {
|
|
35
|
+
return __awaiter(this, arguments, void 0, function* (options, skipPrompts = false) {
|
|
36
36
|
const config = yield (0, runControlHelper_1.loadConfig)();
|
|
37
37
|
let organizationUid = options['organization-uid'];
|
|
38
38
|
if (!organizationUid && !options['no-default-organization']) {
|
|
39
39
|
organizationUid = config.defaultOrganizationUid;
|
|
40
40
|
}
|
|
41
41
|
if (!organizationUid) {
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
// If skipPrompts is true (e.g., --yes flag), try to auto-select
|
|
43
|
+
if (skipPrompts) {
|
|
44
|
+
const organizations = yield getOrganizations();
|
|
45
|
+
if (organizations.length === 0) {
|
|
46
|
+
throw new Error('No organizations available. Please ensure you have access to at least one organization.');
|
|
47
|
+
}
|
|
48
|
+
if (organizations.length === 1) {
|
|
49
|
+
// Auto-select the only available organization
|
|
50
|
+
const org = organizations[0]; // Safe: we just checked length === 1
|
|
51
|
+
organizationUid = org.uid;
|
|
52
|
+
console.info(chalk_1.default.yellow(`Auto-selected organization: ${org.title} (${org.name}, ${org.uid})`));
|
|
53
|
+
// Set as default to avoid prompts in future
|
|
54
|
+
if (!options['no-default-organization']) {
|
|
55
|
+
yield (0, runControlHelper_1.updateConfig)({
|
|
56
|
+
defaultOrganizationUid: organizationUid,
|
|
57
|
+
});
|
|
58
|
+
console.info(chalk_1.default.green('Organization has been set as default for current profile.'));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Multiple organizations available - cannot auto-select safely
|
|
63
|
+
throw new Error(`Cannot auto-select organization: Multiple organizations available (${organizations.length} found).\n` +
|
|
64
|
+
`Please specify one of the following:\n` +
|
|
65
|
+
` 1. Use --organization-uid <uid> flag\n` +
|
|
66
|
+
` 2. Set default organization: sos organization set-default\n` +
|
|
67
|
+
` 3. Remove --yes flag for interactive selection\n\n` +
|
|
68
|
+
`Available organizations:\n` +
|
|
69
|
+
organizations.map((org) => ` - ${org.title} (${org.name}, ${org.uid})`).join('\n'));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Interactive mode - prompt user to select
|
|
74
|
+
organizationUid = yield selectOrganizationUid(options);
|
|
75
|
+
if (organizationUid && !options['no-default-organization']) {
|
|
76
|
+
const response = yield (0, prompts_1.default)({
|
|
77
|
+
type: 'confirm',
|
|
78
|
+
name: 'setDefault',
|
|
79
|
+
message: `Do you want to set the organization as a default for current profile?`,
|
|
80
|
+
initial: false,
|
|
53
81
|
});
|
|
82
|
+
if (response.setDefault) {
|
|
83
|
+
yield (0, runControlHelper_1.updateConfig)({
|
|
84
|
+
defaultOrganizationUid: organizationUid,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
54
87
|
}
|
|
55
88
|
}
|
|
56
89
|
}
|
|
@@ -70,7 +103,11 @@ function selectOrganizationUid(options) {
|
|
|
70
103
|
title: `${org.title} (${org.name}, ${org.uid})`,
|
|
71
104
|
value: org.uid,
|
|
72
105
|
})),
|
|
106
|
+
suggest: helper_1.autocompleteSuggest,
|
|
73
107
|
});
|
|
108
|
+
if (!response.organizationUid) {
|
|
109
|
+
throw new Error('Organization selection was cancelled');
|
|
110
|
+
}
|
|
74
111
|
Debug('Organization selected', response.organizationUid);
|
|
75
112
|
organizationUid = response.organizationUid;
|
|
76
113
|
}
|
|
@@ -60,7 +60,8 @@ exports.pluginUpload = (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
|
|
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);
|
|
@@ -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<
|
|
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
|
-
|
|
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
|
|
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
|
},
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IPaginatedList } from '@signageos/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches all pages from a paginated list.
|
|
4
|
+
* @param firstPage The first page returned from a list() method
|
|
5
|
+
* @returns Array containing all items from all pages
|
|
6
|
+
*/
|
|
7
|
+
export declare function getAllPages<T>(firstPage: IPaginatedList<T>): Promise<T[]>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getAllPages = getAllPages;
|
|
13
|
+
/**
|
|
14
|
+
* Fetches all pages from a paginated list.
|
|
15
|
+
* @param firstPage The first page returned from a list() method
|
|
16
|
+
* @returns Array containing all items from all pages
|
|
17
|
+
*/
|
|
18
|
+
function getAllPages(firstPage) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const allItems = [...firstPage];
|
|
21
|
+
let currentPage = firstPage;
|
|
22
|
+
while (true) {
|
|
23
|
+
const nextPage = yield currentPage.getNextPage();
|
|
24
|
+
if (!nextPage) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
allItems.push(...nextPage);
|
|
28
|
+
currentPage = nextPage;
|
|
29
|
+
}
|
|
30
|
+
return allItems;
|
|
31
|
+
});
|
|
32
|
+
}
|
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';
|
|
@@ -12,7 +13,6 @@ export declare function createClientVersions(): {
|
|
|
12
13
|
signageOS_CLI: any;
|
|
13
14
|
};
|
|
14
15
|
export declare function createOrganizationRestApi(credentials: ICredentials): Promise<RestApi>;
|
|
15
|
-
export declare function createFirmwareVersionRestApi(): Promise<RestApi>;
|
|
16
16
|
export declare const AUTH_HEADER = "X-Auth";
|
|
17
17
|
export interface IOptions {
|
|
18
18
|
url: string;
|
|
@@ -33,4 +33,21 @@ export declare function putResource(options: IOptions, path: string, query?: any
|
|
|
33
33
|
export declare function deleteResource(options: IOptions, path: string): Promise<Response>;
|
|
34
34
|
export declare function deserializeJSON(_key: string, value: any): any;
|
|
35
35
|
export declare function getErrorMessageFromUnknownError(error: unknown): unknown;
|
|
36
|
+
/**
|
|
37
|
+
* Custom suggest function for autocomplete prompts.
|
|
38
|
+
* Searches in both the title (display text) and value (actual value) fields.
|
|
39
|
+
* This allows users to search by UID even when it's shown in parentheses in the title.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const response = await prompts({
|
|
44
|
+
* type: 'autocomplete',
|
|
45
|
+
* name: 'deviceUid',
|
|
46
|
+
* message: 'Select device',
|
|
47
|
+
* choices: devices.map(d => ({ title: `${d.name} (${d.uid})`, value: d.uid })),
|
|
48
|
+
* suggest: autocompleteSuggest,
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function autocompleteSuggest<T extends prompts.Choice>(input: string, choices: T[]): Promise<T[]>;
|
|
36
53
|
export {};
|
package/dist/helper.js
CHANGED
|
@@ -17,7 +17,6 @@ exports.loadApiUrl = loadApiUrl;
|
|
|
17
17
|
exports.getApiUrl = getApiUrl;
|
|
18
18
|
exports.createClientVersions = createClientVersions;
|
|
19
19
|
exports.createOrganizationRestApi = createOrganizationRestApi;
|
|
20
|
-
exports.createFirmwareVersionRestApi = createFirmwareVersionRestApi;
|
|
21
20
|
exports.createOptions = createOptions;
|
|
22
21
|
exports.createUri = createUri;
|
|
23
22
|
exports.getResource = getResource;
|
|
@@ -26,6 +25,7 @@ exports.putResource = putResource;
|
|
|
26
25
|
exports.deleteResource = deleteResource;
|
|
27
26
|
exports.deserializeJSON = deserializeJSON;
|
|
28
27
|
exports.getErrorMessageFromUnknownError = getErrorMessageFromUnknownError;
|
|
28
|
+
exports.autocompleteSuggest = autocompleteSuggest;
|
|
29
29
|
const querystring_1 = require("querystring");
|
|
30
30
|
const RestApi_1 = __importDefault(require("@signageos/sdk/dist/RestApi/RestApi"));
|
|
31
31
|
const runControlHelper_1 = require("./RunControl/runControlHelper");
|
|
@@ -39,11 +39,18 @@ function loadApiUrl() {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
function getApiUrl(config) {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
// Precedence:
|
|
43
|
+
// 1. Explicit global CLI argument (--api-url)
|
|
44
|
+
// 2. Environment variable (SOS_API_URL) - for CI/CD and testing
|
|
45
|
+
// 3. Stored profile configuration (config.apiUrl from ~/.sosrc)
|
|
46
|
+
const cliUrl = (0, globalArgs_1.getGlobalApiUrl)();
|
|
47
|
+
const profileUrl = config.apiUrl;
|
|
48
|
+
const rawApiUrl = cliUrl || profileUrl;
|
|
49
|
+
if (!rawApiUrl) {
|
|
44
50
|
throw new Error(`No API URL is defined. Please use --api-url or set SOS_API_URL environment variable.`);
|
|
45
51
|
}
|
|
46
|
-
|
|
52
|
+
// Normalize: remove trailing slashes to avoid double '//'
|
|
53
|
+
return rawApiUrl.replace(/\/+$/, '');
|
|
47
54
|
}
|
|
48
55
|
function createClientVersions() {
|
|
49
56
|
return {
|
|
@@ -65,25 +72,6 @@ function createOrganizationRestApi(credentials) {
|
|
|
65
72
|
return new RestApi_1.default(options, accountOptions);
|
|
66
73
|
});
|
|
67
74
|
}
|
|
68
|
-
function createFirmwareVersionRestApi() {
|
|
69
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
-
const config = yield (0, runControlHelper_1.loadConfig)();
|
|
71
|
-
if (!config.identification || !config.apiSecurityToken) {
|
|
72
|
-
throw new Error('Identification or token is missing.');
|
|
73
|
-
}
|
|
74
|
-
const options = {
|
|
75
|
-
url: getApiUrl(config),
|
|
76
|
-
auth: {
|
|
77
|
-
clientId: config.identification,
|
|
78
|
-
secret: config.apiSecurityToken,
|
|
79
|
-
},
|
|
80
|
-
version: apiVersions_1.ApiVersions.V1,
|
|
81
|
-
clientVersions: createClientVersions(),
|
|
82
|
-
};
|
|
83
|
-
const accountOptions = Object.assign({}, options);
|
|
84
|
-
return new RestApi_1.default(options, accountOptions);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
75
|
exports.AUTH_HEADER = 'X-Auth';
|
|
88
76
|
function createOptions(method, options, data) {
|
|
89
77
|
return {
|
|
@@ -129,3 +117,23 @@ function getErrorMessageFromUnknownError(error) {
|
|
|
129
117
|
return null;
|
|
130
118
|
}
|
|
131
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Custom suggest function for autocomplete prompts.
|
|
122
|
+
* Searches in both the title (display text) and value (actual value) fields.
|
|
123
|
+
* This allows users to search by UID even when it's shown in parentheses in the title.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const response = await prompts({
|
|
128
|
+
* type: 'autocomplete',
|
|
129
|
+
* name: 'deviceUid',
|
|
130
|
+
* message: 'Select device',
|
|
131
|
+
* choices: devices.map(d => ({ title: `${d.name} (${d.uid})`, value: d.uid })),
|
|
132
|
+
* suggest: autocompleteSuggest,
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
function autocompleteSuggest(input, choices) {
|
|
137
|
+
const searchTerm = input.toLowerCase();
|
|
138
|
+
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)); }));
|
|
139
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,6 @@ const loginCommand_1 = require("./Auth/loginCommand");
|
|
|
15
15
|
const organizationCommand_1 = require("./Organization/organizationCommand");
|
|
16
16
|
const timingCommand_1 = require("./Timing/timingCommand");
|
|
17
17
|
const commandProcessor_1 = require("./Command/commandProcessor");
|
|
18
|
-
const firmwareCommand_1 = require("./Firmware/firmwareCommand");
|
|
19
18
|
const deviceCommand_1 = require("./Device/deviceCommand");
|
|
20
19
|
const generalCommand_1 = require("./generalCommand");
|
|
21
20
|
const commandDefinition_1 = require("./Command/commandDefinition");
|
|
@@ -49,7 +48,7 @@ const index = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
49
48
|
name: 'sos',
|
|
50
49
|
description: 'SignageOS CLI - The central command-line tool for deploying, managing, and debugging signageOS projects and devices',
|
|
51
50
|
optionList: generalCommand_1.GENERAL_OPTION_LIST,
|
|
52
|
-
commands: [appletCommand_1.applet, loginCommand_1.login, organizationCommand_1.organization, timingCommand_1.timing,
|
|
51
|
+
commands: [appletCommand_1.applet, loginCommand_1.login, organizationCommand_1.organization, timingCommand_1.timing, deviceCommand_1.device, customScriptCommand_1.customScript, pluginCommand_1.plugin, runnerCommand_1.runner, autocompleteCommand_1.autocomplete],
|
|
53
52
|
run() {
|
|
54
53
|
return __awaiter(this, void 0, void 0, function* () {
|
|
55
54
|
throw new Error('Unknown command');
|
package/dist/parameters.d.ts
CHANGED
package/dist/parameters.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
@@ -25,7 +25,7 @@ sos applet generate [options]
|
|
|
25
25
|
|
|
26
26
|
| Option | Description | Default |
|
|
27
27
|
| ------------------ | ------------------------------------------------------------------------------- | ------- |
|
|
28
|
-
| `--name` |
|
|
28
|
+
| `--name` | (string) | |
|
|
29
29
|
| `--applet-version` | Applet initial version. Use semantic version (string) | `0.0.0` |
|
|
30
30
|
| `--target-dir` | Directory where will be the applet generated to (string) | |
|
|
31
31
|
| `--git` | Init applet as git repository "no" (default) or "yes" (string) | |
|
|
@@ -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
|