@signageos/cli 3.0.0 → 4.0.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/dist/Applet/Upload/appletUploadCommand.js +1 -1
- package/dist/Auth/auth0Settings.d.ts +8 -0
- package/dist/Auth/auth0Settings.js +18 -0
- package/dist/Auth/loginCommand.d.ts +9 -29
- package/dist/Auth/loginCommand.js +49 -140
- package/dist/Auth/logoutCommand.d.ts +24 -0
- package/dist/Auth/logoutCommand.js +52 -0
- package/dist/Command/Autocomplete/Install/sos-completion.sh +42 -42
- package/dist/CustomScript/Upload/customScriptUploadCommand.js +1 -1
- package/dist/CustomScript/customScriptFacade.d.ts +1 -1
- package/dist/CustomScript/customScriptFacade.js +4 -3
- package/dist/Device/Content/setContentCommand.js +1 -0
- package/dist/Device/deviceFacade.js +1 -0
- package/dist/Emulator/emulatorFacade.js +5 -5
- package/dist/Organization/organizationFacade.js +2 -0
- package/dist/Plugin/Upload/pluginUploadCommand.js +1 -1
- package/dist/Plugin/pluginFacade.d.ts +1 -1
- package/dist/Plugin/pluginFacade.js +4 -3
- package/dist/RunControl/runControlHelper.d.ts +9 -8
- package/dist/RunControl/runControlHelper.js +46 -1
- package/dist/Runner/Upload/runnerUploadCommand.js +1 -1
- package/dist/Runner/runnerFacade.d.ts +1 -1
- package/dist/Runner/runnerFacade.js +4 -3
- package/dist/helper.d.ts +4 -2
- package/dist/helper.js +9 -5
- package/dist/index.js +2 -1
- package/docs/index.md +9 -2
- package/docs/login/index.md +8 -14
- package/docs/logout/index.md +62 -0
- package/package.json +4 -3
|
@@ -200,7 +200,7 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
200
200
|
if (!(error instanceof appletErrors_1.AppletDoesNotExistError)) {
|
|
201
201
|
throw error;
|
|
202
202
|
}
|
|
203
|
-
const createdApplet = yield restApi.applet.create({ name: appletName });
|
|
203
|
+
const createdApplet = yield restApi.applet.create({ name: appletName, organizationUid });
|
|
204
204
|
appletUid = createdApplet.uid;
|
|
205
205
|
(0, log_1.log)('info', chalk_1.default.yellow(`Applet uid is not present in package file.`, chalk_1.default.blue(`\nCreated new uid:`), chalk_1.default.green(appletUid)), `\n`);
|
|
206
206
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Auth0Settings } from '@signageos/cli-common';
|
|
2
|
+
/**
|
|
3
|
+
* Auth0 settings for the signageOS CLI tool (regular API).
|
|
4
|
+
*
|
|
5
|
+
* These connect to the regular signageOS API (not admin API).
|
|
6
|
+
* Override with environment variables for testing or custom Auth0 tenants.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getAuth0Settings(): Auth0Settings;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAuth0Settings = getAuth0Settings;
|
|
4
|
+
/**
|
|
5
|
+
* Auth0 settings for the signageOS CLI tool (regular API).
|
|
6
|
+
*
|
|
7
|
+
* These connect to the regular signageOS API (not admin API).
|
|
8
|
+
* Override with environment variables for testing or custom Auth0 tenants.
|
|
9
|
+
*/
|
|
10
|
+
function getAuth0Settings() {
|
|
11
|
+
var _a, _b, _c, _d;
|
|
12
|
+
return {
|
|
13
|
+
domain: (_a = process.env.SOS_AUTH0_DOMAIN) !== null && _a !== void 0 ? _a : 'sos-production.us.auth0.com',
|
|
14
|
+
clientId: (_b = process.env.SOS_AUTH0_CLIENT_ID) !== null && _b !== void 0 ? _b : '8AU8D3zJ4mK8gszZP3gZO0nv9DusSNjV',
|
|
15
|
+
audience: (_c = process.env.SOS_AUTH0_AUDIENCE) !== null && _c !== void 0 ? _c : 'https://sos-production.us.auth0.com/api/v2/',
|
|
16
|
+
scope: (_d = process.env.SOS_AUTH0_SCOPE) !== null && _d !== void 0 ? _d : 'openid profile email offline_access',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -1,45 +1,25 @@
|
|
|
1
|
-
import { CommandLineOptions } from '../Command/commandDefinition';
|
|
2
|
-
declare const OPTION_LIST: readonly [{
|
|
3
|
-
readonly name: "username";
|
|
4
|
-
readonly type: StringConstructor;
|
|
5
|
-
readonly description: "Username or e-mail used for authentication";
|
|
6
|
-
}];
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
export declare const getIsAuth0Enabled: (options: any) => {
|
|
12
|
-
isAuth0Enabled?: boolean;
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Handles user authentication using username/email and password credentials.
|
|
16
|
-
* Supports Auth0 authentication method. Stores credentials securely in the
|
|
17
|
-
* ~/.sosrc configuration file for subsequent CLI operations.
|
|
2
|
+
* Authenticates the user via the Auth0 Device Authorization Flow.
|
|
3
|
+
* Opens a browser-based verification page where the user logs in,
|
|
4
|
+
* then stores the resulting JWT tokens in `~/.sosrc`.
|
|
18
5
|
*
|
|
19
6
|
* @group Authentication:1
|
|
20
7
|
*
|
|
21
8
|
* @example
|
|
22
9
|
* ```bash
|
|
23
|
-
* # Interactive login (
|
|
10
|
+
* # Interactive login (opens browser for Auth0 authentication)
|
|
24
11
|
* sos login
|
|
25
12
|
*
|
|
26
|
-
* # Login with
|
|
27
|
-
* sos
|
|
13
|
+
* # Login with a specific profile
|
|
14
|
+
* sos --profile staging login
|
|
28
15
|
* ```
|
|
29
16
|
*
|
|
30
|
-
* @
|
|
31
|
-
*
|
|
32
|
-
* @since 0.3.0
|
|
17
|
+
* @since 4.0.0
|
|
33
18
|
*/
|
|
34
19
|
export declare const login: {
|
|
35
20
|
name: "login";
|
|
36
21
|
description: string;
|
|
37
|
-
optionList:
|
|
38
|
-
readonly name: "username";
|
|
39
|
-
readonly type: StringConstructor;
|
|
40
|
-
readonly description: "Username or e-mail used for authentication";
|
|
41
|
-
}];
|
|
22
|
+
optionList: never[];
|
|
42
23
|
commands: never[];
|
|
43
|
-
run(
|
|
24
|
+
run(): Promise<void>;
|
|
44
25
|
};
|
|
45
|
-
export {};
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -45,74 +12,63 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
13
|
};
|
|
47
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.login =
|
|
15
|
+
exports.login = void 0;
|
|
16
|
+
const node_child_process_1 = require("node:child_process");
|
|
17
|
+
const node_os_1 = require("node:os");
|
|
49
18
|
const chalk_1 = __importDefault(require("chalk"));
|
|
50
19
|
const prompts_1 = __importDefault(require("prompts"));
|
|
51
|
-
const debug_1 = __importDefault(require("debug"));
|
|
52
|
-
const os = __importStar(require("os"));
|
|
53
20
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
54
|
-
const apiVersions_1 = require("@signageos/sdk/dist/RestApi/apiVersions");
|
|
55
21
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
56
22
|
const sosControlHelper_1 = require("@signageos/sdk/dist/SosHelper/sosControlHelper");
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const parameters_1 = require("../parameters");
|
|
23
|
+
const cli_common_1 = require("@signageos/cli-common");
|
|
24
|
+
const auth0Settings_1 = require("./auth0Settings");
|
|
60
25
|
const globalArgs_1 = require("../Command/globalArgs");
|
|
61
26
|
const commandDefinition_1 = require("../Command/commandDefinition");
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
exports.getIsAuth0Enabled = getIsAuth0Enabled;
|
|
27
|
+
/** Best-effort attempt to open a URL in the user's default browser. */
|
|
28
|
+
function openInBrowser(url) {
|
|
29
|
+
const cmd = (0, node_os_1.platform)() === 'darwin'
|
|
30
|
+
? `open ${JSON.stringify(url)}`
|
|
31
|
+
: (0, node_os_1.platform)() === 'win32'
|
|
32
|
+
? `start "" ${JSON.stringify(url)}`
|
|
33
|
+
: `xdg-open ${JSON.stringify(url)}`;
|
|
34
|
+
(0, node_child_process_1.exec)(cmd, (err) => {
|
|
35
|
+
if (err) {
|
|
36
|
+
// Silently ignore — the URL is already printed to the console as a fallback.
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
77
40
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
41
|
+
* Authenticates the user via the Auth0 Device Authorization Flow.
|
|
42
|
+
* Opens a browser-based verification page where the user logs in,
|
|
43
|
+
* then stores the resulting JWT tokens in `~/.sosrc`.
|
|
81
44
|
*
|
|
82
45
|
* @group Authentication:1
|
|
83
46
|
*
|
|
84
47
|
* @example
|
|
85
48
|
* ```bash
|
|
86
|
-
* # Interactive login (
|
|
49
|
+
* # Interactive login (opens browser for Auth0 authentication)
|
|
87
50
|
* sos login
|
|
88
51
|
*
|
|
89
|
-
* # Login with
|
|
90
|
-
* sos
|
|
52
|
+
* # Login with a specific profile
|
|
53
|
+
* sos --profile staging login
|
|
91
54
|
* ```
|
|
92
55
|
*
|
|
93
|
-
* @
|
|
94
|
-
*
|
|
95
|
-
* @since 0.3.0
|
|
56
|
+
* @since 4.0.0
|
|
96
57
|
*/
|
|
97
58
|
exports.login = (0, commandDefinition_1.createCommandDefinition)({
|
|
98
59
|
name: 'login',
|
|
99
|
-
description: 'Authenticate user with signageOS',
|
|
100
|
-
optionList:
|
|
60
|
+
description: 'Authenticate user with signageOS via Auth0',
|
|
61
|
+
optionList: [],
|
|
101
62
|
commands: [],
|
|
102
|
-
run(
|
|
63
|
+
run() {
|
|
103
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
|
|
65
|
+
var _a;
|
|
105
66
|
const profile = (0, globalArgs_1.getGlobalProfile)();
|
|
106
67
|
const configFilePath = (0, sosControlHelper_1.getConfigFilePath)();
|
|
107
68
|
// Detect a new (non-existent) named profile and prompt for the API URL
|
|
108
|
-
let promptedApiUrl;
|
|
109
69
|
if (profile) {
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
const content = (yield fs_extra_1.default.readFile(configFilePath)).toString();
|
|
113
|
-
profileExists = content.includes(`[profile ${profile}]`);
|
|
114
|
-
}
|
|
115
|
-
if (!profileExists) {
|
|
70
|
+
const exists = (yield fs_extra_1.default.pathExists(configFilePath)) && (0, cli_common_1.profileExists)(profile);
|
|
71
|
+
if (!exists) {
|
|
116
72
|
(0, log_1.log)('info', `Profile "${profile}" does not exist in ${configFilePath}. Please enter the server API URL to create it.`);
|
|
117
73
|
const { inputApiUrl } = yield (0, prompts_1.default)({
|
|
118
74
|
type: 'text',
|
|
@@ -124,74 +80,27 @@ exports.login = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
124
80
|
if (!inputApiUrl) {
|
|
125
81
|
throw new Error('API URL is required to log in.');
|
|
126
82
|
}
|
|
127
|
-
|
|
83
|
+
(0, cli_common_1.writeProfileField)('apiUrl', inputApiUrl.replace(/\/+$/, ''), profile);
|
|
128
84
|
}
|
|
129
85
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
throw new Error('Missing argument --username <string>');
|
|
86
|
+
const auth0 = (0, auth0Settings_1.getAuth0Settings)();
|
|
87
|
+
(0, log_1.log)('info', 'Starting Auth0 Device Authorization Flow...');
|
|
88
|
+
const deviceCode = yield (0, cli_common_1.requestDeviceCode)(auth0);
|
|
89
|
+
const verificationUrl = (_a = deviceCode.verification_uri_complete) !== null && _a !== void 0 ? _a : deviceCode.verification_uri;
|
|
90
|
+
// Try to open the verification URL in the default browser
|
|
91
|
+
openInBrowser(verificationUrl);
|
|
92
|
+
console.info('');
|
|
93
|
+
console.info(chalk_1.default.bold('To authenticate, open this URL in your browser:'));
|
|
94
|
+
console.info(chalk_1.default.cyan.underline(verificationUrl));
|
|
95
|
+
console.info('');
|
|
96
|
+
if (!deviceCode.verification_uri_complete) {
|
|
97
|
+
console.info(`Then enter this code: ${chalk_1.default.bold.yellow(deviceCode.user_code)}`);
|
|
98
|
+
console.info('');
|
|
144
99
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
const authQueryParams = (0, exports.getIsAuth0Enabled)(options);
|
|
151
|
-
const { id: tokenId, securityToken: apiSecurityToken, name, } = yield getOrCreateApiSecurityToken(Object.assign({ identification,
|
|
152
|
-
password,
|
|
153
|
-
apiUrl }, authQueryParams));
|
|
154
|
-
yield (0, runControlHelper_1.saveConfig)({
|
|
155
|
-
apiUrl: profile || apiUrl !== parameters_1.parameters.apiUrl ? apiUrl : undefined,
|
|
156
|
-
identification: tokenId,
|
|
157
|
-
apiSecurityToken,
|
|
158
|
-
});
|
|
159
|
-
(0, log_1.log)('info', `User ${chalk_1.default.green(identification)} has been logged in with token "${name}". Credentials are stored in ${chalk_1.default.blue((0, sosControlHelper_1.getConfigFilePath)())}`);
|
|
100
|
+
console.info(chalk_1.default.dim(`Waiting for authorization (expires in ${Math.round(deviceCode.expires_in / 60)} minutes)...`));
|
|
101
|
+
const tokens = yield (0, cli_common_1.pollForToken)(auth0, deviceCode.device_code, deviceCode.interval, deviceCode.expires_in);
|
|
102
|
+
(0, cli_common_1.saveStoredTokens)(tokens, profile);
|
|
103
|
+
(0, log_1.log)('info', `Successfully authenticated. Credentials are stored in ${chalk_1.default.blue(configFilePath)}`);
|
|
160
104
|
});
|
|
161
105
|
},
|
|
162
106
|
});
|
|
163
|
-
function getOrCreateApiSecurityToken(_a) {
|
|
164
|
-
return __awaiter(this, arguments, void 0, function* ({ identification, password, apiUrl, isAuth0Enabled, }) {
|
|
165
|
-
var _b;
|
|
166
|
-
const ACCOUNT_SECURITY_TOKEN_RESOURCE = 'account/security-token';
|
|
167
|
-
const options = {
|
|
168
|
-
url: apiUrl,
|
|
169
|
-
auth: { clientId: undefined, secret: undefined },
|
|
170
|
-
version: apiVersions_1.ApiVersions.V1,
|
|
171
|
-
};
|
|
172
|
-
const tokenName = generateTokenName();
|
|
173
|
-
const requestBody = Object.assign({ identification,
|
|
174
|
-
password, name: tokenName }, (isAuth0Enabled !== undefined ? { isAuth0AuthenticationEnabled: isAuth0Enabled } : {}));
|
|
175
|
-
const response = yield (0, helper_1.postResource)(options, ACCOUNT_SECURITY_TOKEN_RESOURCE, null, requestBody);
|
|
176
|
-
const responseBody = JSON.parse(yield response.text(), helper_1.deserializeJSON);
|
|
177
|
-
// Don't log sensitive response data
|
|
178
|
-
Debug('POST security-token response status', response.status);
|
|
179
|
-
if (response.status === 201) {
|
|
180
|
-
return responseBody;
|
|
181
|
-
}
|
|
182
|
-
else if (response.status === 403) {
|
|
183
|
-
throw new Error(`Incorrect username or password`);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// Ensure password is not logged in error messages
|
|
187
|
-
const errorMessage = (_b = responseBody === null || responseBody === void 0 ? void 0 : responseBody.message) !== null && _b !== void 0 ? _b : `HTTP status ${response.status}`;
|
|
188
|
-
throw new Error('Unknown error: ' + errorMessage);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
function generateTokenName() {
|
|
193
|
-
const hostname = os.hostname();
|
|
194
|
-
const shortHostname = hostname.split('.')[0];
|
|
195
|
-
const userInfo = os.userInfo();
|
|
196
|
-
return `${userInfo.username}@${shortHostname}`;
|
|
197
|
-
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs the user out by clearing stored Auth0 tokens from `~/.sosrc`.
|
|
3
|
+
* Non-auth fields (apiUrl, defaultOrganizationUid, emulatorUid) are preserved.
|
|
4
|
+
*
|
|
5
|
+
* @group Authentication:2
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```bash
|
|
9
|
+
* # Logout from default profile
|
|
10
|
+
* sos logout
|
|
11
|
+
*
|
|
12
|
+
* # Logout from a specific profile
|
|
13
|
+
* sos --profile staging logout
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @since 4.0.0
|
|
17
|
+
*/
|
|
18
|
+
export declare const logout: {
|
|
19
|
+
name: "logout";
|
|
20
|
+
description: string;
|
|
21
|
+
optionList: never[];
|
|
22
|
+
commands: never[];
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.logout = void 0;
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
18
|
+
const sosControlHelper_1 = require("@signageos/sdk/dist/SosHelper/sosControlHelper");
|
|
19
|
+
const cli_common_1 = require("@signageos/cli-common");
|
|
20
|
+
const globalArgs_1 = require("../Command/globalArgs");
|
|
21
|
+
const commandDefinition_1 = require("../Command/commandDefinition");
|
|
22
|
+
/**
|
|
23
|
+
* Logs the user out by clearing stored Auth0 tokens from `~/.sosrc`.
|
|
24
|
+
* Non-auth fields (apiUrl, defaultOrganizationUid, emulatorUid) are preserved.
|
|
25
|
+
*
|
|
26
|
+
* @group Authentication:2
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```bash
|
|
30
|
+
* # Logout from default profile
|
|
31
|
+
* sos logout
|
|
32
|
+
*
|
|
33
|
+
* # Logout from a specific profile
|
|
34
|
+
* sos --profile staging logout
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @since 4.0.0
|
|
38
|
+
*/
|
|
39
|
+
exports.logout = (0, commandDefinition_1.createCommandDefinition)({
|
|
40
|
+
name: 'logout',
|
|
41
|
+
description: 'Log out from signageOS (clear stored tokens)',
|
|
42
|
+
optionList: [],
|
|
43
|
+
commands: [],
|
|
44
|
+
run() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const profile = (0, globalArgs_1.getGlobalProfile)();
|
|
47
|
+
(0, cli_common_1.clearStoredTokens)(profile);
|
|
48
|
+
const configFilePath = (0, sosControlHelper_1.getConfigFilePath)();
|
|
49
|
+
(0, log_1.log)('info', `Logged out. Auth tokens removed from ${chalk_1.default.blue(configFilePath)}.`);
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
});
|
|
@@ -2,62 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
# Extract command path from completion words array
|
|
4
4
|
_sos_extract_cmd_path() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
local result=""
|
|
6
|
+
for ((i = 1; i < $1; i++)); do
|
|
7
|
+
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
|
8
|
+
if [[ -n "$result" ]]; then
|
|
9
|
+
result="${result} ${COMP_WORDS[i]}"
|
|
10
|
+
else
|
|
11
|
+
result="${COMP_WORDS[i]}"
|
|
12
|
+
fi
|
|
13
|
+
fi
|
|
14
|
+
done
|
|
15
|
+
echo "$result"
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
# Common completion logic
|
|
19
19
|
_sos_completion_impl() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
20
|
+
local cur="$1"
|
|
21
|
+
local prev="$2"
|
|
22
|
+
local cmd_path="$3"
|
|
23
|
+
|
|
24
|
+
# Handle direct command completion or empty command path
|
|
25
|
+
if [[ "${cur}" == *sos* || -z "$cmd_path" ]]; then
|
|
26
|
+
COMPREPLY=($(compgen -W "${TOPLEVEL_COMMANDS}" -- "$cur"))
|
|
27
|
+
return 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# We need to find the subcommands for the current command path
|
|
31
|
+
# This will be added by the generateCompletionScript function
|
|
32
|
+
# with specific command paths and their subcommands
|
|
33
|
+
case "$cmd_path" in
|
|
34
|
+
# COMMAND_SCHEMA_CASES will be replaced with actual cases during generation
|
|
35
|
+
*)
|
|
36
|
+
# Default to top-level commands
|
|
37
|
+
COMPREPLY=($(compgen -W "${TOPLEVEL_COMMANDS}" -- "$cur"))
|
|
38
|
+
;;
|
|
39
|
+
esac
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
# Completion function with bash-completion
|
|
43
43
|
_sos_completion() {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
local cur prev words cword split
|
|
45
|
+
_init_completion -s || return
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
cmd_path=$(_sos_extract_cmd_path $COMP_CWORD)
|
|
48
|
+
_sos_completion_impl "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD - 1]}" "$cmd_path"
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
# Fallback completion for systems without bash-completion
|
|
52
52
|
_sos_completion_fallback() {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
COMPREPLY=()
|
|
54
|
+
cmd_path=$(_sos_extract_cmd_path $COMP_CWORD)
|
|
55
|
+
_sos_completion_impl "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD - 1]}" "$cmd_path"
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
# Register the appropriate completion function
|
|
59
|
-
if command -v _init_completion
|
|
60
|
-
|
|
59
|
+
if command -v _init_completion > /dev/null 2>&1; then
|
|
60
|
+
complete -F _sos_completion sos
|
|
61
61
|
else
|
|
62
|
-
|
|
63
|
-
fi
|
|
62
|
+
complete -F _sos_completion_fallback sos
|
|
63
|
+
fi
|
|
@@ -73,7 +73,7 @@ exports.customScriptUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
73
73
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
74
74
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
75
75
|
const config = yield (0, customScriptFacade_1.getConfig)(currentDirectory);
|
|
76
|
-
const customScriptVersion = yield (0, customScriptFacade_1.ensureCustomScriptVersion)(restApi, config, skipConfirmation);
|
|
76
|
+
const customScriptVersion = yield (0, customScriptFacade_1.ensureCustomScriptVersion)(restApi, config, skipConfirmation, organizationUid);
|
|
77
77
|
for (const platform of Object.keys(config.platforms)) {
|
|
78
78
|
const platformConfig = config.platforms[platform];
|
|
79
79
|
if (!platformConfig) {
|
|
@@ -117,7 +117,7 @@ export declare function getConfig(workDir: string): Promise<{
|
|
|
117
117
|
* Add data to the config file .sosconfig.json
|
|
118
118
|
*/
|
|
119
119
|
export declare function addToConfigFile(workDir: string, data: Partial<CustomScriptConfig>): Promise<void>;
|
|
120
|
-
export declare function ensureCustomScriptVersion(restApi: RestApi, config: CustomScriptConfig, skipConfirmation?: boolean): Promise<ICustomScriptVersion | import("@signageos/sdk/dist/RestApi/CustomScript/Version/CustomScriptVersion").CustomScriptVersion>;
|
|
120
|
+
export declare function ensureCustomScriptVersion(restApi: RestApi, config: CustomScriptConfig, skipConfirmation?: boolean, organizationUid?: string): Promise<ICustomScriptVersion | import("@signageos/sdk/dist/RestApi/CustomScript/Version/CustomScriptVersion").CustomScriptVersion>;
|
|
121
121
|
export declare function uploadCode({ restApi, workDir, platform, config, customScriptVersion, }: {
|
|
122
122
|
restApi: RestApi;
|
|
123
123
|
workDir: string;
|
|
@@ -127,10 +127,10 @@ function loadConfigFromFile(workDir) {
|
|
|
127
127
|
function getConfigFilePath(workDir) {
|
|
128
128
|
return path.join(workDir, fileSystem_1.SOS_CONFIG_FILE_NAME);
|
|
129
129
|
}
|
|
130
|
-
function ensureCustomScriptVersion(restApi, config, skipConfirmation) {
|
|
130
|
+
function ensureCustomScriptVersion(restApi, config, skipConfirmation, organizationUid) {
|
|
131
131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
132
132
|
var _a;
|
|
133
|
-
const customScript = yield ensureCustomScript(restApi, config, skipConfirmation);
|
|
133
|
+
const customScript = yield ensureCustomScript(restApi, config, skipConfirmation, organizationUid);
|
|
134
134
|
const customScriptVersion = yield restApi.customScript.version.get({
|
|
135
135
|
customScriptUid: customScript.uid,
|
|
136
136
|
version: config.version,
|
|
@@ -160,7 +160,7 @@ function ensureCustomScriptVersion(restApi, config, skipConfirmation) {
|
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
-
function ensureCustomScript(restApi, config, skipConfirmation) {
|
|
163
|
+
function ensureCustomScript(restApi, config, skipConfirmation, organizationUid) {
|
|
164
164
|
return __awaiter(this, void 0, void 0, function* () {
|
|
165
165
|
if (config.uid) {
|
|
166
166
|
const customScript = yield restApi.customScript.get(config.uid);
|
|
@@ -194,6 +194,7 @@ function ensureCustomScript(restApi, config, skipConfirmation) {
|
|
|
194
194
|
title: config.name, // TODO change
|
|
195
195
|
description: config.description,
|
|
196
196
|
dangerLevel: config.dangerLevel ? config.dangerLevel : 'normal', // default to 'normal' if not provided
|
|
197
|
+
organizationUid,
|
|
197
198
|
});
|
|
198
199
|
// TODO ask for permission or read from CLI arg
|
|
199
200
|
(0, log_1.log)('info', chalk_1.default.yellow('Adding Custom Script uid to the config file'));
|
|
@@ -109,6 +109,7 @@ function disconnectDevice(organization, deviceUid) {
|
|
|
109
109
|
clientId: organization.oauthClientId,
|
|
110
110
|
secret: organization.oauthClientSecret,
|
|
111
111
|
},
|
|
112
|
+
accessToken: config.accessToken,
|
|
112
113
|
version: apiVersions_1.ApiVersions.V1,
|
|
113
114
|
};
|
|
114
115
|
const responseOfPost = yield (0, helper_1.postResource)(options, DEVICE_RESOURCE, null, { deviceUid: `${deviceUid}` });
|
|
@@ -25,12 +25,12 @@ const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
|
25
25
|
const paginationHelper_1 = require("../helper/paginationHelper");
|
|
26
26
|
const createRestApi = (config) => {
|
|
27
27
|
var _a, _b;
|
|
28
|
+
const auth = config.accessToken
|
|
29
|
+
? { accessToken: config.accessToken }
|
|
30
|
+
: { clientId: (_a = config.identification) !== null && _a !== void 0 ? _a : '', secret: (_b = config.apiSecurityToken) !== null && _b !== void 0 ? _b : '' };
|
|
28
31
|
const options = {
|
|
29
32
|
url: (0, helper_1.getApiUrl)(config),
|
|
30
|
-
auth
|
|
31
|
-
clientId: (_a = config.identification) !== null && _a !== void 0 ? _a : '',
|
|
32
|
-
secret: (_b = config.apiSecurityToken) !== null && _b !== void 0 ? _b : '',
|
|
33
|
-
},
|
|
33
|
+
auth,
|
|
34
34
|
version: apiVersions_1.ApiVersions.V1,
|
|
35
35
|
clientVersions: (0, helper_1.createClientVersions)(),
|
|
36
36
|
};
|
|
@@ -70,7 +70,7 @@ function loadEmulatorOrCreateNewAndReturnUid(organizationUid) {
|
|
|
70
70
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
71
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
72
72
|
const config = yield (0, runControlHelper_1.loadConfig)();
|
|
73
|
-
if (!config.identification || !config.apiSecurityToken) {
|
|
73
|
+
if (!config.accessToken && (!config.identification || !config.apiSecurityToken)) {
|
|
74
74
|
throw new Error(`No authenticized account found. Try to login using ${chalk_1.default.green('sos login')}`);
|
|
75
75
|
}
|
|
76
76
|
const restApi = createRestApi(config);
|
|
@@ -127,6 +127,7 @@ function getOrganizations() {
|
|
|
127
127
|
clientId: config.identification,
|
|
128
128
|
secret: config.apiSecurityToken,
|
|
129
129
|
},
|
|
130
|
+
accessToken: config.accessToken,
|
|
130
131
|
version: apiVersions_1.ApiVersions.V1,
|
|
131
132
|
};
|
|
132
133
|
const responseOfGet = yield (0, helper_1.getResource)(options, ORGANIZATION_RESOURCE);
|
|
@@ -153,6 +154,7 @@ function getOrganization(organizationUid) {
|
|
|
153
154
|
clientId: config.identification,
|
|
154
155
|
secret: config.apiSecurityToken,
|
|
155
156
|
},
|
|
157
|
+
accessToken: config.accessToken,
|
|
156
158
|
version: apiVersions_1.ApiVersions.V1,
|
|
157
159
|
};
|
|
158
160
|
const responseOfGet = yield (0, helper_1.getResource)(options, ORGANIZATION_RESOURCE + '/' + organizationUid);
|
|
@@ -66,7 +66,7 @@ exports.pluginUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
66
66
|
const config = yield (0, pluginFacade_1.getSosConfig)(currentDirectory);
|
|
67
67
|
const schema = yield (0, pluginFacade_1.loadSchemas)(currentDirectory);
|
|
68
68
|
const skipConfirmation = !!options.yes;
|
|
69
|
-
const pluginVersion = yield (0, pluginFacade_1.ensurePluginVersion)(restApi, config, schema, skipConfirmation);
|
|
69
|
+
const pluginVersion = yield (0, pluginFacade_1.ensurePluginVersion)(restApi, config, schema, skipConfirmation, organizationUid);
|
|
70
70
|
for (const platform of Object.keys(config.platforms)) {
|
|
71
71
|
const platformConfig = config.platforms[platform];
|
|
72
72
|
if (!platformConfig) {
|
|
@@ -2,7 +2,7 @@ import z from 'zod';
|
|
|
2
2
|
import RestApi from '@signageos/sdk/dist/RestApi/RestApi';
|
|
3
3
|
import { IPluginVersion } from '@signageos/sdk/dist/RestApi/Plugin/Version/IPluginVersion';
|
|
4
4
|
import { PlatformConfig } from '../CustomScript/customScriptFacade';
|
|
5
|
-
export declare function ensurePluginVersion(restApi: RestApi, config: PluginConfig, schema: any, skipConfirmation?: boolean): Promise<import("@signageos/sdk/dist/RestApi/Plugin/Version/PluginVersion").PluginVersion>;
|
|
5
|
+
export declare function ensurePluginVersion(restApi: RestApi, config: PluginConfig, schema: any, skipConfirmation?: boolean, organizationUid?: string): Promise<import("@signageos/sdk/dist/RestApi/Plugin/Version/PluginVersion").PluginVersion>;
|
|
6
6
|
export declare function uploadCode({ restApi, workDir, platform, config, pluginVersion, }: {
|
|
7
7
|
restApi: RestApi;
|
|
8
8
|
workDir: string;
|
|
@@ -62,10 +62,10 @@ const archive_1 = require("../Lib/archive");
|
|
|
62
62
|
const runtimeFileSystem_1 = require("@signageos/sdk/dist/Development/runtimeFileSystem");
|
|
63
63
|
const customScriptFacade_1 = require("../CustomScript/customScriptFacade");
|
|
64
64
|
const PLUGIN_BUILDS_DIRNAME = 'plugin_builds';
|
|
65
|
-
function ensurePluginVersion(restApi, config, schema, skipConfirmation) {
|
|
65
|
+
function ensurePluginVersion(restApi, config, schema, skipConfirmation, organizationUid) {
|
|
66
66
|
return __awaiter(this, void 0, void 0, function* () {
|
|
67
67
|
var _a;
|
|
68
|
-
const plugin = yield ensurePlugin(restApi, config, skipConfirmation);
|
|
68
|
+
const plugin = yield ensurePlugin(restApi, config, skipConfirmation, organizationUid);
|
|
69
69
|
const pluginVersion = yield restApi.plugin.version.get({
|
|
70
70
|
pluginUid: plugin.uid,
|
|
71
71
|
version: config.version,
|
|
@@ -97,7 +97,7 @@ function ensurePluginVersion(restApi, config, schema, skipConfirmation) {
|
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
|
-
function ensurePlugin(restApi, config, skipConfirmation) {
|
|
100
|
+
function ensurePlugin(restApi, config, skipConfirmation, organizationUid) {
|
|
101
101
|
return __awaiter(this, void 0, void 0, function* () {
|
|
102
102
|
if (config.uid) {
|
|
103
103
|
const plugin = yield restApi.plugin.get(config.uid);
|
|
@@ -129,6 +129,7 @@ function ensurePlugin(restApi, config, skipConfirmation) {
|
|
|
129
129
|
name: config.name,
|
|
130
130
|
title: config.name,
|
|
131
131
|
description: config.description,
|
|
132
|
+
organizationUid,
|
|
132
133
|
});
|
|
133
134
|
// TODO ask for permission or read from CLI arg
|
|
134
135
|
(0, log_1.log)('info', chalk_1.default.yellow('Adding Plugin uid to the config file'));
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { IConfig } from '@signageos/sdk/dist/SosHelper/sosControlHelper';
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Extended config interface that includes Auth0 JWT token alongside legacy fields.
|
|
4
|
+
* When `accessToken` is present, it takes precedence over `identification`/`apiSecurityToken`.
|
|
5
|
+
*/
|
|
6
|
+
export interface IExtendedConfig extends IConfig {
|
|
7
|
+
accessToken?: string;
|
|
8
|
+
}
|
|
9
|
+
/** The same as loadConfig in SDK, but respect CLI --profile argument and Auth0 tokens */
|
|
10
|
+
export declare function loadConfig(): Promise<IExtendedConfig>;
|
|
10
11
|
/** The same as saveConfig in SDK, but respect CLI --profile argument */
|
|
11
12
|
export declare function saveConfig(newConfig: IConfig): Promise<void>;
|
|
12
13
|
/** The same as updateConfig in SDK, but respect CLI --profile argument */
|
|
@@ -8,13 +8,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.loadConfig = loadConfig;
|
|
13
16
|
exports.saveConfig = saveConfig;
|
|
14
17
|
exports.updateConfig = updateConfig;
|
|
18
|
+
const debug_1 = __importDefault(require("debug"));
|
|
15
19
|
const sosControlHelper_1 = require("@signageos/sdk/dist/SosHelper/sosControlHelper");
|
|
20
|
+
const cli_common_1 = require("@signageos/cli-common");
|
|
16
21
|
const globalArgs_1 = require("../Command/globalArgs");
|
|
17
|
-
|
|
22
|
+
const auth0Settings_1 = require("../Auth/auth0Settings");
|
|
23
|
+
const Debug = (0, debug_1.default)('@signageos/cli:RunControl');
|
|
24
|
+
/** The same as loadConfig in SDK, but respect CLI --profile argument and Auth0 tokens */
|
|
18
25
|
function loadConfig() {
|
|
19
26
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20
27
|
const profile = (0, globalArgs_1.getGlobalProfile)();
|
|
@@ -36,6 +43,44 @@ function loadConfig() {
|
|
|
36
43
|
envOverride.apiUrl = process.env.SOS_API_URL;
|
|
37
44
|
}
|
|
38
45
|
const finalConfig = Object.assign(Object.assign({}, config), envOverride);
|
|
46
|
+
// Check for SOS_ACCESS_TOKEN env var (CI-friendly JWT override)
|
|
47
|
+
const envToken = process.env.SOS_ACCESS_TOKEN;
|
|
48
|
+
if (envToken) {
|
|
49
|
+
Debug('Using access token from SOS_ACCESS_TOKEN env var');
|
|
50
|
+
finalConfig.accessToken = envToken;
|
|
51
|
+
return finalConfig;
|
|
52
|
+
}
|
|
53
|
+
// Try to load Auth0 tokens from ~/.sosrc
|
|
54
|
+
const tokens = (0, cli_common_1.loadStoredTokens)(profile);
|
|
55
|
+
if (tokens) {
|
|
56
|
+
if ((0, cli_common_1.isTokenExpired)(tokens)) {
|
|
57
|
+
Debug('Stored access token is expired (expiresAt: %s)', tokens.expiresAt);
|
|
58
|
+
if (tokens.refreshToken) {
|
|
59
|
+
try {
|
|
60
|
+
Debug('Attempting token refresh via Auth0');
|
|
61
|
+
const auth0 = (0, auth0Settings_1.getAuth0Settings)();
|
|
62
|
+
const refreshed = yield (0, cli_common_1.refreshAccessToken)(auth0, tokens.refreshToken);
|
|
63
|
+
(0, cli_common_1.saveStoredTokens)(refreshed, profile);
|
|
64
|
+
finalConfig.accessToken = refreshed.accessToken;
|
|
65
|
+
Debug('Token refreshed successfully (new expiresAt: %s)', refreshed.expiresAt);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
Debug('Token refresh failed: %s', error instanceof Error ? error.message : String(error));
|
|
69
|
+
// Token refresh failed — fall through to legacy auth or require re-login
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
Debug('No refresh token available, cannot refresh');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
Debug('Using stored access token (expiresAt: %s)', tokens.expiresAt);
|
|
78
|
+
finalConfig.accessToken = tokens.accessToken;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
Debug('No stored Auth0 tokens found, using legacy auth');
|
|
83
|
+
}
|
|
39
84
|
return finalConfig;
|
|
40
85
|
});
|
|
41
86
|
}
|
|
@@ -67,7 +67,7 @@ exports.runnerUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
67
67
|
const config = yield (0, pluginFacade_1.getSosConfig)(currentDirectory);
|
|
68
68
|
const schema = yield (0, runnerFacade_1.loadSchemas)(currentDirectory);
|
|
69
69
|
const skipConfirmation = !!options.yes;
|
|
70
|
-
const runnerVersion = yield (0, runnerFacade_1.ensureRunnerVersion)(restApi, config, schema, skipConfirmation);
|
|
70
|
+
const runnerVersion = yield (0, runnerFacade_1.ensureRunnerVersion)(restApi, config, schema, skipConfirmation, organizationUid);
|
|
71
71
|
for (const platform of Object.keys(config.platforms)) {
|
|
72
72
|
const platformConfig = config.platforms[platform];
|
|
73
73
|
if (!platformConfig) {
|
|
@@ -3,7 +3,7 @@ import { PlatformConfig } from '../CustomScript/customScriptFacade';
|
|
|
3
3
|
import { IRunnerVersion } from '@signageos/sdk/dist/RestApi/Runner/Version/IRunnerVersion';
|
|
4
4
|
import z from 'zod';
|
|
5
5
|
import { ConfigSchema } from '../Plugin/pluginFacade';
|
|
6
|
-
export declare function ensureRunnerVersion(restApi: RestApi, config: RunnerConfig, schema: any, skipConfirmation?: boolean): Promise<IRunnerVersion>;
|
|
6
|
+
export declare function ensureRunnerVersion(restApi: RestApi, config: RunnerConfig, schema: any, skipConfirmation?: boolean, organizationUid?: string): Promise<IRunnerVersion>;
|
|
7
7
|
export declare function uploadCode({ restApi, workDir, platform, config, runnerVersion, }: {
|
|
8
8
|
restApi: RestApi;
|
|
9
9
|
workDir: string;
|
|
@@ -59,10 +59,10 @@ const fileSystem_1 = require("../Lib/fileSystem");
|
|
|
59
59
|
const runtimeFileSystem_1 = require("@signageos/sdk/dist/Development/runtimeFileSystem");
|
|
60
60
|
const customScriptFacade_1 = require("../CustomScript/customScriptFacade");
|
|
61
61
|
const PLUGIN_BUILDS_DIRNAME = 'plugin_builds';
|
|
62
|
-
function ensureRunnerVersion(restApi, config, schema, skipConfirmation) {
|
|
62
|
+
function ensureRunnerVersion(restApi, config, schema, skipConfirmation, organizationUid) {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
64
|
var _a;
|
|
65
|
-
const runner = yield ensureRunner(restApi, config, skipConfirmation);
|
|
65
|
+
const runner = yield ensureRunner(restApi, config, skipConfirmation, organizationUid);
|
|
66
66
|
const runnerVersion = yield restApi.runner.version.get({ runnerUid: runner.uid, version: config.version });
|
|
67
67
|
if (runnerVersion) {
|
|
68
68
|
return runnerVersion;
|
|
@@ -93,7 +93,7 @@ function ensureRunnerVersion(restApi, config, schema, skipConfirmation) {
|
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
|
-
function ensureRunner(restApi, config, skipConfirmation) {
|
|
96
|
+
function ensureRunner(restApi, config, skipConfirmation, organizationUid) {
|
|
97
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
98
98
|
if (config.uid) {
|
|
99
99
|
const runner = yield restApi.runner.get(config.uid);
|
|
@@ -125,6 +125,7 @@ function ensureRunner(restApi, config, skipConfirmation) {
|
|
|
125
125
|
name: config.name,
|
|
126
126
|
title: config.name,
|
|
127
127
|
description: config.description,
|
|
128
|
+
organizationUid,
|
|
128
129
|
});
|
|
129
130
|
// TODO ask for permission or read from CLI arg
|
|
130
131
|
(0, log_1.log)('info', chalk_1.default.yellow('Adding Runner uid to the config file'));
|
package/dist/helper.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import RestApi from '@signageos/sdk/dist/RestApi/RestApi';
|
|
3
|
+
import { IExtendedConfig } from './RunControl/runControlHelper';
|
|
3
4
|
import { ApiVersions } from '@signageos/sdk/dist/RestApi/apiVersions';
|
|
4
|
-
import { IConfig } from '@signageos/sdk/dist/SosHelper/sosControlHelper';
|
|
5
5
|
type RequestInit = globalThis.RequestInit;
|
|
6
6
|
interface ICredentials {
|
|
7
7
|
oauthClientId: string;
|
|
8
8
|
oauthClientSecret: string;
|
|
9
9
|
}
|
|
10
10
|
export declare function loadApiUrl(): Promise<string>;
|
|
11
|
-
export declare function getApiUrl(config:
|
|
11
|
+
export declare function getApiUrl(config: IExtendedConfig): string;
|
|
12
12
|
export declare function createClientVersions(): {
|
|
13
13
|
signageOS_CLI: any;
|
|
14
14
|
};
|
|
@@ -20,6 +20,8 @@ export interface IOptions {
|
|
|
20
20
|
clientId: string | undefined;
|
|
21
21
|
secret: string | undefined;
|
|
22
22
|
};
|
|
23
|
+
/** JWT access token — when set, used as `X-Auth: <token>` (takes precedence over clientId:secret) */
|
|
24
|
+
accessToken?: string;
|
|
23
25
|
version: ApiVersions;
|
|
24
26
|
headers?: {
|
|
25
27
|
[name: string]: string;
|
package/dist/helper.js
CHANGED
|
@@ -59,12 +59,13 @@ function createClientVersions() {
|
|
|
59
59
|
}
|
|
60
60
|
function createOrganizationRestApi(credentials) {
|
|
61
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const config = yield (0, runControlHelper_1.loadConfig)();
|
|
63
|
+
const auth = config.accessToken
|
|
64
|
+
? { accessToken: config.accessToken }
|
|
65
|
+
: { clientId: credentials.oauthClientId, secret: credentials.oauthClientSecret };
|
|
62
66
|
const options = {
|
|
63
67
|
url: yield loadApiUrl(),
|
|
64
|
-
auth
|
|
65
|
-
clientId: credentials.oauthClientId,
|
|
66
|
-
secret: credentials.oauthClientSecret,
|
|
67
|
-
},
|
|
68
|
+
auth,
|
|
68
69
|
version: apiVersions_1.ApiVersions.V1,
|
|
69
70
|
clientVersions: createClientVersions(),
|
|
70
71
|
};
|
|
@@ -74,8 +75,11 @@ function createOrganizationRestApi(credentials) {
|
|
|
74
75
|
}
|
|
75
76
|
exports.AUTH_HEADER = 'X-Auth';
|
|
76
77
|
function createOptions(method, options, data) {
|
|
78
|
+
var _a, _b;
|
|
79
|
+
// Prefer JWT accessToken when available; fall back to legacy clientId:secret
|
|
80
|
+
const authValue = options.accessToken ? options.accessToken : ((_a = options.auth.clientId) !== null && _a !== void 0 ? _a : '') + ':' + ((_b = options.auth.secret) !== null && _b !== void 0 ? _b : '');
|
|
77
81
|
return {
|
|
78
|
-
headers: Object.assign({ 'Content-Type': 'application/json', [exports.AUTH_HEADER]:
|
|
82
|
+
headers: Object.assign({ 'Content-Type': 'application/json', [exports.AUTH_HEADER]: authValue }, (options.headers || {})),
|
|
79
83
|
method,
|
|
80
84
|
body: typeof data !== 'undefined' ? JSON.stringify(data) : undefined,
|
|
81
85
|
};
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
const appletCommand_1 = require("./Applet/appletCommand");
|
|
14
14
|
const loginCommand_1 = require("./Auth/loginCommand");
|
|
15
|
+
const logoutCommand_1 = require("./Auth/logoutCommand");
|
|
15
16
|
const organizationCommand_1 = require("./Organization/organizationCommand");
|
|
16
17
|
const timingCommand_1 = require("./Timing/timingCommand");
|
|
17
18
|
const commandProcessor_1 = require("./Command/commandProcessor");
|
|
@@ -48,7 +49,7 @@ const index = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
48
49
|
name: 'sos',
|
|
49
50
|
description: 'SignageOS CLI - The central command-line tool for deploying, managing, and debugging signageOS projects and devices',
|
|
50
51
|
optionList: generalCommand_1.GENERAL_OPTION_LIST,
|
|
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],
|
|
52
|
+
commands: [appletCommand_1.applet, loginCommand_1.login, logoutCommand_1.logout, organizationCommand_1.organization, timingCommand_1.timing, deviceCommand_1.device, customScriptCommand_1.customScript, pluginCommand_1.plugin, runnerCommand_1.runner, autocompleteCommand_1.autocomplete],
|
|
52
53
|
run() {
|
|
53
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
55
|
throw new Error('Unknown command');
|
package/docs/index.md
CHANGED
|
@@ -90,10 +90,16 @@ access to all available command groups.
|
|
|
90
90
|
|
|
91
91
|
#### `sos login`
|
|
92
92
|
|
|
93
|
-
Authenticate user with signageOS
|
|
93
|
+
Authenticate user with signageOS via Auth0
|
|
94
94
|
|
|
95
95
|
[→ See detailed documentation](/cli/login/)
|
|
96
96
|
|
|
97
|
+
#### `sos logout`
|
|
98
|
+
|
|
99
|
+
Log out from signageOS (clear stored tokens)
|
|
100
|
+
|
|
101
|
+
[→ See detailed documentation](/cli/logout/)
|
|
102
|
+
|
|
97
103
|
### Development
|
|
98
104
|
|
|
99
105
|
#### `sos applet`
|
|
@@ -185,7 +191,8 @@ sos --api-url https://api.custom.signageos.io applet list
|
|
|
185
191
|
## Related Commands
|
|
186
192
|
|
|
187
193
|
- [`sos applet`](/cli/applet/) - Applet development and management operations
|
|
188
|
-
- [`sos login`](/cli/login/) - Authenticate user with signageOS
|
|
194
|
+
- [`sos login`](/cli/login/) - Authenticate user with signageOS via Auth0
|
|
195
|
+
- [`sos logout`](/cli/logout/) - Log out from signageOS (clear stored tokens)
|
|
189
196
|
- [`sos organization`](/cli/organization/) - Organization management operations
|
|
190
197
|
- [`sos timing`](/cli/timing/) - Timing management
|
|
191
198
|
- [`sos device`](/cli/device/) - Device management
|
package/docs/login/index.md
CHANGED
|
@@ -5,14 +5,14 @@ sidebar_position: 10
|
|
|
5
5
|
---
|
|
6
6
|
# login
|
|
7
7
|
|
|
8
|
-
Authenticate user with signageOS
|
|
8
|
+
Authenticate user with signageOS via Auth0
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
## Description
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
Authenticates the user via the Auth0 Device Authorization Flow.
|
|
14
|
+
Opens a browser-based verification page where the user logs in,
|
|
15
|
+
then stores the resulting JWT tokens in `~/.sosrc`.
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
@@ -20,20 +20,14 @@ Supports Auth0 authentication method. Stores credentials securely in the
|
|
|
20
20
|
sos login [options]
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
## Options
|
|
24
|
-
|
|
25
|
-
| Option | Description |
|
|
26
|
-
| ------------ | --------------------------------------------------- |
|
|
27
|
-
| `--username` | Username or e-mail used for authentication (string) |
|
|
28
|
-
|
|
29
23
|
## Examples
|
|
30
24
|
|
|
31
25
|
```bash
|
|
32
|
-
# Interactive login (
|
|
26
|
+
# Interactive login (opens browser for Auth0 authentication)
|
|
33
27
|
sos login
|
|
34
28
|
|
|
35
|
-
# Login with
|
|
36
|
-
sos
|
|
29
|
+
# Login with a specific profile
|
|
30
|
+
sos --profile staging login
|
|
37
31
|
```
|
|
38
32
|
|
|
39
33
|
## Advanced Usage
|
|
@@ -91,7 +85,7 @@ Generate tokens at: https://box.signageos.io/settings
|
|
|
91
85
|
|
|
92
86
|
## Since
|
|
93
87
|
|
|
94
|
-
0.
|
|
88
|
+
4.0.0
|
|
95
89
|
|
|
96
90
|
## Global Options
|
|
97
91
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: logout-index
|
|
3
|
+
title: logout
|
|
4
|
+
sidebar_position: 20
|
|
5
|
+
---
|
|
6
|
+
# logout
|
|
7
|
+
|
|
8
|
+
Log out from signageOS (clear stored tokens)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Description
|
|
12
|
+
|
|
13
|
+
Logs the user out by clearing stored Auth0 tokens from `~/.sosrc`.
|
|
14
|
+
Non-auth fields (apiUrl, defaultOrganizationUid, emulatorUid) are preserved.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
sos logout [options]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Logout from default profile
|
|
26
|
+
sos logout
|
|
27
|
+
|
|
28
|
+
# Logout from a specific profile
|
|
29
|
+
sos --profile staging logout
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Since
|
|
33
|
+
|
|
34
|
+
4.0.0
|
|
35
|
+
|
|
36
|
+
## Global Options
|
|
37
|
+
|
|
38
|
+
All commands support the following global options:
|
|
39
|
+
|
|
40
|
+
| Option | Alias | Description |
|
|
41
|
+
|--------|-------|-------------|
|
|
42
|
+
| `--help` | `-h` | Display help information for any command |
|
|
43
|
+
| `--version` | `-v` | Display the installed version of the CLI |
|
|
44
|
+
| `--api-url` | `-u` | Override the API URL for REST requests |
|
|
45
|
+
| `--profile` | | Use a specific profile from ~/.sosrc config |
|
|
46
|
+
|
|
47
|
+
### Examples
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Show version
|
|
51
|
+
sos --version
|
|
52
|
+
|
|
53
|
+
# Get help for any command
|
|
54
|
+
sos applet --help
|
|
55
|
+
sos applet upload --help
|
|
56
|
+
|
|
57
|
+
# Use custom API endpoint
|
|
58
|
+
sos --api-url https://api.example.com applet upload
|
|
59
|
+
|
|
60
|
+
# Use specific profile
|
|
61
|
+
sos --profile production organization list
|
|
62
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signageos/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"author": "signageOS.io <dev@signageos.io>",
|
|
6
6
|
"files": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@istanbuljs/nyc-config-typescript": "1.0.2",
|
|
57
|
-
"@signageos/codestyle": "2.
|
|
57
|
+
"@signageos/codestyle": "2.3.0",
|
|
58
58
|
"@types/archiver": "6.0.3",
|
|
59
59
|
"@types/child-process-promise": "2.2.6",
|
|
60
60
|
"@types/cli-progress": "3.11.6",
|
|
@@ -85,8 +85,9 @@
|
|
|
85
85
|
"unzipper": "0.12.3"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
+
"@signageos/cli-common": "0.1.0",
|
|
88
89
|
"@signageos/file": "2.0.1",
|
|
89
|
-
"@signageos/sdk": "2.
|
|
90
|
+
"@signageos/sdk": "2.6.0",
|
|
90
91
|
"archiver": "7.0.1",
|
|
91
92
|
"chalk": "2.4.2",
|
|
92
93
|
"child-process-promise": "2.1.3",
|