@celonis/content-cli 1.18.0 → 1.18.1
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/commands/sdk/module.js +29 -13
- package/commands/sdk/preview-certificate.js +82 -0
- package/commands/sdk/preview-headers.js +25 -0
- package/commands/sdk/preview-inline-scripts.js +50 -0
- package/commands/sdk/preview-proxy.js +182 -0
- package/commands/sdk/sdk-api.js +3 -13
- package/commands/sdk/sdk-preview.service.js +98 -0
- package/commands/sdk/sdk.service.js +18 -15
- package/content-cli.js +2 -2
- package/core/command/module-handler.js +4 -7
- package/core/http/http-client.js +3 -2
- package/core/profile/profile.service.js +45 -1
- package/core/utils/logger.js +1 -0
- package/lib/commands/sdk/module.d.ts +2 -1
- package/lib/commands/sdk/preview-certificate.d.ts +5 -0
- package/lib/commands/sdk/preview-headers.d.ts +5 -0
- package/lib/commands/sdk/preview-inline-scripts.d.ts +13 -0
- package/lib/commands/sdk/preview-proxy.d.ts +14 -0
- package/lib/commands/sdk/sdk-api.d.ts +5 -2
- package/lib/commands/sdk/sdk-preview.service.d.ts +11 -0
- package/lib/commands/sdk/sdk.service.d.ts +4 -3
- package/lib/core/http/http-client.d.ts +1 -1
- package/lib/core/profile/profile.service.d.ts +3 -0
- package/package.json +6 -5
package/commands/sdk/module.js
CHANGED
|
@@ -13,40 +13,56 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
13
13
|
if (v !== undefined) module.exports = v;
|
|
14
14
|
}
|
|
15
15
|
else if (typeof define === "function" && define.amd) {
|
|
16
|
-
define(["require", "exports", "../../core/command/module-handler", "./sdk.service"], factory);
|
|
16
|
+
define(["require", "exports", "../../core/command/module-handler", "./sdk-preview.service", "./sdk.service"], factory);
|
|
17
17
|
}
|
|
18
18
|
})(function (require, exports) {
|
|
19
19
|
"use strict";
|
|
20
20
|
const module_handler_1 = require("../../core/command/module-handler");
|
|
21
|
+
const sdk_preview_service_1 = require("./sdk-preview.service");
|
|
21
22
|
const sdk_service_1 = require("./sdk.service");
|
|
22
23
|
class Module extends module_handler_1.IModule {
|
|
23
24
|
register(context, configurator) {
|
|
24
25
|
const sdkCommand = configurator
|
|
25
26
|
.command("sdk")
|
|
26
27
|
.beta()
|
|
27
|
-
.description("Implement custom apps for
|
|
28
|
-
sdkCommand
|
|
29
|
-
.command("download")
|
|
30
|
-
.beta()
|
|
31
|
-
.description("Download the latest Celonis SDK generated for a Codespace asset")
|
|
32
|
-
.requiredOption("--appId <appId>", "Identifier of the app to download the SDK for")
|
|
33
|
-
.action(this.downloadSdk);
|
|
28
|
+
.description("Implement custom apps for Codehub assets using the Celonis SDK");
|
|
34
29
|
sdkCommand
|
|
35
30
|
.command("publish")
|
|
36
31
|
.beta()
|
|
37
|
-
.description("Publish a build of a custom app as a new version of its
|
|
32
|
+
.description("Publish a build of a custom app as a new version of its Codehub asset")
|
|
38
33
|
.requiredOption("--appId <appId>", "Identifier of the app to publish the build for")
|
|
39
34
|
.requiredOption("--dist <dist>", "Directory containing the build of the app")
|
|
35
|
+
.option("--buildVersion <buildVersion>", "Semantic version of the build. Defaults to the next major version")
|
|
36
|
+
.option("--message <message>", "Message describing the build, at most 500 characters")
|
|
40
37
|
.action(this.publishApp);
|
|
38
|
+
sdkCommand
|
|
39
|
+
.command("preview")
|
|
40
|
+
.beta()
|
|
41
|
+
.skipProfileLoading()
|
|
42
|
+
.description("Proxy your local dev server to preview the app inside Celonis")
|
|
43
|
+
.option("--target <target>", "URL of the local dev server to proxy", "http://localhost:4200")
|
|
44
|
+
.option("--port <port>", "Target port on which the preview is hosted", "4300")
|
|
45
|
+
.option("--allow-inline-scripts", "Allow inline scripts in your dev server's HTML")
|
|
46
|
+
.action(this.previewApp);
|
|
47
|
+
sdkCommand
|
|
48
|
+
.command("token")
|
|
49
|
+
.beta()
|
|
50
|
+
.description("Print a token with read access to the Celonis SDK, e.g. to authenticate against the npm registry")
|
|
51
|
+
.action(this.printToken);
|
|
41
52
|
}
|
|
42
|
-
|
|
53
|
+
publishApp(context, command, options) {
|
|
43
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
-
yield new sdk_service_1.SdkService(context).
|
|
55
|
+
yield new sdk_service_1.SdkService(context).publishApp(options.appId, options.dist, options.buildVersion, options.message);
|
|
45
56
|
});
|
|
46
57
|
}
|
|
47
|
-
|
|
58
|
+
previewApp(context, command, options) {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
yield new sdk_preview_service_1.SdkPreviewService().previewUntilStopped(options.target, options.port, options.allowInlineScripts === true);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
printToken(context) {
|
|
48
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
-
yield new sdk_service_1.SdkService(context).
|
|
65
|
+
yield new sdk_service_1.SdkService(context).printToken();
|
|
50
66
|
});
|
|
51
67
|
}
|
|
52
68
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
(function (factory) {
|
|
11
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
12
|
+
var v = factory(require, exports);
|
|
13
|
+
if (v !== undefined) module.exports = v;
|
|
14
|
+
}
|
|
15
|
+
else if (typeof define === "function" && define.amd) {
|
|
16
|
+
define(["require", "exports", "node:crypto", "node:fs", "node:path", "selfsigned"], factory);
|
|
17
|
+
}
|
|
18
|
+
})(function (require, exports) {
|
|
19
|
+
"use strict";
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.loadOrCreatePreviewCertificate = void 0;
|
|
22
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
const node_fs_1 = require("node:fs");
|
|
24
|
+
const node_path_1 = require("node:path");
|
|
25
|
+
const selfsigned_1 = require("selfsigned");
|
|
26
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
27
|
+
const CERT_FILE = "localhost-cert.pem";
|
|
28
|
+
const KEY_FILE = "localhost-key.pem";
|
|
29
|
+
function loadOrCreatePreviewCertificate(directory, now = new Date()) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
const existing = readUsableCertificate(directory, now);
|
|
32
|
+
if (existing) {
|
|
33
|
+
return existing;
|
|
34
|
+
}
|
|
35
|
+
const generated = yield (0, selfsigned_1.generate)([{ name: "commonName", value: "localhost" }], {
|
|
36
|
+
keyType: "ec",
|
|
37
|
+
curve: "P-256",
|
|
38
|
+
algorithm: "sha256",
|
|
39
|
+
notBeforeDate: now,
|
|
40
|
+
notAfterDate: new Date(now.getTime() + 365 * DAY_MS),
|
|
41
|
+
extensions: [
|
|
42
|
+
{
|
|
43
|
+
name: "subjectAltName",
|
|
44
|
+
altNames: [
|
|
45
|
+
{ type: 2, value: "localhost" },
|
|
46
|
+
{ type: 7, ip: "127.0.0.1" },
|
|
47
|
+
{ type: 7, ip: "::1" },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
const certificate = { key: generated.private, cert: generated.cert };
|
|
53
|
+
(0, node_fs_1.mkdirSync)(directory, { recursive: true });
|
|
54
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(directory, CERT_FILE), certificate.cert);
|
|
55
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(directory, KEY_FILE), certificate.key, { mode: 0o600 });
|
|
56
|
+
return certificate;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
exports.loadOrCreatePreviewCertificate = loadOrCreatePreviewCertificate;
|
|
60
|
+
function readUsableCertificate(directory, now) {
|
|
61
|
+
const certPath = (0, node_path_1.join)(directory, CERT_FILE);
|
|
62
|
+
const keyPath = (0, node_path_1.join)(directory, KEY_FILE);
|
|
63
|
+
if (!(0, node_fs_1.existsSync)(certPath) || !(0, node_fs_1.existsSync)(keyPath)) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const cert = (0, node_fs_1.readFileSync)(certPath, "utf8");
|
|
68
|
+
const key = (0, node_fs_1.readFileSync)(keyPath, "utf8");
|
|
69
|
+
const x509 = new node_crypto_1.X509Certificate(cert);
|
|
70
|
+
if (!x509.checkPrivateKey((0, node_crypto_1.createPrivateKey)(key))) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (new Date(x509.validTo).getTime() - now.getTime() <= DAY_MS) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
return { key, cert };
|
|
77
|
+
}
|
|
78
|
+
catch (_a) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.LOCAL_PREVIEW_HEADERS = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Copied from `localPreviewHeaders()` in ems-frontend `libs/common/fragments/sandbox/src/lib/policy.ts`,
|
|
15
|
+
* whose spec fails when the gateway policy drifts. Update both together.
|
|
16
|
+
*/
|
|
17
|
+
exports.LOCAL_PREVIEW_HEADERS = {
|
|
18
|
+
"content-security-policy": "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self'; media-src 'self' blob:; connect-src 'none'; worker-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'none'; frame-ancestors https://*.celonis.cloud http://localhost:*; sandbox allow-scripts",
|
|
19
|
+
"permissions-policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=(), hid=(), clipboard-read=(), clipboard-write=(), display-capture=()",
|
|
20
|
+
"access-control-allow-origin": "*",
|
|
21
|
+
"referrer-policy": "no-referrer",
|
|
22
|
+
"x-content-type-options": "nosniff",
|
|
23
|
+
"cache-control": "no-store",
|
|
24
|
+
};
|
|
25
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports", "node:crypto"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.allowInlineScripts = exports.inlineScriptHashes = void 0;
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const SCRIPT_ELEMENT = /<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi;
|
|
15
|
+
const SRC_ATTRIBUTE = /(?:^|[\s/])src(?=[\s=/]|$)/i;
|
|
16
|
+
const EXCERPT_LENGTH = 60;
|
|
17
|
+
/**
|
|
18
|
+
* The inline scripts (`<script>` without `src`) of an HTML document, distinct by hash and in document order.
|
|
19
|
+
* Each hash covers the script text as the browser parses it for CSP (line endings normalized to LF).
|
|
20
|
+
*/
|
|
21
|
+
function inlineScriptHashes(html) {
|
|
22
|
+
const scripts = new Map();
|
|
23
|
+
for (const [, attributes, text] of html.matchAll(SCRIPT_ELEMENT)) {
|
|
24
|
+
if (SRC_ATTRIBUTE.test(attributes) || text.length === 0) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
// Browsers hash the parsed text, and the HTML parser turns CRLF and lone CR into LF.
|
|
28
|
+
const parsedText = text.replace(/\r\n?/g, "\n");
|
|
29
|
+
const hash = `'sha256-${(0, node_crypto_1.createHash)("sha256").update(parsedText, "utf8").digest("base64")}'`;
|
|
30
|
+
if (!scripts.has(hash)) {
|
|
31
|
+
scripts.set(hash, { hash, excerpt: text.replace(/\s+/g, " ").trim().slice(0, EXCERPT_LENGTH) });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return [...scripts.values()];
|
|
35
|
+
}
|
|
36
|
+
exports.inlineScriptHashes = inlineScriptHashes;
|
|
37
|
+
/** Appends the hashes to the policy's `script-src` directive and leaves every other directive unchanged. */
|
|
38
|
+
function allowInlineScripts(csp, hashes) {
|
|
39
|
+
if (hashes.length === 0) {
|
|
40
|
+
return csp;
|
|
41
|
+
}
|
|
42
|
+
return csp
|
|
43
|
+
.split(";")
|
|
44
|
+
.map(directive => /^\s*script-src(\s|$)/i.test(directive)
|
|
45
|
+
? `${directive.trimEnd()} ${hashes.join(" ")}`
|
|
46
|
+
: directive)
|
|
47
|
+
.join(";");
|
|
48
|
+
}
|
|
49
|
+
exports.allowInlineScripts = allowInlineScripts;
|
|
50
|
+
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports", "node:http", "node:https", "node:net", "node:tls", "../../core/utils/logger", "./preview-inline-scripts"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.startPreviewProxy = void 0;
|
|
13
|
+
const http = require("node:http");
|
|
14
|
+
const https = require("node:https");
|
|
15
|
+
const net = require("node:net");
|
|
16
|
+
const tls = require("node:tls");
|
|
17
|
+
const logger_1 = require("../../core/utils/logger");
|
|
18
|
+
const preview_inline_scripts_1 = require("./preview-inline-scripts");
|
|
19
|
+
const REPLACED_HEADERS = ["content-security-policy", "content-security-policy-report-only", "x-frame-options"];
|
|
20
|
+
const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
21
|
+
const BODILESS_STATUSES = new Set([204, 304]);
|
|
22
|
+
function inlineScriptWarning(path, excerpt, allowed) {
|
|
23
|
+
return allowed
|
|
24
|
+
? `Allowing an inline script in ${path} for the local preview: "${excerpt}". ` +
|
|
25
|
+
"Inline scripts are disabled for published apps, so they can only be used during development."
|
|
26
|
+
: `Blocking an inline script in ${path}: "${excerpt}". Inline scripts are disabled for published apps. You can allow inline scripts during development by passing --allow-inline-scripts.`;
|
|
27
|
+
}
|
|
28
|
+
function startPreviewProxy(options) {
|
|
29
|
+
const { target, port, certificate, headers, allowInlineScripts: allowInline } = options;
|
|
30
|
+
const secureTarget = target.protocol === "https:";
|
|
31
|
+
const targetHostname = target.hostname.replace(/^\[(.*)\]$/, "$1");
|
|
32
|
+
const targetPort = Number(target.port) || (secureTarget ? 443 : 80);
|
|
33
|
+
const rejectUnauthorized = !LOOPBACK_HOSTNAMES.has(target.hostname);
|
|
34
|
+
const agent = secureTarget
|
|
35
|
+
? new https.Agent({ keepAlive: true, rejectUnauthorized })
|
|
36
|
+
: new http.Agent({ keepAlive: true });
|
|
37
|
+
const removedHeaders = new Set([...REPLACED_HEADERS, ...Object.keys(headers).map(name => name.toLowerCase())]);
|
|
38
|
+
const unreachableMessage = `content-cli sdk preview can't reach ${target.origin}. Start your dev server or pass --target.`;
|
|
39
|
+
const openSockets = new Set();
|
|
40
|
+
const warnedInlineScripts = new Set();
|
|
41
|
+
let warnedUnreachable = false;
|
|
42
|
+
function track(socket) {
|
|
43
|
+
openSockets.add(socket);
|
|
44
|
+
socket.once("close", () => openSockets.delete(socket));
|
|
45
|
+
}
|
|
46
|
+
function forwardRequest(req, res) {
|
|
47
|
+
const proxyReq = (secureTarget ? https : http).request({
|
|
48
|
+
protocol: target.protocol,
|
|
49
|
+
hostname: targetHostname,
|
|
50
|
+
port: targetPort,
|
|
51
|
+
method: req.method,
|
|
52
|
+
path: req.url,
|
|
53
|
+
headers: Object.assign(Object.assign({}, req.headers), { host: target.host, "accept-encoding": "identity" }),
|
|
54
|
+
agent,
|
|
55
|
+
});
|
|
56
|
+
let responded = false;
|
|
57
|
+
proxyReq.on("response", proxyRes => {
|
|
58
|
+
var _a;
|
|
59
|
+
responded = true;
|
|
60
|
+
warnedUnreachable = false;
|
|
61
|
+
const responseHeaders = {};
|
|
62
|
+
for (const [name, value] of Object.entries(proxyRes.headers)) {
|
|
63
|
+
if (!removedHeaders.has(name.toLowerCase())) {
|
|
64
|
+
responseHeaders[name] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
proxyRes.on("error", () => res.destroy());
|
|
68
|
+
proxyRes.on("aborted", () => res.destroy());
|
|
69
|
+
const isHtml = /^text\/html\b/i.test((_a = proxyRes.headers["content-type"]) !== null && _a !== void 0 ? _a : "");
|
|
70
|
+
const hasBody = req.method !== "HEAD" && !BODILESS_STATUSES.has(proxyRes.statusCode);
|
|
71
|
+
if (!isHtml || !hasBody) {
|
|
72
|
+
res.writeHead(proxyRes.statusCode, Object.assign(Object.assign({}, responseHeaders), headers));
|
|
73
|
+
proxyRes.pipe(res);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const chunks = [];
|
|
77
|
+
proxyRes.on("data", (chunk) => chunks.push(chunk));
|
|
78
|
+
proxyRes.on("end", () => {
|
|
79
|
+
if (res.destroyed) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const body = Buffer.concat(chunks);
|
|
83
|
+
const scripts = (0, preview_inline_scripts_1.inlineScriptHashes)(body.toString("utf8"));
|
|
84
|
+
for (const { hash, excerpt } of scripts) {
|
|
85
|
+
if (!warnedInlineScripts.has(hash)) {
|
|
86
|
+
warnedInlineScripts.add(hash);
|
|
87
|
+
logger_1.logger.warn(inlineScriptWarning(req.url, excerpt, allowInline));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (proxyRes.headers["content-length"] !== undefined) {
|
|
91
|
+
responseHeaders["content-length"] = body.length;
|
|
92
|
+
}
|
|
93
|
+
const csp = headers["content-security-policy"];
|
|
94
|
+
res.writeHead(proxyRes.statusCode, Object.assign(Object.assign(Object.assign({}, responseHeaders), headers), (csp === undefined || !allowInline ? {} : {
|
|
95
|
+
"content-security-policy": (0, preview_inline_scripts_1.allowInlineScripts)(csp, scripts.map(script => script.hash)),
|
|
96
|
+
})));
|
|
97
|
+
res.end(body);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
proxyReq.on("error", () => {
|
|
101
|
+
if (res.destroyed) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (responded || res.headersSent) {
|
|
105
|
+
res.destroy();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!warnedUnreachable) {
|
|
109
|
+
warnedUnreachable = true;
|
|
110
|
+
logger_1.logger.warn(unreachableMessage);
|
|
111
|
+
}
|
|
112
|
+
res.writeHead(502, Object.assign(Object.assign({}, headers), { "content-type": "text/plain" }));
|
|
113
|
+
res.end(unreachableMessage);
|
|
114
|
+
});
|
|
115
|
+
res.on("close", () => {
|
|
116
|
+
if (!res.writableFinished) {
|
|
117
|
+
proxyReq.destroy();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
req.pipe(proxyReq);
|
|
121
|
+
}
|
|
122
|
+
function forwardUpgrade(req, socket, head) {
|
|
123
|
+
const targetSocket = secureTarget
|
|
124
|
+
? tls.connect({
|
|
125
|
+
host: targetHostname,
|
|
126
|
+
port: targetPort,
|
|
127
|
+
servername: net.isIP(targetHostname) ? undefined : targetHostname,
|
|
128
|
+
rejectUnauthorized,
|
|
129
|
+
})
|
|
130
|
+
: net.connect({ host: targetHostname, port: targetPort });
|
|
131
|
+
track(targetSocket);
|
|
132
|
+
const destroyBoth = () => {
|
|
133
|
+
socket.destroy();
|
|
134
|
+
targetSocket.destroy();
|
|
135
|
+
};
|
|
136
|
+
socket.on("error", destroyBoth);
|
|
137
|
+
targetSocket.on("error", destroyBoth);
|
|
138
|
+
socket.on("close", () => targetSocket.destroy());
|
|
139
|
+
targetSocket.on("close", () => socket.destroy());
|
|
140
|
+
targetSocket.once(secureTarget ? "secureConnect" : "connect", () => {
|
|
141
|
+
const lines = [`${req.method} ${req.url} HTTP/${req.httpVersion}`];
|
|
142
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
143
|
+
const name = req.rawHeaders[i];
|
|
144
|
+
lines.push(`${name}: ${name.toLowerCase() === "host" ? target.host : req.rawHeaders[i + 1]}`);
|
|
145
|
+
}
|
|
146
|
+
targetSocket.write(`${lines.join("\r\n")}\r\n\r\n`);
|
|
147
|
+
if (head.length > 0) {
|
|
148
|
+
targetSocket.write(head);
|
|
149
|
+
}
|
|
150
|
+
targetSocket.pipe(socket);
|
|
151
|
+
socket.pipe(targetSocket);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const server = https.createServer({ key: certificate.key, cert: certificate.cert }, forwardRequest);
|
|
155
|
+
server.on("connection", track);
|
|
156
|
+
server.on("upgrade", forwardUpgrade);
|
|
157
|
+
function close() {
|
|
158
|
+
return new Promise(closed => {
|
|
159
|
+
server.close(() => closed());
|
|
160
|
+
openSockets.forEach(socket => socket.destroy());
|
|
161
|
+
agent.destroy();
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return new Promise((resolve, reject) => {
|
|
165
|
+
const onListenError = (error) => {
|
|
166
|
+
agent.destroy();
|
|
167
|
+
reject(new logger_1.FatalError(error.code === "EADDRINUSE"
|
|
168
|
+
? `Port ${port} is already in use. Stop the other process or pass --port.`
|
|
169
|
+
: `Could not start the preview proxy on port ${port}: ${error.message}`));
|
|
170
|
+
};
|
|
171
|
+
server.once("error", onListenError);
|
|
172
|
+
server.listen({ port, host: "localhost" }, () => {
|
|
173
|
+
server.off("error", onListenError);
|
|
174
|
+
resolve({
|
|
175
|
+
url: `https://localhost:${server.address().port}`,
|
|
176
|
+
close,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
exports.startPreviewProxy = startPreviewProxy;
|
|
182
|
+
});
|
package/commands/sdk/sdk-api.js
CHANGED
|
@@ -24,21 +24,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
24
24
|
constructor(context) {
|
|
25
25
|
this.httpClient = () => context.httpClient;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
publishApp(appId, bundle, options) {
|
|
28
28
|
return __awaiter(this, void 0, void 0, function* () {
|
|
29
29
|
return this.httpClient()
|
|
30
|
-
.
|
|
31
|
-
.catch(
|
|
32
|
-
const problem = `Problem downloading SDK for app ${appId}`;
|
|
33
|
-
throw new logger_1.FatalError(e ? `${problem}: ${e}` : problem);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
publishApp(appId, bundle) {
|
|
38
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
return this.httpClient()
|
|
40
|
-
.postBinary(`/pro-code-app-manager/api/codespace/apps/${appId}/publish`, bundle, "application/zip")
|
|
41
|
-
.catch((e) => {
|
|
30
|
+
.postBinary(`/pro-code-app-manager/api/codespace/apps/${appId}/publish`, bundle, "application/zip", options)
|
|
31
|
+
.catch(e => {
|
|
42
32
|
throw new logger_1.FatalError(`Problem publishing app ${appId}: ${e}`);
|
|
43
33
|
});
|
|
44
34
|
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
(function (factory) {
|
|
11
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
12
|
+
var v = factory(require, exports);
|
|
13
|
+
if (v !== undefined) module.exports = v;
|
|
14
|
+
}
|
|
15
|
+
else if (typeof define === "function" && define.amd) {
|
|
16
|
+
define(["require", "exports", "node:os", "node:path", "../../core/utils/logger", "./preview-certificate", "./preview-headers", "./preview-proxy"], factory);
|
|
17
|
+
}
|
|
18
|
+
})(function (require, exports) {
|
|
19
|
+
"use strict";
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.SdkPreviewService = void 0;
|
|
22
|
+
const os = require("node:os");
|
|
23
|
+
const path = require("node:path");
|
|
24
|
+
const logger_1 = require("../../core/utils/logger");
|
|
25
|
+
const preview_certificate_1 = require("./preview-certificate");
|
|
26
|
+
const preview_headers_1 = require("./preview-headers");
|
|
27
|
+
const preview_proxy_1 = require("./preview-proxy");
|
|
28
|
+
class SdkPreviewService {
|
|
29
|
+
constructor(certificateDirectory = SdkPreviewService.CERTIFICATE_DIRECTORY) {
|
|
30
|
+
this.certificateDirectory = certificateDirectory;
|
|
31
|
+
}
|
|
32
|
+
preview(target, port, allowInlineScripts = false) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
const targetUrl = this.parseTarget(target);
|
|
35
|
+
const portNumber = this.parsePort(port);
|
|
36
|
+
const certificate = yield (0, preview_certificate_1.loadOrCreatePreviewCertificate)(this.certificateDirectory);
|
|
37
|
+
const proxy = yield (0, preview_proxy_1.startPreviewProxy)({
|
|
38
|
+
target: targetUrl,
|
|
39
|
+
port: portNumber,
|
|
40
|
+
certificate,
|
|
41
|
+
headers: preview_headers_1.LOCAL_PREVIEW_HEADERS,
|
|
42
|
+
allowInlineScripts,
|
|
43
|
+
});
|
|
44
|
+
logger_1.logger.info(`Local preview running on https://localhost:${portNumber}, forwarding to ${target}.`);
|
|
45
|
+
logger_1.logger.info(`Open the Local preview in your Codehub. If it stays blank, open https://localhost:${portNumber} in a browser tab and accept the certificate, then reload the preview.`);
|
|
46
|
+
logger_1.logger.info("Press Ctrl+C to stop.");
|
|
47
|
+
return proxy;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
previewUntilStopped(target, port, allowInlineScripts = false) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
const proxy = yield this.preview(target, port, allowInlineScripts);
|
|
53
|
+
yield this.waitForShutdownSignal();
|
|
54
|
+
yield proxy.close();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
waitForShutdownSignal() {
|
|
58
|
+
return new Promise(resolve => {
|
|
59
|
+
const stop = () => {
|
|
60
|
+
process.removeListener("SIGINT", stop);
|
|
61
|
+
process.removeListener("SIGTERM", stop);
|
|
62
|
+
resolve();
|
|
63
|
+
};
|
|
64
|
+
process.once("SIGINT", stop);
|
|
65
|
+
process.once("SIGTERM", stop);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
parseTarget(target) {
|
|
69
|
+
const message = "--target must be an http or https origin, for example http://localhost:4200";
|
|
70
|
+
let url;
|
|
71
|
+
try {
|
|
72
|
+
url = new URL(target);
|
|
73
|
+
}
|
|
74
|
+
catch (_a) {
|
|
75
|
+
throw new logger_1.FatalError(message);
|
|
76
|
+
}
|
|
77
|
+
const isOrigin = (url.protocol === "http:" || url.protocol === "https:") &&
|
|
78
|
+
!url.username &&
|
|
79
|
+
!url.password &&
|
|
80
|
+
url.pathname === "/" &&
|
|
81
|
+
!url.search &&
|
|
82
|
+
!url.hash;
|
|
83
|
+
if (!isOrigin) {
|
|
84
|
+
throw new logger_1.FatalError(message);
|
|
85
|
+
}
|
|
86
|
+
return url;
|
|
87
|
+
}
|
|
88
|
+
parsePort(port) {
|
|
89
|
+
const value = typeof port === "number" || /^\d+$/.test(port) ? Number(port) : Number.NaN;
|
|
90
|
+
if (!Number.isInteger(value) || value < 1 || value > 65535) {
|
|
91
|
+
throw new logger_1.FatalError("--port must be a number between 1 and 65535");
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.SdkPreviewService = SdkPreviewService;
|
|
97
|
+
SdkPreviewService.CERTIFICATE_DIRECTORY = path.resolve(os.homedir(), ".celonis-content-cli-preview");
|
|
98
|
+
});
|
|
@@ -13,7 +13,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
13
13
|
if (v !== undefined) module.exports = v;
|
|
14
14
|
}
|
|
15
15
|
else if (typeof define === "function" && define.amd) {
|
|
16
|
-
define(["require", "exports", "node:fs", "node:path", "adm-zip", "./sdk-api", "../../core/utils/logger"], factory);
|
|
16
|
+
define(["require", "exports", "node:fs", "node:path", "adm-zip", "./sdk-api", "../../core/utils/logger", "../../core/profile/profile.service"], factory);
|
|
17
17
|
}
|
|
18
18
|
})(function (require, exports) {
|
|
19
19
|
"use strict";
|
|
@@ -24,30 +24,34 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
24
24
|
const AdmZip = require("adm-zip");
|
|
25
25
|
const sdk_api_1 = require("./sdk-api");
|
|
26
26
|
const logger_1 = require("../../core/utils/logger");
|
|
27
|
+
const profile_service_1 = require("../../core/profile/profile.service");
|
|
27
28
|
class SdkService {
|
|
28
29
|
constructor(context) {
|
|
30
|
+
this.context = context;
|
|
29
31
|
this.sdkApi = new sdk_api_1.SdkApi(context);
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
const sdk = yield this.sdkApi.downloadSdk(appId);
|
|
34
|
-
const sdkDirectory = path.resolve(process.cwd(), SdkService.SDK_DIRECTORY);
|
|
35
|
-
fs.rmSync(sdkDirectory, { recursive: true, force: true });
|
|
36
|
-
fs.mkdirSync(sdkDirectory, { recursive: true });
|
|
37
|
-
const sdkFile = path.join(SdkService.SDK_DIRECTORY, `${appId}.tgz`);
|
|
38
|
-
fs.writeFileSync(path.resolve(process.cwd(), sdkFile), sdk);
|
|
39
|
-
logger_1.logger.info(`SDK downloaded successfully: ${sdkFile}`);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
publishApp(appId, dist) {
|
|
33
|
+
publishApp(appId, dist, buildVersion, message) {
|
|
43
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
35
|
const distDirectory = path.resolve(process.cwd(), dist);
|
|
45
36
|
this.requireDirectory(distDirectory);
|
|
46
37
|
const bundle = this.compressDirectory(distDirectory);
|
|
47
|
-
const { version } = yield this.sdkApi.publishApp(appId, bundle);
|
|
38
|
+
const { version } = yield this.sdkApi.publishApp(appId, bundle, { version: buildVersion, message });
|
|
48
39
|
logger_1.logger.info(`App published successfully as version '${version}'`);
|
|
49
40
|
});
|
|
50
41
|
}
|
|
42
|
+
printToken() {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
const profile = this.requireProfile();
|
|
45
|
+
const token = yield new profile_service_1.ProfileService().acquireSdkToken(profile);
|
|
46
|
+
process.stdout.write(`${token}\n`);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
requireProfile() {
|
|
50
|
+
if (!this.context.profile) {
|
|
51
|
+
throw new logger_1.FatalError("No profile provided. Please provide a profile to acquire a token for");
|
|
52
|
+
}
|
|
53
|
+
return this.context.profile;
|
|
54
|
+
}
|
|
51
55
|
requireDirectory(directory) {
|
|
52
56
|
if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {
|
|
53
57
|
throw new logger_1.FatalError(`The dist directory ${directory} does not exist or is no directory`);
|
|
@@ -60,5 +64,4 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
exports.SdkService = SdkService;
|
|
63
|
-
SdkService.SDK_DIRECTORY = ".celonis-sdk";
|
|
64
67
|
});
|
package/content-cli.js
CHANGED
|
@@ -102,8 +102,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
102
102
|
bootstrapProgram.parseOptions(process.argv);
|
|
103
103
|
const globalOpts = bootstrapProgram.opts();
|
|
104
104
|
if (!globalOpts.quietmode) {
|
|
105
|
-
console.
|
|
106
|
-
console.
|
|
105
|
+
console.error(`Content CLI - (C) Copyright 2025 - Celonis SE - Version ${version_1.VersionUtils.getCurrentCliVersion()}`);
|
|
106
|
+
console.error();
|
|
107
107
|
}
|
|
108
108
|
if (globalOpts.debug) {
|
|
109
109
|
logger_1.logger.transports.forEach(t => {
|
|
@@ -236,7 +236,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
236
236
|
}
|
|
237
237
|
printBetaNoticeIfBetaCommand() {
|
|
238
238
|
if (this.cmd.isBeta) {
|
|
239
|
-
logger_1.logger.
|
|
239
|
+
logger_1.logger.warn(chalk.yellow("This command is in beta and may change in future releases."));
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
printBetaNoticeIfBetaOptions() {
|
|
@@ -244,12 +244,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
244
244
|
return;
|
|
245
245
|
}
|
|
246
246
|
const providedOptions = this.cmd.optsWithGlobals();
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
logger_1.logger.info(chalk.yellow(`The option '${option.long}' is in beta and may change in future releases.`));
|
|
251
|
-
}
|
|
252
|
-
}
|
|
247
|
+
this.cmd.options
|
|
248
|
+
.filter(option => option.isBeta && Object.hasOwn(providedOptions, option.attributeName()))
|
|
249
|
+
.forEach(option => logger_1.logger.warn(chalk.yellow(`The option '${option.long}' is in beta and may change in future releases.`)));
|
|
253
250
|
}
|
|
254
251
|
}
|
|
255
252
|
exports.CommandConfig = CommandConfig;
|
package/core/http/http-client.js
CHANGED
|
@@ -133,11 +133,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
|
-
postBinary(url, body, contentType) {
|
|
136
|
+
postBinary(url, body, contentType, parameters) {
|
|
137
137
|
return __awaiter(this, void 0, void 0, function* () {
|
|
138
138
|
return new Promise((resolve, reject) => {
|
|
139
139
|
this.axios.post(this.resolveUrl(url), body, {
|
|
140
|
-
headers: this.buildHeaders(contentType)
|
|
140
|
+
headers: this.buildHeaders(contentType),
|
|
141
|
+
params: parameters
|
|
141
142
|
}).then(response => {
|
|
142
143
|
this.handleResponse(response, resolve, reject);
|
|
143
144
|
}).catch(err => {
|
|
@@ -36,8 +36,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
36
36
|
const OAUTH_SCOPES = ["studio", "package-manager", "integration.data-pools", "action-engine.projects"];
|
|
37
37
|
/** Device code fallback: try without action-engine.projects if all 4 scopes fail. */
|
|
38
38
|
const DEVICE_CODE_SCOPES_WITHOUT_ACTION_ENGINE = ["studio", "package-manager", "integration.data-pools"];
|
|
39
|
+
const SDK_SCOPE = "pro-code-app-manager.sdk";
|
|
39
40
|
/** First attempt for both auth flows: all scopes plus the pro-code-app-manager scopes, which are not yet available on every environment. */
|
|
40
|
-
const OAUTH_SCOPES_WITH_PRO_CODE = [...OAUTH_SCOPES,
|
|
41
|
+
const OAUTH_SCOPES_WITH_PRO_CODE = [...OAUTH_SCOPES, SDK_SCOPE, "pro-code-app-manager.publish"];
|
|
41
42
|
class ProfileService {
|
|
42
43
|
constructor() {
|
|
43
44
|
this.profileContainerPath = path.resolve(homedir, ".celonis-content-cli-profiles");
|
|
@@ -318,6 +319,49 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
318
319
|
yield this.storeProfile(profile);
|
|
319
320
|
});
|
|
320
321
|
}
|
|
322
|
+
acquireSdkToken(profile) {
|
|
323
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
switch (profile.type) {
|
|
325
|
+
case profile_interface_1.ProfileType.DEVICE_CODE:
|
|
326
|
+
return this.acquireDeviceCodeSdkToken(profile);
|
|
327
|
+
case profile_interface_1.ProfileType.CLIENT_CREDENTIALS:
|
|
328
|
+
return this.acquireClientCredentialsSdkToken(profile);
|
|
329
|
+
default:
|
|
330
|
+
throw new logger_1.FatalError("An SDK token cannot be acquired for API key profiles. Use the API key directly for authentication.");
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
acquireDeviceCodeSdkToken(profile) {
|
|
335
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
336
|
+
const issuer = yield openid_client_1.Issuer.discover(profile.team);
|
|
337
|
+
const oauthClient = new issuer.Client({
|
|
338
|
+
client_id: "content-cli",
|
|
339
|
+
token_endpoint_auth_method: "none",
|
|
340
|
+
});
|
|
341
|
+
const tokenSet = yield oauthClient.refresh(profile.refreshToken, {
|
|
342
|
+
exchangeBody: { scope: SDK_SCOPE },
|
|
343
|
+
});
|
|
344
|
+
profile.refreshToken = tokenSet.refresh_token;
|
|
345
|
+
profile.expiresAt = 0;
|
|
346
|
+
yield this.storeProfile(profile);
|
|
347
|
+
return tokenSet.access_token;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
acquireClientCredentialsSdkToken(profile) {
|
|
351
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
352
|
+
const issuer = yield openid_client_1.Issuer.discover(profile.team);
|
|
353
|
+
const oauthClient = new issuer.Client({
|
|
354
|
+
client_id: profile.clientId,
|
|
355
|
+
client_secret: profile.clientSecret,
|
|
356
|
+
token_endpoint_auth_method: profile.clientAuthenticationMethod,
|
|
357
|
+
});
|
|
358
|
+
const tokenSet = yield oauthClient.grant({
|
|
359
|
+
grant_type: "client_credentials",
|
|
360
|
+
scope: SDK_SCOPE,
|
|
361
|
+
});
|
|
362
|
+
return tokenSet.access_token;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
321
365
|
unrefreshableProfile(profileName, err) {
|
|
322
366
|
const cause = err instanceof Error ? err.message : "an unrecognised error";
|
|
323
367
|
logger_1.logger.debug(`Refreshing the profile ${profileName} failed: ${cause}`);
|
package/core/utils/logger.js
CHANGED
|
@@ -2,7 +2,8 @@ import { Configurator, IModule } from "../../core/command/module-handler";
|
|
|
2
2
|
import { Context } from "../../core/command/cli-context";
|
|
3
3
|
declare class Module extends IModule {
|
|
4
4
|
register(context: Context, configurator: Configurator): void;
|
|
5
|
-
private downloadSdk;
|
|
6
5
|
private publishApp;
|
|
6
|
+
private previewApp;
|
|
7
|
+
private printToken;
|
|
7
8
|
}
|
|
8
9
|
export = Module;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface InlineScript {
|
|
2
|
+
/** `'sha256-<base64>'`, quoted and ready for a CSP source list. */
|
|
3
|
+
hash: string;
|
|
4
|
+
/** The first 60 characters of the script text, with whitespace collapsed. */
|
|
5
|
+
excerpt: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The inline scripts (`<script>` without `src`) of an HTML document, distinct by hash and in document order.
|
|
9
|
+
* Each hash covers the script text as the browser parses it for CSP (line endings normalized to LF).
|
|
10
|
+
*/
|
|
11
|
+
export declare function inlineScriptHashes(html: string): InlineScript[];
|
|
12
|
+
/** Appends the hashes to the policy's `script-src` directive and leaves every other directive unchanged. */
|
|
13
|
+
export declare function allowInlineScripts(csp: string, hashes: readonly string[]): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PreviewCertificate } from "./preview-certificate";
|
|
2
|
+
export interface PreviewProxyOptions {
|
|
3
|
+
target: URL;
|
|
4
|
+
port: number;
|
|
5
|
+
certificate: PreviewCertificate;
|
|
6
|
+
headers: Readonly<Record<string, string>>;
|
|
7
|
+
/** Adds a hash of each inline script in proxied HTML to `script-src`. Published apps block inline scripts. */
|
|
8
|
+
allowInlineScripts: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface PreviewProxy {
|
|
11
|
+
url: string;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare function startPreviewProxy(options: PreviewProxyOptions): Promise<PreviewProxy>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Context } from "../../core/command/cli-context";
|
|
3
|
+
export interface SdkPublishOptions {
|
|
4
|
+
version?: string;
|
|
5
|
+
message?: string;
|
|
6
|
+
}
|
|
3
7
|
export interface SdkPublishResponse {
|
|
4
8
|
version: string;
|
|
5
9
|
}
|
|
6
10
|
export declare class SdkApi {
|
|
7
11
|
private readonly httpClient;
|
|
8
12
|
constructor(context: Context);
|
|
9
|
-
|
|
10
|
-
publishApp(appId: string, bundle: Buffer): Promise<SdkPublishResponse>;
|
|
13
|
+
publishApp(appId: string, bundle: Buffer, options: SdkPublishOptions): Promise<SdkPublishResponse>;
|
|
11
14
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PreviewProxy } from "./preview-proxy";
|
|
2
|
+
export declare class SdkPreviewService {
|
|
3
|
+
private readonly certificateDirectory;
|
|
4
|
+
static readonly CERTIFICATE_DIRECTORY: string;
|
|
5
|
+
constructor(certificateDirectory?: string);
|
|
6
|
+
preview(target: string, port: string | number, allowInlineScripts?: boolean): Promise<PreviewProxy>;
|
|
7
|
+
previewUntilStopped(target: string, port: string | number, allowInlineScripts?: boolean): Promise<void>;
|
|
8
|
+
private waitForShutdownSignal;
|
|
9
|
+
private parseTarget;
|
|
10
|
+
private parsePort;
|
|
11
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Context } from "../../core/command/cli-context";
|
|
2
2
|
export declare class SdkService {
|
|
3
|
-
|
|
3
|
+
private readonly context;
|
|
4
4
|
private readonly sdkApi;
|
|
5
5
|
constructor(context: Context);
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
publishApp(appId: string, dist: string, buildVersion?: string, message?: string): Promise<void>;
|
|
7
|
+
printToken(): Promise<void>;
|
|
8
|
+
private requireProfile;
|
|
8
9
|
private requireDirectory;
|
|
9
10
|
private compressDirectory;
|
|
10
11
|
}
|
|
@@ -17,7 +17,7 @@ export declare class HttpClient {
|
|
|
17
17
|
getFile(url: string): Promise<any>;
|
|
18
18
|
postFile(url: string, formData: FormData, parameters?: {}): Promise<any>;
|
|
19
19
|
post(url: string, body: any): Promise<any>;
|
|
20
|
-
postBinary(url: string, body: Buffer, contentType: string): Promise<any>;
|
|
20
|
+
postBinary(url: string, body: Buffer, contentType: string, parameters?: {}): Promise<any>;
|
|
21
21
|
put(url: string, body: object): Promise<any>;
|
|
22
22
|
delete(url: string): Promise<any>;
|
|
23
23
|
downloadFile(url: string): Promise<any>;
|
|
@@ -19,6 +19,9 @@ export declare class ProfileService {
|
|
|
19
19
|
getAllFilesInDirectory(): string[];
|
|
20
20
|
authorizeProfile(profile: Profile): Promise<void>;
|
|
21
21
|
refreshProfile(profile: Profile): Promise<void>;
|
|
22
|
+
acquireSdkToken(profile: Profile): Promise<string>;
|
|
23
|
+
private acquireDeviceCodeSdkToken;
|
|
24
|
+
private acquireClientCredentialsSdkToken;
|
|
22
25
|
private unrefreshableProfile;
|
|
23
26
|
private getProfileEnvVariables;
|
|
24
27
|
private getBaseTeamUrl;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celonis/content-cli",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.1",
|
|
4
4
|
"description": "CLI Tool to help manage content in Celonis Platform",
|
|
5
5
|
"main": "content-cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,17 +18,18 @@
|
|
|
18
18
|
"node": ">=18.20.5"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
+
"@github/keytar": "7.10.6",
|
|
21
22
|
"adm-zip": "0.6.0",
|
|
22
|
-
"chalk": "4.1.2",
|
|
23
|
-
"uuid": "9.0.1",
|
|
24
23
|
"axios": "1.18.0",
|
|
24
|
+
"chalk": "4.1.2",
|
|
25
25
|
"commander": "13.1.0",
|
|
26
26
|
"form-data": "4.0.6",
|
|
27
|
-
"openid-client": "5.6.1",
|
|
28
27
|
"hpagent": "1.2.0",
|
|
29
|
-
"
|
|
28
|
+
"openid-client": "5.6.1",
|
|
29
|
+
"selfsigned": "5.5.0",
|
|
30
30
|
"semver": "7.6.3",
|
|
31
31
|
"simple-git": "3.36.0",
|
|
32
|
+
"uuid": "9.0.1",
|
|
32
33
|
"valid-url": "1.0.9",
|
|
33
34
|
"winston": "3.17.0",
|
|
34
35
|
"yaml": "2.8.3"
|