@red-hat-developer-hub/backstage-plugin-orchestrator-backend-module-loki 1.3.0 → 1.3.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-orchestrator-backend-module-loki
|
|
2
2
|
|
|
3
|
+
## 1.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e6d1c2d: Fix to allow properly quoted LoqQL querys in the selector field
|
|
8
|
+
- Updated dependencies [43e0722]
|
|
9
|
+
- @red-hat-developer-hub/backstage-plugin-orchestrator-common@3.7.1
|
|
10
|
+
- @red-hat-developer-hub/backstage-plugin-orchestrator-node@1.3.1
|
|
11
|
+
|
|
3
12
|
## 1.3.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
|
@@ -105,6 +105,43 @@ function parseAndValidateLogStreamSelectors(lokiConfig, configKeyPath) {
|
|
|
105
105
|
return { label, value };
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
|
+
function assertNoUnquotedLogQlBraces(element, context) {
|
|
109
|
+
let i = 0;
|
|
110
|
+
while (i < element.length) {
|
|
111
|
+
const ch = element[i];
|
|
112
|
+
if (ch === '"') {
|
|
113
|
+
i = skipQuotedString(element, i + 1, '"', context);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (ch === "`") {
|
|
117
|
+
i = skipQuotedString(element, i + 1, "`", context);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (ch === "{" || ch === "}") {
|
|
121
|
+
throw new errors.InputError(
|
|
122
|
+
`${context}: entry must not contain unquoted "{" or "}"`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
i++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function skipQuotedString(element, start, quote, context) {
|
|
129
|
+
let i = start;
|
|
130
|
+
while (i < element.length) {
|
|
131
|
+
const ch = element[i];
|
|
132
|
+
if (quote === '"' && ch === "\\") {
|
|
133
|
+
i += 2;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (ch === quote) {
|
|
137
|
+
return i + 1;
|
|
138
|
+
}
|
|
139
|
+
i++;
|
|
140
|
+
}
|
|
141
|
+
throw new errors.InputError(
|
|
142
|
+
`${context}: entry contains an unclosed ${quote === '"' ? "double-quoted" : "backtick-quoted"} string`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
108
145
|
function parseAndValidateLogPipelineFilters(lokiConfig, configKeyPath) {
|
|
109
146
|
const filters = lokiConfig.getOptionalStringArray("logPipelineFilters");
|
|
110
147
|
if (!filters?.length) {
|
|
@@ -121,12 +158,7 @@ function parseAndValidateLogPipelineFilters(lokiConfig, configKeyPath) {
|
|
|
121
158
|
if (/[\r\n\u2028\u2029]/.test(element)) {
|
|
122
159
|
throw new errors.InputError(`${ctx}: entry must not contain line breaks`);
|
|
123
160
|
}
|
|
124
|
-
|
|
125
|
-
throw new errors.InputError(`${ctx}: entry must not contain "{"`);
|
|
126
|
-
}
|
|
127
|
-
if (element.includes("}")) {
|
|
128
|
-
throw new errors.InputError(`${ctx}: entry must not contain "}"`);
|
|
129
|
-
}
|
|
161
|
+
assertNoUnquotedLogQlBraces(element, ctx);
|
|
130
162
|
return element;
|
|
131
163
|
});
|
|
132
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.cjs.js","sources":["../../src/workflowLogsProviders/helpers.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\n\n/**\n * Returns whether `hostname` matches any entry in `allowedHosts` (case-insensitive).\n * Empty or whitespace-only patterns are ignored.\n */\nexport function hostnameMatchesAllowedHosts(\n hostname: string,\n allowedHosts: string[],\n): boolean {\n const hostLower = hostname.toLowerCase();\n return allowedHosts.some(pattern => {\n const p = pattern.trim().toLowerCase();\n if (!p) {\n return false;\n }\n if (p.startsWith('.')) {\n const suffix = p.slice(1);\n return hostLower === suffix || hostLower.endsWith(`.${suffix}`);\n }\n return hostLower === p;\n });\n}\n\n/**\n * Parses baseUrl, applies scheme/host policy, and returns a normalized origin[+path] base\n * (no trailing slash) for appending Loki API paths.\n */\nexport function parseAndValidateLokiBaseUrl(options: {\n rawBaseUrl: string;\n allowedHosts?: string[];\n allowInsecureHttp?: boolean;\n}): string {\n const trimmed = options.rawBaseUrl.trim();\n if (!trimmed) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not be empty',\n );\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl must be a valid absolute URL, got \"${trimmed}\"`,\n );\n }\n\n if (parsed.username || parsed.password) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not include embedded credentials',\n );\n }\n\n if (parsed.search || parsed.hash) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not include a query or fragment',\n );\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl must use http: or https:, got \"${parsed.protocol}\"`,\n );\n }\n\n if (!parsed.hostname) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must include a hostname',\n );\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n if (\n isProduction &&\n parsed.protocol === 'http:' &&\n options.allowInsecureHttp !== true\n ) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must use https in production (set allowInsecureHttp to true only if you explicitly require http)',\n );\n }\n\n const hosts = options.allowedHosts?.map(h => h.trim()).filter(Boolean) ?? [];\n if (\n hosts.length > 0 &&\n !hostnameMatchesAllowedHosts(parsed.hostname, hosts)\n ) {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl hostname \"${parsed.hostname}\" is not allowed by allowedHosts`,\n );\n }\n\n let pathname = parsed.pathname;\n while (pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n return pathname ? `${parsed.origin}${pathname}` : parsed.origin;\n}\n\n/** Prometheus / Loki stream label names: `[a-zA-Z_]\\w*` (ASCII `\\w` only; no `/u` flag). */\nconst LOKI_LABEL_NAME_PATTERN = /^[a-zA-Z_]\\w*$/;\nconst PROMETHEUS_LABEL_NAME_RULE_DESC = String.raw`[a-zA-Z_]\\w*`;\n\n/**\n * Label matcher fragment after the label name: `=\"...\"`, `!=`, regex with `\"` or `` ` ``.\n * Requires properly closed quotes and escapes so the fragment cannot break out of `{...}`.\n */\nconst LOG_STREAM_SELECTOR_VALUE_PATTERNS: RegExp[] = [\n /^=(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\")$/,\n /^!=(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\")$/,\n /^=~(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|`[^`\\r\\n]*`)$/,\n /^!~(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|`[^`\\r\\n]*`)$/,\n];\n\nexport interface ValidatedLogStreamSelector {\n label: string;\n value: string;\n}\n\nfunction assertValidLokiLabelName(label: string, context: string): void {\n if (!LOKI_LABEL_NAME_PATTERN.test(label)) {\n throw new Error(\n `${context}: label must match Prometheus label name rules ${PROMETHEUS_LABEL_NAME_RULE_DESC} (got \"${label}\")`,\n );\n }\n}\n\nfunction assertValidLogStreamSelectorValue(\n value: string,\n context: string,\n): void {\n if (\n !LOG_STREAM_SELECTOR_VALUE_PATTERNS.some(pattern => pattern.test(value))\n ) {\n throw new Error(\n `${context}: value must be a LogQL label matcher (e.g. =\"literal\", !=\"...\", =~\"re\", or =~\\`re\\`) with no raw line breaks outside escapes`,\n );\n }\n}\n\n/**\n * Reads and validates `logStreamSelectors` at startup.\n */\nexport function parseAndValidateLogStreamSelectors(\n lokiConfig: Config,\n configKeyPath: string,\n): ValidatedLogStreamSelector[] {\n const entries = lokiConfig.getOptionalConfigArray('logStreamSelectors');\n if (!entries?.length) {\n return [];\n }\n return entries.map((entry, i) => {\n const label = entry.getOptionalString('label') ?? 'openshift_log_type';\n const value = entry.getOptionalString('value') ?? '=\"application\"';\n const ctxBase = `${configKeyPath}[${i}]`;\n assertValidLokiLabelName(label, ctxBase);\n assertValidLogStreamSelectorValue(value, ctxBase);\n return { label, value };\n });\n}\n\n/**\n * Reads and validates `logPipelineFilters` at startup.\n */\nexport function parseAndValidateLogPipelineFilters(\n lokiConfig: Config,\n configKeyPath: string,\n): string[] {\n const filters = lokiConfig.getOptionalStringArray('logPipelineFilters');\n if (!filters?.length) {\n return [];\n }\n return filters.map((raw, i) => {\n const element = raw.trim();\n const ctx = `${configKeyPath}[${i}]`;\n if (!element) {\n throw new InputError(\n `${ctx}: entry must not be empty or whitespace-only`,\n );\n }\n if (/[\\r\\n\\u2028\\u2029]/.test(element)) {\n throw new InputError(`${ctx}: entry must not contain line breaks`);\n }\n if (element.includes('{')) {\n throw new InputError(`${ctx}: entry must not contain \"{\"`);\n }\n if (element.includes('}')) {\n throw new InputError(`${ctx}: entry must not contain \"}\"`);\n }\n return element;\n });\n}\n\nfunction workflowInstanceIdHasDisallowedChars(id: string): boolean {\n for (let i = 0; i < id.length; i++) {\n const c = id.codePointAt(i);\n if (c === undefined) {\n continue;\n }\n if (\n (c >= 0x00 && c <= 0x08) ||\n c === 0x0b ||\n c === 0x0c ||\n (c >= 0x0e && c <= 0x1f) ||\n c === 0x7f ||\n c === 0x0a ||\n c === 0x0d ||\n c === 0x2028 ||\n c === 0x2029\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Rejects instance ids that cannot be safely embedded in a LogQL line filter.\n */\nexport function assertSafeWorkflowInstanceIdForLineFilter(id: string): void {\n if (workflowInstanceIdHasDisallowedChars(id)) {\n throw new InputError(\n 'Workflow instance id contains characters that are not allowed in Loki line filters',\n );\n }\n}\n\n/**\n * Escapes a string for use inside LogQL double-quoted line filter literals (`|=\"...\"`).\n */\nexport function escapeLogQlDoubleQuotedLineLiteral(fragment: string): string {\n return fragment\n .replaceAll('\\\\', String.raw`\\\\`)\n .replaceAll('\"', String.raw`\\\"`);\n}\n"],"names":["InputError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"helpers.cjs.js","sources":["../../src/workflowLogsProviders/helpers.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Config } from '@backstage/config';\nimport { InputError } from '@backstage/errors';\n\n/**\n * Returns whether `hostname` matches any entry in `allowedHosts` (case-insensitive).\n * Empty or whitespace-only patterns are ignored.\n */\nexport function hostnameMatchesAllowedHosts(\n hostname: string,\n allowedHosts: string[],\n): boolean {\n const hostLower = hostname.toLowerCase();\n return allowedHosts.some(pattern => {\n const p = pattern.trim().toLowerCase();\n if (!p) {\n return false;\n }\n if (p.startsWith('.')) {\n const suffix = p.slice(1);\n return hostLower === suffix || hostLower.endsWith(`.${suffix}`);\n }\n return hostLower === p;\n });\n}\n\n/**\n * Parses baseUrl, applies scheme/host policy, and returns a normalized origin[+path] base\n * (no trailing slash) for appending Loki API paths.\n */\nexport function parseAndValidateLokiBaseUrl(options: {\n rawBaseUrl: string;\n allowedHosts?: string[];\n allowInsecureHttp?: boolean;\n}): string {\n const trimmed = options.rawBaseUrl.trim();\n if (!trimmed) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not be empty',\n );\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl must be a valid absolute URL, got \"${trimmed}\"`,\n );\n }\n\n if (parsed.username || parsed.password) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not include embedded credentials',\n );\n }\n\n if (parsed.search || parsed.hash) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must not include a query or fragment',\n );\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl must use http: or https:, got \"${parsed.protocol}\"`,\n );\n }\n\n if (!parsed.hostname) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must include a hostname',\n );\n }\n\n const isProduction = process.env.NODE_ENV === 'production';\n if (\n isProduction &&\n parsed.protocol === 'http:' &&\n options.allowInsecureHttp !== true\n ) {\n throw new InputError(\n 'orchestrator.workflowLogProvider.loki.baseUrl must use https in production (set allowInsecureHttp to true only if you explicitly require http)',\n );\n }\n\n const hosts = options.allowedHosts?.map(h => h.trim()).filter(Boolean) ?? [];\n if (\n hosts.length > 0 &&\n !hostnameMatchesAllowedHosts(parsed.hostname, hosts)\n ) {\n throw new InputError(\n `orchestrator.workflowLogProvider.loki.baseUrl hostname \"${parsed.hostname}\" is not allowed by allowedHosts`,\n );\n }\n\n let pathname = parsed.pathname;\n while (pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1);\n }\n return pathname ? `${parsed.origin}${pathname}` : parsed.origin;\n}\n\n/** Prometheus / Loki stream label names: `[a-zA-Z_]\\w*` (ASCII `\\w` only; no `/u` flag). */\nconst LOKI_LABEL_NAME_PATTERN = /^[a-zA-Z_]\\w*$/;\nconst PROMETHEUS_LABEL_NAME_RULE_DESC = String.raw`[a-zA-Z_]\\w*`;\n\n/**\n * Label matcher fragment after the label name: `=\"...\"`, `!=`, regex with `\"` or `` ` ``.\n * Requires properly closed quotes and escapes so the fragment cannot break out of `{...}`.\n */\nconst LOG_STREAM_SELECTOR_VALUE_PATTERNS: RegExp[] = [\n /^=(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\")$/,\n /^!=(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\")$/,\n /^=~(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|`[^`\\r\\n]*`)$/,\n /^!~(?:\"(?:[^\"\\\\\\r\\n]|\\\\.)*\"|`[^`\\r\\n]*`)$/,\n];\n\nexport interface ValidatedLogStreamSelector {\n label: string;\n value: string;\n}\n\nfunction assertValidLokiLabelName(label: string, context: string): void {\n if (!LOKI_LABEL_NAME_PATTERN.test(label)) {\n throw new Error(\n `${context}: label must match Prometheus label name rules ${PROMETHEUS_LABEL_NAME_RULE_DESC} (got \"${label}\")`,\n );\n }\n}\n\nfunction assertValidLogStreamSelectorValue(\n value: string,\n context: string,\n): void {\n if (\n !LOG_STREAM_SELECTOR_VALUE_PATTERNS.some(pattern => pattern.test(value))\n ) {\n throw new Error(\n `${context}: value must be a LogQL label matcher (e.g. =\"literal\", !=\"...\", =~\"re\", or =~\\`re\\`) with no raw line breaks outside escapes`,\n );\n }\n}\n\n/**\n * Reads and validates `logStreamSelectors` at startup.\n */\nexport function parseAndValidateLogStreamSelectors(\n lokiConfig: Config,\n configKeyPath: string,\n): ValidatedLogStreamSelector[] {\n const entries = lokiConfig.getOptionalConfigArray('logStreamSelectors');\n if (!entries?.length) {\n return [];\n }\n return entries.map((entry, i) => {\n const label = entry.getOptionalString('label') ?? 'openshift_log_type';\n const value = entry.getOptionalString('value') ?? '=\"application\"';\n const ctxBase = `${configKeyPath}[${i}]`;\n assertValidLokiLabelName(label, ctxBase);\n assertValidLogStreamSelectorValue(value, ctxBase);\n return { label, value };\n });\n}\n\n/**\n * Rejects `{` / `}` outside quoted LogQL literals so pipeline config cannot\n * close the stream selector (`{...}`) and inject a new selector. Braces inside\n * `\"...\"` or `` `...` `` (e.g. `line_format \"{{.message}}\"`) are allowed.\n */\nfunction assertNoUnquotedLogQlBraces(element: string, context: string): void {\n let i = 0;\n while (i < element.length) {\n const ch = element[i];\n if (ch === '\"') {\n i = skipQuotedString(element, i + 1, '\"', context);\n continue;\n }\n if (ch === '`') {\n i = skipQuotedString(element, i + 1, '`', context);\n continue;\n }\n if (ch === '{' || ch === '}') {\n throw new InputError(\n `${context}: entry must not contain unquoted \"{\" or \"}\"`,\n );\n }\n i++;\n }\n}\n\nfunction skipQuotedString(\n element: string,\n start: number,\n quote: '\"' | '`',\n context: string,\n): number {\n let i = start;\n while (i < element.length) {\n const ch = element[i];\n if (quote === '\"' && ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === quote) {\n return i + 1;\n }\n i++;\n }\n throw new InputError(\n `${context}: entry contains an unclosed ${quote === '\"' ? 'double-quoted' : 'backtick-quoted'} string`,\n );\n}\n\n/**\n * Reads and validates `logPipelineFilters` at startup.\n */\nexport function parseAndValidateLogPipelineFilters(\n lokiConfig: Config,\n configKeyPath: string,\n): string[] {\n const filters = lokiConfig.getOptionalStringArray('logPipelineFilters');\n if (!filters?.length) {\n return [];\n }\n return filters.map((raw, i) => {\n const element = raw.trim();\n const ctx = `${configKeyPath}[${i}]`;\n if (!element) {\n throw new InputError(\n `${ctx}: entry must not be empty or whitespace-only`,\n );\n }\n if (/[\\r\\n\\u2028\\u2029]/.test(element)) {\n throw new InputError(`${ctx}: entry must not contain line breaks`);\n }\n assertNoUnquotedLogQlBraces(element, ctx);\n return element;\n });\n}\n\nfunction workflowInstanceIdHasDisallowedChars(id: string): boolean {\n for (let i = 0; i < id.length; i++) {\n const c = id.codePointAt(i);\n if (c === undefined) {\n continue;\n }\n if (\n (c >= 0x00 && c <= 0x08) ||\n c === 0x0b ||\n c === 0x0c ||\n (c >= 0x0e && c <= 0x1f) ||\n c === 0x7f ||\n c === 0x0a ||\n c === 0x0d ||\n c === 0x2028 ||\n c === 0x2029\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Rejects instance ids that cannot be safely embedded in a LogQL line filter.\n */\nexport function assertSafeWorkflowInstanceIdForLineFilter(id: string): void {\n if (workflowInstanceIdHasDisallowedChars(id)) {\n throw new InputError(\n 'Workflow instance id contains characters that are not allowed in Loki line filters',\n );\n }\n}\n\n/**\n * Escapes a string for use inside LogQL double-quoted line filter literals (`|=\"...\"`).\n */\nexport function escapeLogQlDoubleQuotedLineLiteral(fragment: string): string {\n return fragment\n .replaceAll('\\\\', String.raw`\\\\`)\n .replaceAll('\"', String.raw`\\\"`);\n}\n"],"names":["InputError"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@red-hat-developer-hub/backstage-plugin-orchestrator-backend-module-loki",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "The loki backend module for the orchestrator plugin.",
|
|
6
6
|
"main": "./dist/index.cjs.js",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@backstage/backend-plugin-api": "^1.9.1",
|
|
49
49
|
"@backstage/errors": "^1.3.1",
|
|
50
|
-
"@red-hat-developer-hub/backstage-plugin-orchestrator-common": "^3.7.
|
|
51
|
-
"@red-hat-developer-hub/backstage-plugin-orchestrator-node": "^1.3.
|
|
50
|
+
"@red-hat-developer-hub/backstage-plugin-orchestrator-common": "^3.7.1",
|
|
51
|
+
"@red-hat-developer-hub/backstage-plugin-orchestrator-node": "^1.3.1",
|
|
52
52
|
"luxon": "^3.7.2",
|
|
53
53
|
"undici": "^7.24.0"
|
|
54
54
|
},
|