@backstage/backend-defaults 0.15.1 → 0.15.2
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 +50 -6
- package/config.d.ts +26 -0
- package/dist/PackageDiscoveryService.cjs.js +1 -1
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js +2 -2
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js +2 -2
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheClient.cjs.js +2 -2
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js +2 -2
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js +191 -157
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js +2 -2
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +4 -4
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js +2 -2
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js +2 -2
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +4 -4
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +6 -6
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js +2 -2
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js +25 -7
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js +30 -13
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/util.cjs.js +3 -3
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
- package/dist/httpRouter.cjs.js +2 -0
- package/dist/httpRouter.cjs.js.map +1 -1
- package/dist/httpRouter.d.ts +10 -1
- package/dist/package.json.cjs.js +1 -1
- package/dist/rootHttpRouter.d.ts +2 -3
- package/dist/urlReader.d.ts +1 -1
- package/package.json +16 -15
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js +0 -12
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,59 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
-
## 0.15.
|
|
3
|
+
## 0.15.2
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- 7455dae: Use node prefix on native imports
|
|
8
|
+
- 44f5d04: Minor internal restructure of the postgres config loading code
|
|
9
|
+
- 4fc7bf0: Bump to tar v7
|
|
10
|
+
- 5dd683f: `createRateLimitMiddleware` is now exported from `@backstage/backend-defaults/httpRouter`
|
|
11
|
+
- 8dd518a: Support `connection.type: azure` in database client to use Microsoft Entra authentication with Azure database for PostgreSQL
|
|
12
|
+
- 69d880e: Bump to latest zod to ensure it has the latest features
|
|
8
13
|
- Updated dependencies
|
|
9
|
-
- @backstage/backend-
|
|
10
|
-
- @backstage/
|
|
11
|
-
- @backstage/
|
|
12
|
-
- @backstage/plugin-
|
|
14
|
+
- @backstage/backend-app-api@1.5.0
|
|
15
|
+
- @backstage/integration@1.20.0
|
|
16
|
+
- @backstage/integration-aws-node@0.1.20
|
|
17
|
+
- @backstage/backend-plugin-api@1.7.0
|
|
18
|
+
- @backstage/backend-dev-utils@0.1.7
|
|
19
|
+
- @backstage/config-loader@1.10.8
|
|
20
|
+
- @backstage/cli-node@0.2.18
|
|
21
|
+
- @backstage/plugin-auth-node@0.6.13
|
|
22
|
+
- @backstage/plugin-permission-node@0.10.10
|
|
23
|
+
- @backstage/plugin-events-node@0.4.19
|
|
24
|
+
|
|
25
|
+
## 0.15.2-next.1
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- 8dd518a: Support `connection.type: azure` in database client to use Microsoft Entra authentication with Azure database for PostgreSQL
|
|
30
|
+
- Updated dependencies
|
|
31
|
+
- @backstage/integration@1.20.0-next.1
|
|
32
|
+
- @backstage/cli-node@0.2.18-next.1
|
|
33
|
+
- @backstage/backend-plugin-api@1.7.0-next.1
|
|
34
|
+
|
|
35
|
+
## 0.15.1-next.0
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- 7455dae: Use node prefix on native imports
|
|
40
|
+
- 44f5d04: Minor internal restructure of the postgres config loading code
|
|
41
|
+
- 4fc7bf0: Bump to tar v7
|
|
42
|
+
- 69d880e: Bump to latest zod to ensure it has the latest features
|
|
43
|
+
- Updated dependencies
|
|
44
|
+
- @backstage/integration-aws-node@0.1.20-next.0
|
|
45
|
+
- @backstage/backend-plugin-api@1.7.0-next.0
|
|
46
|
+
- @backstage/backend-dev-utils@0.1.7-next.0
|
|
47
|
+
- @backstage/config-loader@1.10.8-next.0
|
|
48
|
+
- @backstage/integration@1.19.3-next.0
|
|
49
|
+
- @backstage/cli-node@0.2.17-next.0
|
|
50
|
+
- @backstage/plugin-auth-node@0.6.12-next.0
|
|
51
|
+
- @backstage/backend-app-api@1.5.0-next.0
|
|
52
|
+
- @backstage/plugin-permission-node@0.10.9-next.0
|
|
53
|
+
- @backstage/plugin-events-node@0.4.19-next.0
|
|
54
|
+
- @backstage/config@1.3.6
|
|
55
|
+
- @backstage/errors@1.2.7
|
|
56
|
+
- @backstage/types@1.2.2
|
|
13
57
|
|
|
14
58
|
## 0.15.0
|
|
15
59
|
|
package/config.d.ts
CHANGED
|
@@ -592,6 +592,32 @@ export interface Config {
|
|
|
592
592
|
*/
|
|
593
593
|
connection:
|
|
594
594
|
| string
|
|
595
|
+
| {
|
|
596
|
+
/**
|
|
597
|
+
* The specific config for Azure database for PostgreSQL connections with Entra authentication
|
|
598
|
+
*/
|
|
599
|
+
type: 'azure';
|
|
600
|
+
/**
|
|
601
|
+
* Optional Azure token credential configuration
|
|
602
|
+
*/
|
|
603
|
+
tokenCredential?: {
|
|
604
|
+
/**
|
|
605
|
+
* How early before an access token expires to refresh it with a new one.
|
|
606
|
+
* Defaults to 5 minutes
|
|
607
|
+
* Supported formats:
|
|
608
|
+
* - A string in the format of '1d', '2 seconds' etc. as supported by the `ms` library.
|
|
609
|
+
* - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'.
|
|
610
|
+
* - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`.
|
|
611
|
+
*/
|
|
612
|
+
tokenRenewableOffsetTime?: string | HumanDuration;
|
|
613
|
+
clientId?: string;
|
|
614
|
+
/**
|
|
615
|
+
* @visibility secret
|
|
616
|
+
*/
|
|
617
|
+
clientSecret?: string;
|
|
618
|
+
tenantId?: string;
|
|
619
|
+
};
|
|
620
|
+
}
|
|
595
621
|
| {
|
|
596
622
|
/**
|
|
597
623
|
* The specific config for cloudsql connections
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fs = require('fs-extra');
|
|
4
|
-
var platformPath = require('path');
|
|
4
|
+
var platformPath = require('node:path');
|
|
5
5
|
var errors = require('@backstage/errors');
|
|
6
6
|
|
|
7
7
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PackageDiscoveryService.cjs.js","sources":["../src/PackageDiscoveryService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\n\nimport {\n BackendFeature,\n RootConfigService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { isError } from '@backstage/errors';\n\nconst DETECTED_PACKAGE_ROLES = [\n 'node-library',\n 'backend',\n 'backend-plugin',\n 'backend-plugin-module',\n];\n\n/** @internal */\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n ['object', 'function'].includes(typeof value) &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\n/** @internal */\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n\n/** @internal */\nasync function findClosestPackageDir(\n searchDir: string,\n): Promise<string | undefined> {\n let path = searchDir;\n\n // Some confidence check to avoid infinite loop\n for (let i = 0; i < 1000; i++) {\n const packagePath = resolvePath(path, 'package.json');\n const exists = await fs.pathExists(packagePath);\n if (exists) {\n return path;\n }\n\n const newPath = dirname(path);\n if (newPath === path) {\n return undefined;\n }\n path = newPath;\n }\n\n throw new Error(\n `Iteration limit reached when searching for root package.json at ${searchDir}`,\n );\n}\n\n/** @internal */\nexport class PackageDiscoveryService {\n private readonly config: RootConfigService;\n private readonly logger: RootLoggerService;\n\n constructor(config: RootConfigService, logger: RootLoggerService) {\n this.config = config;\n this.logger = logger;\n }\n\n getDependencyNames(path: string) {\n const { dependencies } = require(path) as BackstagePackageJson;\n const packagesConfig = this.config.getOptional('backend.packages');\n\n const dependencyNames = Object.keys(dependencies || {});\n\n if (packagesConfig === 'all') {\n return dependencyNames;\n }\n\n const includedPackagesConfig = this.config.getOptionalStringArray(\n 'backend.packages.include',\n );\n\n const includedPackages = includedPackagesConfig\n ? new Set(includedPackagesConfig)\n : dependencyNames;\n const excludedPackagesSet = new Set(\n this.config.getOptionalStringArray('backend.packages.exclude'),\n );\n\n return [...includedPackages].filter(name => !excludedPackagesSet.has(name));\n }\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const packagesConfig = this.config.getOptional('backend.packages');\n if (!packagesConfig || Object.keys(packagesConfig).length === 0) {\n return { features: [] };\n }\n\n const packageDir = await findClosestPackageDir(process.argv[1]);\n if (!packageDir) {\n throw new Error('Package discovery failed to find package.json');\n }\n const dependencyNames = this.getDependencyNames(\n resolvePath(packageDir, 'package.json'),\n );\n\n const features: BackendFeature[] = [];\n\n for (const name of dependencyNames) {\n let depPkg: BackstagePackageJson;\n try {\n const packageJsonPath = require.resolve(`${name}/package.json`, {\n paths: [packageDir],\n });\n depPkg = require(packageJsonPath) as BackstagePackageJson;\n } catch (error) {\n // Handle packages with \"exports\" field that don't export ./package.json\n if (isError(error) && error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {\n continue; // Skip packages that don't export package.json - they can't be Backstage packages\n }\n throw error;\n }\n if (\n !depPkg?.backstage?.role ||\n !DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)\n ) {\n continue; // Not a backstage backend package, ignore\n }\n\n const exportedModulePaths = [\n require.resolve(name, {\n paths: [packageDir],\n }),\n ];\n\n // Find modules exported as alpha\n try {\n exportedModulePaths.push(\n require.resolve(`${name}/alpha`, { paths: [packageDir] }),\n );\n } catch {\n /* ignore */\n }\n\n for (const modulePath of exportedModulePaths) {\n const mod = require(modulePath);\n\n if (isBackendFeature(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default);\n }\n if (isBackendFeatureFactory(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default());\n }\n }\n }\n\n return { features: Array.from(new Set(features)) };\n }\n}\n"],"names":["resolvePath","fs","dirname","isError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PackageDiscoveryService.cjs.js","sources":["../src/PackageDiscoveryService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'node:path';\n\nimport {\n BackendFeature,\n RootConfigService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { BackstagePackageJson } from '@backstage/cli-node';\nimport { isError } from '@backstage/errors';\n\nconst DETECTED_PACKAGE_ROLES = [\n 'node-library',\n 'backend',\n 'backend-plugin',\n 'backend-plugin-module',\n];\n\n/** @internal */\nfunction isBackendFeature(value: unknown): value is BackendFeature {\n return (\n !!value &&\n ['object', 'function'].includes(typeof value) &&\n (value as BackendFeature).$$type === '@backstage/BackendFeature'\n );\n}\n\n/** @internal */\nfunction isBackendFeatureFactory(\n value: unknown,\n): value is () => BackendFeature {\n return (\n !!value &&\n typeof value === 'function' &&\n (value as any).$$type === '@backstage/BackendFeatureFactory'\n );\n}\n\n/** @internal */\nasync function findClosestPackageDir(\n searchDir: string,\n): Promise<string | undefined> {\n let path = searchDir;\n\n // Some confidence check to avoid infinite loop\n for (let i = 0; i < 1000; i++) {\n const packagePath = resolvePath(path, 'package.json');\n const exists = await fs.pathExists(packagePath);\n if (exists) {\n return path;\n }\n\n const newPath = dirname(path);\n if (newPath === path) {\n return undefined;\n }\n path = newPath;\n }\n\n throw new Error(\n `Iteration limit reached when searching for root package.json at ${searchDir}`,\n );\n}\n\n/** @internal */\nexport class PackageDiscoveryService {\n private readonly config: RootConfigService;\n private readonly logger: RootLoggerService;\n\n constructor(config: RootConfigService, logger: RootLoggerService) {\n this.config = config;\n this.logger = logger;\n }\n\n getDependencyNames(path: string) {\n const { dependencies } = require(path) as BackstagePackageJson;\n const packagesConfig = this.config.getOptional('backend.packages');\n\n const dependencyNames = Object.keys(dependencies || {});\n\n if (packagesConfig === 'all') {\n return dependencyNames;\n }\n\n const includedPackagesConfig = this.config.getOptionalStringArray(\n 'backend.packages.include',\n );\n\n const includedPackages = includedPackagesConfig\n ? new Set(includedPackagesConfig)\n : dependencyNames;\n const excludedPackagesSet = new Set(\n this.config.getOptionalStringArray('backend.packages.exclude'),\n );\n\n return [...includedPackages].filter(name => !excludedPackagesSet.has(name));\n }\n\n async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {\n const packagesConfig = this.config.getOptional('backend.packages');\n if (!packagesConfig || Object.keys(packagesConfig).length === 0) {\n return { features: [] };\n }\n\n const packageDir = await findClosestPackageDir(process.argv[1]);\n if (!packageDir) {\n throw new Error('Package discovery failed to find package.json');\n }\n const dependencyNames = this.getDependencyNames(\n resolvePath(packageDir, 'package.json'),\n );\n\n const features: BackendFeature[] = [];\n\n for (const name of dependencyNames) {\n let depPkg: BackstagePackageJson;\n try {\n const packageJsonPath = require.resolve(`${name}/package.json`, {\n paths: [packageDir],\n });\n depPkg = require(packageJsonPath) as BackstagePackageJson;\n } catch (error) {\n // Handle packages with \"exports\" field that don't export ./package.json\n if (isError(error) && error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {\n continue; // Skip packages that don't export package.json - they can't be Backstage packages\n }\n throw error;\n }\n if (\n !depPkg?.backstage?.role ||\n !DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)\n ) {\n continue; // Not a backstage backend package, ignore\n }\n\n const exportedModulePaths = [\n require.resolve(name, {\n paths: [packageDir],\n }),\n ];\n\n // Find modules exported as alpha\n try {\n exportedModulePaths.push(\n require.resolve(`${name}/alpha`, { paths: [packageDir] }),\n );\n } catch {\n /* ignore */\n }\n\n for (const modulePath of exportedModulePaths) {\n const mod = require(modulePath);\n\n if (isBackendFeature(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default);\n }\n if (isBackendFeatureFactory(mod.default)) {\n this.logger.info(`Detected: ${name}`);\n features.push(mod.default());\n }\n }\n }\n\n return { features: Array.from(new Set(features)) };\n }\n}\n"],"names":["resolvePath","fs","dirname","isError"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
4
|
|
|
5
5
|
function createCredentialsWithServicePrincipal(sub, token, accessRestrictions) {
|
|
6
6
|
const principal = createServicePrincipal(sub, accessRestrictions);
|
|
@@ -95,7 +95,7 @@ function createServicePrincipal(sub, accessRestrictions) {
|
|
|
95
95
|
value: () => {
|
|
96
96
|
let parts = sub;
|
|
97
97
|
if (accessRestrictions) {
|
|
98
|
-
const hash =
|
|
98
|
+
const hash = node_crypto.createHash("sha256").update(JSON.stringify(accessRestrictions)).digest("base64").replace(/=+$/, "");
|
|
99
99
|
parts += `,accessRestrictions=${hash}`;
|
|
100
100
|
}
|
|
101
101
|
return `servicePrincipal{${parts}}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.cjs.js","sources":["../../../src/entrypoints/auth/helpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { InternalBackstageCredentials } from './types';\nimport { createHash } from 'crypto';\n\nexport function createCredentialsWithServicePrincipal(\n sub: string,\n token?: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): InternalBackstageCredentials<BackstageServicePrincipal> {\n const principal = createServicePrincipal(sub, accessRestrictions);\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal,\n } as const;\n Object.defineProperties(result, {\n token: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: token,\n },\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function createCredentialsWithUserPrincipal(\n sub: string,\n token: string,\n expiresAt?: Date,\n actor?: string,\n): InternalBackstageCredentials<BackstageUserPrincipal> {\n const principal = createUserPrincipal(\n sub,\n actor ? createServicePrincipal(actor) : undefined,\n );\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n expiresAt,\n principal,\n } as const;\n Object.defineProperties(result, {\n token: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: token,\n },\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function createCredentialsWithNonePrincipal(): InternalBackstageCredentials<BackstageNonePrincipal> {\n const principal = createNonePrincipal();\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function toInternalBackstageCredentials(\n credentials: BackstageCredentials,\n): InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n> {\n if (credentials.$$type !== '@backstage/BackstageCredentials') {\n throw new Error('Invalid credential type');\n }\n\n const internalCredentials = credentials as InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n >;\n\n if (internalCredentials.version !== 'v1') {\n throw new Error(\n `Invalid credential version ${internalCredentials.version}`,\n );\n }\n\n return internalCredentials;\n}\n\nfunction createServicePrincipal(\n sub: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): BackstageServicePrincipal {\n const result = {\n type: 'service',\n subject: sub,\n accessRestrictions,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => {\n let parts = sub;\n if (accessRestrictions) {\n const hash = createHash('sha256')\n .update(JSON.stringify(accessRestrictions))\n .digest('base64')\n .replace(/=+$/, '');\n parts += `,accessRestrictions=${hash}`;\n }\n return `servicePrincipal{${parts}}`;\n },\n },\n });\n return result;\n}\n\nfunction createUserPrincipal(\n userEntityRef: string,\n actor?: BackstageServicePrincipal,\n): BackstageUserPrincipal {\n const result = {\n type: 'user',\n userEntityRef,\n actor,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => {\n let parts = userEntityRef;\n if (actor) {\n parts += `,actor={${actor}}`;\n }\n return `userPrincipal{${parts}}`;\n },\n },\n });\n return result;\n}\n\nfunction createNonePrincipal(): BackstageNonePrincipal {\n const result = {\n type: 'none',\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => 'nonePrincipal',\n },\n });\n return result;\n}\n"],"names":["createHash"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"helpers.cjs.js","sources":["../../../src/entrypoints/auth/helpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { InternalBackstageCredentials } from './types';\nimport { createHash } from 'node:crypto';\n\nexport function createCredentialsWithServicePrincipal(\n sub: string,\n token?: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): InternalBackstageCredentials<BackstageServicePrincipal> {\n const principal = createServicePrincipal(sub, accessRestrictions);\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal,\n } as const;\n Object.defineProperties(result, {\n token: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: token,\n },\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function createCredentialsWithUserPrincipal(\n sub: string,\n token: string,\n expiresAt?: Date,\n actor?: string,\n): InternalBackstageCredentials<BackstageUserPrincipal> {\n const principal = createUserPrincipal(\n sub,\n actor ? createServicePrincipal(actor) : undefined,\n );\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n expiresAt,\n principal,\n } as const;\n Object.defineProperties(result, {\n token: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: token,\n },\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function createCredentialsWithNonePrincipal(): InternalBackstageCredentials<BackstageNonePrincipal> {\n const principal = createNonePrincipal();\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `backstageCredentials{${principal}}`,\n },\n });\n return result;\n}\n\nexport function toInternalBackstageCredentials(\n credentials: BackstageCredentials,\n): InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n> {\n if (credentials.$$type !== '@backstage/BackstageCredentials') {\n throw new Error('Invalid credential type');\n }\n\n const internalCredentials = credentials as InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n >;\n\n if (internalCredentials.version !== 'v1') {\n throw new Error(\n `Invalid credential version ${internalCredentials.version}`,\n );\n }\n\n return internalCredentials;\n}\n\nfunction createServicePrincipal(\n sub: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): BackstageServicePrincipal {\n const result = {\n type: 'service',\n subject: sub,\n accessRestrictions,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => {\n let parts = sub;\n if (accessRestrictions) {\n const hash = createHash('sha256')\n .update(JSON.stringify(accessRestrictions))\n .digest('base64')\n .replace(/=+$/, '');\n parts += `,accessRestrictions=${hash}`;\n }\n return `servicePrincipal{${parts}}`;\n },\n },\n });\n return result;\n}\n\nfunction createUserPrincipal(\n userEntityRef: string,\n actor?: BackstageServicePrincipal,\n): BackstageUserPrincipal {\n const result = {\n type: 'user',\n userEntityRef,\n actor,\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => {\n let parts = userEntityRef;\n if (actor) {\n parts += `,actor={${actor}}`;\n }\n return `userPrincipal{${parts}}`;\n },\n },\n });\n return result;\n}\n\nfunction createNonePrincipal(): BackstageNonePrincipal {\n const result = {\n type: 'none',\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => 'nonePrincipal',\n },\n });\n return result;\n}\n"],"names":["createHash"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var types = require('@backstage/types');
|
|
4
|
-
var
|
|
4
|
+
var node_fs = require('node:fs');
|
|
5
5
|
var jose = require('jose');
|
|
6
6
|
|
|
7
7
|
const DEFAULT_ALGORITHM = "ES256";
|
|
@@ -69,7 +69,7 @@ class StaticConfigPluginKeySource {
|
|
|
69
69
|
return this.loadKeyFromFile(path, keyId, algorithm, jose.importPKCS8);
|
|
70
70
|
}
|
|
71
71
|
static async loadKeyFromFile(path, keyId, algorithm, importer) {
|
|
72
|
-
const content = await
|
|
72
|
+
const content = await node_fs.promises.readFile(path, { encoding: "utf8", flag: "r" });
|
|
73
73
|
const key = await importer(content, algorithm);
|
|
74
74
|
const jwk = await jose.exportJWK(key);
|
|
75
75
|
jwk.kid = keyId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StaticConfigPluginKeySource.cjs.js","sources":["../../../../../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose';\nimport { KeyPayload } from './types';\nimport { PluginKeySource } from './types';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey?: JWK;\n keyId: string;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile?: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * Key source that loads predefined public/private key pairs from disk.\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the `create` method.\n */\nexport class StaticConfigPluginKeySource implements PluginKeySource {\n private readonly keyPairs: KeyPair[];\n private readonly keyDurationSeconds: number;\n\n private constructor(keyPairs: KeyPair[], keyDurationSeconds: number) {\n this.keyPairs = keyPairs;\n this.keyDurationSeconds = keyDurationSeconds;\n }\n\n public static async create(options: {\n sourceConfig: Config;\n keyDuration: HumanDuration;\n }): Promise<PluginKeySource> {\n const keyConfigs = options.sourceConfig\n .getConfigArray('static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getOptionalString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n if (keyPairs.length < 1) {\n throw new Error(\n 'At least one key pair must be provided in static.keys, when the static key store type is used',\n );\n } else if (!keyPairs[0].privateKey) {\n throw new Error(\n 'Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used',\n );\n }\n\n return new StaticConfigPluginKeySource(\n keyPairs,\n durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS,\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n return this.keyPairs[0].privateKey!;\n }\n\n async listKeys(): Promise<{ keys: KeyPayload[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return { keys };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise<KeyPair> {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = options.privateKeyFile\n ? await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n )\n : undefined;\n\n return { publicKey, privateKey, keyId };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise<KeyLike>,\n ): Promise<JWK> {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): KeyPayload {\n const publicKey = {\n ...keyPair.publicKey,\n kid: keyPair.keyId,\n };\n\n return {\n key: publicKey,\n id: keyPair.keyId,\n expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS),\n };\n }\n}\n"],"names":["durationToMilliseconds","importSPKI","importPKCS8","fs","exportJWK"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"StaticConfigPluginKeySource.cjs.js","sources":["../../../../../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\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 { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'node:fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose';\nimport { KeyPayload } from './types';\nimport { PluginKeySource } from './types';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey?: JWK;\n keyId: string;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile?: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * Key source that loads predefined public/private key pairs from disk.\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the `create` method.\n */\nexport class StaticConfigPluginKeySource implements PluginKeySource {\n private readonly keyPairs: KeyPair[];\n private readonly keyDurationSeconds: number;\n\n private constructor(keyPairs: KeyPair[], keyDurationSeconds: number) {\n this.keyPairs = keyPairs;\n this.keyDurationSeconds = keyDurationSeconds;\n }\n\n public static async create(options: {\n sourceConfig: Config;\n keyDuration: HumanDuration;\n }): Promise<PluginKeySource> {\n const keyConfigs = options.sourceConfig\n .getConfigArray('static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getOptionalString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n if (keyPairs.length < 1) {\n throw new Error(\n 'At least one key pair must be provided in static.keys, when the static key store type is used',\n );\n } else if (!keyPairs[0].privateKey) {\n throw new Error(\n 'Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used',\n );\n }\n\n return new StaticConfigPluginKeySource(\n keyPairs,\n durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS,\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n return this.keyPairs[0].privateKey!;\n }\n\n async listKeys(): Promise<{ keys: KeyPayload[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return { keys };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise<KeyPair> {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = options.privateKeyFile\n ? await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n )\n : undefined;\n\n return { publicKey, privateKey, keyId };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise<KeyLike>,\n ): Promise<JWK> {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): KeyPayload {\n const publicKey = {\n ...keyPair.publicKey,\n kid: keyPair.keyId,\n };\n\n return {\n key: publicKey,\n id: keyPair.keyId,\n expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS),\n };\n }\n}\n"],"names":["durationToMilliseconds","importSPKI","importPKCS8","fs","exportJWK"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
4
|
var types = require('./types.cjs.js');
|
|
5
5
|
|
|
6
6
|
class DefaultCacheClient {
|
|
@@ -42,7 +42,7 @@ class DefaultCacheClient {
|
|
|
42
42
|
if (wellFormedKey.length < 200) {
|
|
43
43
|
return wellFormedKey;
|
|
44
44
|
}
|
|
45
|
-
return
|
|
45
|
+
return node_crypto.createHash("sha256").update(candidateKey).digest("base64");
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CacheClient.cjs.js","sources":["../../../src/entrypoints/cache/CacheClient.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\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 {\n CacheService,\n CacheServiceOptions,\n CacheServiceSetOptions,\n} from '@backstage/backend-plugin-api';\nimport { JsonValue } from '@backstage/types';\nimport { createHash } from 'crypto';\nimport Keyv from 'keyv';\nimport { ttlToMilliseconds } from './types';\n\nexport type CacheClientFactory = (options: CacheServiceOptions) => Keyv;\n\n/**\n * A basic, concrete implementation of the CacheService, suitable for almost\n * all uses in Backstage.\n */\nexport class DefaultCacheClient implements CacheService {\n #client: Keyv;\n #clientFactory: CacheClientFactory;\n #options: CacheServiceOptions;\n\n constructor(\n client: Keyv,\n clientFactory: CacheClientFactory,\n options: CacheServiceOptions,\n ) {\n this.#client = client;\n this.#clientFactory = clientFactory;\n this.#options = options;\n }\n\n async get<TValue extends JsonValue>(\n key: string,\n ): Promise<TValue | undefined> {\n const k = this.getNormalizedKey(key);\n const value = await this.#client.get(k);\n return value as TValue | undefined;\n }\n\n async set(\n key: string,\n value: JsonValue,\n opts: CacheServiceSetOptions = {},\n ): Promise<void> {\n const k = this.getNormalizedKey(key);\n const ttl =\n opts.ttl !== undefined ? ttlToMilliseconds(opts.ttl) : undefined;\n await this.#client.set(k, value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n const k = this.getNormalizedKey(key);\n await this.#client.delete(k);\n }\n\n withOptions(options: CacheServiceOptions): CacheService {\n const newOptions = { ...this.#options, ...options };\n return new DefaultCacheClient(\n this.#clientFactory(newOptions),\n this.#clientFactory,\n newOptions,\n );\n }\n\n /**\n * Ensures keys are well-formed for any/all cache stores.\n */\n private getNormalizedKey(candidateKey: string): string {\n // Remove potentially invalid characters.\n const wellFormedKey = Buffer.from(candidateKey).toString('base64');\n\n // Memcache in particular doesn't do well with keys > 250 bytes.\n // Padded because a plugin ID is also prepended to the key.\n if (wellFormedKey.length < 200) {\n return wellFormedKey;\n }\n\n return createHash('sha256').update(candidateKey).digest('base64');\n }\n}\n"],"names":["ttlToMilliseconds","createHash"],"mappings":";;;;;AAgCO,MAAM,kBAAA,CAA2C;AAAA,EACtD,OAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EAEA,WAAA,CACE,MAAA,EACA,aAAA,EACA,OAAA,EACA;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,cAAA,GAAiB,aAAA;AACtB,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAAA,EAClB;AAAA,EAEA,MAAM,IACJ,GAAA,EAC6B;AAC7B,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,CAAA;AACtC,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,MAAM,GAAA,CACJ,GAAA,EACA,KAAA,EACA,IAAA,GAA+B,EAAC,EACjB;AACf,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,MACJ,IAAA,CAAK,GAAA,KAAQ,SAAYA,uBAAA,CAAkB,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AACzD,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,OAAO,GAAG,CAAA;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,GAAA,EAA4B;AACvC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA;AAAA,EAC7B;AAAA,EAEA,YAAY,OAAA,EAA4C;AACtD,IAAA,MAAM,aAAa,EAAE,GAAG,IAAA,CAAK,QAAA,EAAU,GAAG,OAAA,EAAQ;AAClD,IAAA,OAAO,IAAI,kBAAA;AAAA,MACT,IAAA,CAAK,eAAe,UAAU,CAAA;AAAA,MAC9B,IAAA,CAAK,cAAA;AAAA,MACL;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,YAAA,EAA8B;AAErD,IAAA,MAAM,gBAAgB,MAAA,CAAO,IAAA,CAAK,YAAY,CAAA,CAAE,SAAS,QAAQ,CAAA;AAIjE,IAAA,IAAI,aAAA,CAAc,SAAS,GAAA,EAAK;AAC9B,MAAA,OAAO,aAAA;AAAA,IACT;AAEA,IAAA,OAAOC,
|
|
1
|
+
{"version":3,"file":"CacheClient.cjs.js","sources":["../../../src/entrypoints/cache/CacheClient.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\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 {\n CacheService,\n CacheServiceOptions,\n CacheServiceSetOptions,\n} from '@backstage/backend-plugin-api';\nimport { JsonValue } from '@backstage/types';\nimport { createHash } from 'node:crypto';\nimport Keyv from 'keyv';\nimport { ttlToMilliseconds } from './types';\n\nexport type CacheClientFactory = (options: CacheServiceOptions) => Keyv;\n\n/**\n * A basic, concrete implementation of the CacheService, suitable for almost\n * all uses in Backstage.\n */\nexport class DefaultCacheClient implements CacheService {\n #client: Keyv;\n #clientFactory: CacheClientFactory;\n #options: CacheServiceOptions;\n\n constructor(\n client: Keyv,\n clientFactory: CacheClientFactory,\n options: CacheServiceOptions,\n ) {\n this.#client = client;\n this.#clientFactory = clientFactory;\n this.#options = options;\n }\n\n async get<TValue extends JsonValue>(\n key: string,\n ): Promise<TValue | undefined> {\n const k = this.getNormalizedKey(key);\n const value = await this.#client.get(k);\n return value as TValue | undefined;\n }\n\n async set(\n key: string,\n value: JsonValue,\n opts: CacheServiceSetOptions = {},\n ): Promise<void> {\n const k = this.getNormalizedKey(key);\n const ttl =\n opts.ttl !== undefined ? ttlToMilliseconds(opts.ttl) : undefined;\n await this.#client.set(k, value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n const k = this.getNormalizedKey(key);\n await this.#client.delete(k);\n }\n\n withOptions(options: CacheServiceOptions): CacheService {\n const newOptions = { ...this.#options, ...options };\n return new DefaultCacheClient(\n this.#clientFactory(newOptions),\n this.#clientFactory,\n newOptions,\n );\n }\n\n /**\n * Ensures keys are well-formed for any/all cache stores.\n */\n private getNormalizedKey(candidateKey: string): string {\n // Remove potentially invalid characters.\n const wellFormedKey = Buffer.from(candidateKey).toString('base64');\n\n // Memcache in particular doesn't do well with keys > 250 bytes.\n // Padded because a plugin ID is also prepended to the key.\n if (wellFormedKey.length < 200) {\n return wellFormedKey;\n }\n\n return createHash('sha256').update(candidateKey).digest('base64');\n }\n}\n"],"names":["ttlToMilliseconds","createHash"],"mappings":";;;;;AAgCO,MAAM,kBAAA,CAA2C;AAAA,EACtD,OAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EAEA,WAAA,CACE,MAAA,EACA,aAAA,EACA,OAAA,EACA;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,cAAA,GAAiB,aAAA;AACtB,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAAA,EAClB;AAAA,EAEA,MAAM,IACJ,GAAA,EAC6B;AAC7B,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,CAAA;AACtC,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,MAAM,GAAA,CACJ,GAAA,EACA,KAAA,EACA,IAAA,GAA+B,EAAC,EACjB;AACf,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,MACJ,IAAA,CAAK,GAAA,KAAQ,SAAYA,uBAAA,CAAkB,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AACzD,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,OAAO,GAAG,CAAA;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,GAAA,EAA4B;AACvC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACnC,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA;AAAA,EAC7B;AAAA,EAEA,YAAY,OAAA,EAA4C;AACtD,IAAA,MAAM,aAAa,EAAE,GAAG,IAAA,CAAK,QAAA,EAAU,GAAG,OAAA,EAAQ;AAClD,IAAA,OAAO,IAAI,kBAAA;AAAA,MACT,IAAA,CAAK,eAAe,UAAU,CAAA;AAAA,MAC9B,IAAA,CAAK,cAAA;AAAA,MACL;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,YAAA,EAA8B;AAErD,IAAA,MAAM,gBAAgB,MAAA,CAAO,IAAA,CAAK,YAAY,CAAA,CAAE,SAAS,QAAQ,CAAA;AAIjE,IAAA,IAAI,aAAA,CAAc,SAAS,GAAA,EAAK;AAC9B,MAAA,OAAO,aAAA;AAAA,IACT;AAEA,IAAA,OAAOC,uBAAW,QAAQ,CAAA,CAAE,OAAO,YAAY,CAAA,CAAE,OAAO,QAAQ,CAAA;AAAA,EAClE;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfinispanKeyvStore.cjs.js","sources":["../../../../../src/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\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 { EventEmitter } from 'events';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { InfinispanPutOptions } from '../../types';\n\n/**\n * Interface defining the required methods for an Infinispan client.\n * @public\n */\nexport interface InfinispanClientCacheInterface {\n get(key: string): Promise<string | null | undefined>;\n put(key: string, value: string, options?: InfinispanPutOptions): Promise<any>;\n remove(key: string): Promise<boolean>;\n clear(): Promise<void>;\n disconnect(): Promise<void>;\n on?(event: 'error' | string, listener: (...args: any[]) => void): this;\n connect?(): Promise<any>;\n query?(query: string): Promise<any[] | null>;\n containsKey?(key: string): Promise<boolean>;\n}\n\n/**\n * Options for creating an InfinispanKeyvStore instance.\n */\nexport interface InfinispanKeyvStoreOptions {\n clientPromise: Promise<InfinispanClientCacheInterface>;\n logger: LoggerService;\n defaultTtl?: number; // TTL in milliseconds\n}\n\n/**\n * A Keyv store implementation that uses Infinispan as the backend.\n * This store implements the Keyv store interface and provides caching functionality\n * using Infinispan's distributed cache capabilities.\n */\nexport class InfinispanKeyvStore extends EventEmitter {\n private readonly clientPromise: Promise<InfinispanClientCacheInterface>;\n private readonly logger: LoggerService;\n private readonly defaultTtl?: number;\n private resolvedClient: InfinispanClientCacheInterface | null = null;\n\n public readonly namespace?: string; // Keyv expects this\n\n constructor(options: InfinispanKeyvStoreOptions) {\n super();\n this.clientPromise = options.clientPromise;\n this.logger = options.logger.child({ class: InfinispanKeyvStore.name });\n this.defaultTtl = options.defaultTtl;\n\n // Eagerly try to resolve the client to attach error listeners early\n // and to have it ready for disconnect if resolved.\n this.clientPromise\n .then(client => {\n this.resolvedClient = client;\n if (typeof client.on === 'function') {\n client.on('error', (error: Error) => {\n this.logger.error('Native Infinispan client reported an error.', {\n error: error.message,\n });\n this.emit('error', error);\n });\n } else {\n this.logger.warn(\n 'Native Infinispan client does not appear to support .on(\"error\") event listening.',\n );\n }\n })\n .catch(err => {\n this.logger.error(\n 'Failed to resolve Infinispan client promise in constructor.',\n { error: err.message },\n );\n // Errors from operations will also be emitted when clientPromise is awaited and rejects.\n this.emit('error', err);\n });\n }\n\n private async getClient(): Promise<InfinispanClientCacheInterface> {\n if (this.resolvedClient) {\n return this.resolvedClient;\n }\n // If not yet resolved (e.g. called very quickly or promise rejected and retrying implicitly)\n // Await the promise. This will throw if the promise is rejected.\n this.resolvedClient = await this.clientPromise;\n return this.resolvedClient;\n }\n\n async get(key: string): Promise<string | undefined> {\n this.logger.debug(`Getting key: ${key}`);\n try {\n const client = await this.getClient();\n const value = await client.get(key);\n if (value === null || value === undefined) {\n this.logger.debug(`Key not found or value is null/undefined: ${key}`);\n return undefined;\n }\n this.logger.debug(`Successfully retrieved key: ${key}`);\n return value;\n } catch (error: any) {\n this.logger.error(`Error getting key '${key}' from Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async set(key: string, value: string, ttl?: number): Promise<void> {\n this.logger.debug(`Setting key: ${key}`, { ttl });\n this.logger.debug(`Setting key: ${key}`, { ttlInput: ttl });\n const currentTtl = ttl ?? this.defaultTtl;\n this.logger.debug(`Calculated currentTtl for key ${key}: ${currentTtl}ms`); // Log do TTL calculado\n const storeOptions: InfinispanPutOptions = {};\n\n if (typeof currentTtl === 'number' && currentTtl > 0) {\n storeOptions.lifespan = `${currentTtl}ms`; // Ensure time unit is passed as string\n // Ensure this matches client expectations. If client expects string '10s', convert here.\n // For now, assuming number in ms is fine or string like '10000ms'.\n // The PutOptions defines lifespan as string | number | null.\n } else if (typeof currentTtl === 'string') {\n storeOptions.lifespan = currentTtl;\n }\n\n try {\n const client = await this.getClient();\n await client.put(key, value, storeOptions);\n this.logger.debug(`Successfully set key: ${key}`);\n } catch (error: any) {\n this.logger.error(`Error setting key '${key}' in Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async delete(key: string): Promise<boolean> {\n this.logger.debug(`Deleting key: ${key}`);\n try {\n const client = await this.getClient();\n const deleted = await client.remove(key);\n this.logger.debug(`Key deletion status for '${key}': ${deleted}`);\n return deleted;\n } catch (error: any) {\n this.logger.error(`Error deleting key '${key}' from Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async clear(): Promise<void> {\n this.logger.info('Clearing all entries from Infinispan cache.');\n try {\n const client = await this.getClient();\n await client.clear();\n this.logger.info('Infinispan cache cleared successfully.');\n } catch (error: any) {\n this.logger.error('Error clearing Infinispan cache.', {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n // This disconnect is for the Keyv store instance, but the actual client is shared.\n // The CacheManager should handle the shared client's disconnection.\n // However, if Keyv calls this, we shouldn't error.\n async disconnect(): Promise<void> {\n this.logger.info(\n 'InfinispanKeyvStore disconnect called. Shared client managed by CacheManager.',\n );\n // No-op for this store instance as the actual client is managed externally by CacheManager.\n // The CacheManager's stop() method will disconnect the shared native client.\n return Promise.resolve();\n }\n}\n"],"names":["EventEmitter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InfinispanKeyvStore.cjs.js","sources":["../../../../../src/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\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 { EventEmitter } from 'node:events';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { InfinispanPutOptions } from '../../types';\n\n/**\n * Interface defining the required methods for an Infinispan client.\n * @public\n */\nexport interface InfinispanClientCacheInterface {\n get(key: string): Promise<string | null | undefined>;\n put(key: string, value: string, options?: InfinispanPutOptions): Promise<any>;\n remove(key: string): Promise<boolean>;\n clear(): Promise<void>;\n disconnect(): Promise<void>;\n on?(event: 'error' | string, listener: (...args: any[]) => void): this;\n connect?(): Promise<any>;\n query?(query: string): Promise<any[] | null>;\n containsKey?(key: string): Promise<boolean>;\n}\n\n/**\n * Options for creating an InfinispanKeyvStore instance.\n */\nexport interface InfinispanKeyvStoreOptions {\n clientPromise: Promise<InfinispanClientCacheInterface>;\n logger: LoggerService;\n defaultTtl?: number; // TTL in milliseconds\n}\n\n/**\n * A Keyv store implementation that uses Infinispan as the backend.\n * This store implements the Keyv store interface and provides caching functionality\n * using Infinispan's distributed cache capabilities.\n */\nexport class InfinispanKeyvStore extends EventEmitter {\n private readonly clientPromise: Promise<InfinispanClientCacheInterface>;\n private readonly logger: LoggerService;\n private readonly defaultTtl?: number;\n private resolvedClient: InfinispanClientCacheInterface | null = null;\n\n public readonly namespace?: string; // Keyv expects this\n\n constructor(options: InfinispanKeyvStoreOptions) {\n super();\n this.clientPromise = options.clientPromise;\n this.logger = options.logger.child({ class: InfinispanKeyvStore.name });\n this.defaultTtl = options.defaultTtl;\n\n // Eagerly try to resolve the client to attach error listeners early\n // and to have it ready for disconnect if resolved.\n this.clientPromise\n .then(client => {\n this.resolvedClient = client;\n if (typeof client.on === 'function') {\n client.on('error', (error: Error) => {\n this.logger.error('Native Infinispan client reported an error.', {\n error: error.message,\n });\n this.emit('error', error);\n });\n } else {\n this.logger.warn(\n 'Native Infinispan client does not appear to support .on(\"error\") event listening.',\n );\n }\n })\n .catch(err => {\n this.logger.error(\n 'Failed to resolve Infinispan client promise in constructor.',\n { error: err.message },\n );\n // Errors from operations will also be emitted when clientPromise is awaited and rejects.\n this.emit('error', err);\n });\n }\n\n private async getClient(): Promise<InfinispanClientCacheInterface> {\n if (this.resolvedClient) {\n return this.resolvedClient;\n }\n // If not yet resolved (e.g. called very quickly or promise rejected and retrying implicitly)\n // Await the promise. This will throw if the promise is rejected.\n this.resolvedClient = await this.clientPromise;\n return this.resolvedClient;\n }\n\n async get(key: string): Promise<string | undefined> {\n this.logger.debug(`Getting key: ${key}`);\n try {\n const client = await this.getClient();\n const value = await client.get(key);\n if (value === null || value === undefined) {\n this.logger.debug(`Key not found or value is null/undefined: ${key}`);\n return undefined;\n }\n this.logger.debug(`Successfully retrieved key: ${key}`);\n return value;\n } catch (error: any) {\n this.logger.error(`Error getting key '${key}' from Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async set(key: string, value: string, ttl?: number): Promise<void> {\n this.logger.debug(`Setting key: ${key}`, { ttl });\n this.logger.debug(`Setting key: ${key}`, { ttlInput: ttl });\n const currentTtl = ttl ?? this.defaultTtl;\n this.logger.debug(`Calculated currentTtl for key ${key}: ${currentTtl}ms`); // Log do TTL calculado\n const storeOptions: InfinispanPutOptions = {};\n\n if (typeof currentTtl === 'number' && currentTtl > 0) {\n storeOptions.lifespan = `${currentTtl}ms`; // Ensure time unit is passed as string\n // Ensure this matches client expectations. If client expects string '10s', convert here.\n // For now, assuming number in ms is fine or string like '10000ms'.\n // The PutOptions defines lifespan as string | number | null.\n } else if (typeof currentTtl === 'string') {\n storeOptions.lifespan = currentTtl;\n }\n\n try {\n const client = await this.getClient();\n await client.put(key, value, storeOptions);\n this.logger.debug(`Successfully set key: ${key}`);\n } catch (error: any) {\n this.logger.error(`Error setting key '${key}' in Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async delete(key: string): Promise<boolean> {\n this.logger.debug(`Deleting key: ${key}`);\n try {\n const client = await this.getClient();\n const deleted = await client.remove(key);\n this.logger.debug(`Key deletion status for '${key}': ${deleted}`);\n return deleted;\n } catch (error: any) {\n this.logger.error(`Error deleting key '${key}' from Infinispan.`, {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n async clear(): Promise<void> {\n this.logger.info('Clearing all entries from Infinispan cache.');\n try {\n const client = await this.getClient();\n await client.clear();\n this.logger.info('Infinispan cache cleared successfully.');\n } catch (error: any) {\n this.logger.error('Error clearing Infinispan cache.', {\n error: error.message,\n });\n this.emit(\n 'error',\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n }\n\n // This disconnect is for the Keyv store instance, but the actual client is shared.\n // The CacheManager should handle the shared client's disconnection.\n // However, if Keyv calls this, we shouldn't error.\n async disconnect(): Promise<void> {\n this.logger.info(\n 'InfinispanKeyvStore disconnect called. Shared client managed by CacheManager.',\n );\n // No-op for this store instance as the actual client is managed externally by CacheManager.\n // The CacheManager's stop() method will disconnect the shared native client.\n return Promise.resolve();\n }\n}\n"],"names":["EventEmitter"],"mappings":"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"}
|