@backstage/backend-defaults 0.17.1-next.2 → 0.17.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,36 @@
1
1
  # @backstage/backend-defaults
2
2
 
3
+ ## 0.17.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 90b572e: Adds an alpha `TracingService` to provide a unified interface for emitting trace spans across Backstage plugins.
8
+ - 97d3bd4: Fixed a race condition in `CachedUserInfoService` where a failed request could incorrectly evict a newer cache entry for the same token. The error handler now verifies the map entry is still the same promise before deleting it.
9
+ - 3595c97: Exported `defaultServiceFactories` to allow use with `createSpecializedBackend` for advanced configuration like `extensionPointFactoryMiddleware`.
10
+ - 89d3248: Fixed scheduler `sleep` firing immediately for durations longer than ~24.8 days, caused by Node.js `setTimeout` overflowing its 32-bit millisecond limit.
11
+ - d00a44b: Fixed Valkey cluster mode to use `iovalkey`'s `Cluster` class instead of
12
+ `createCluster` from `@keyv/redis`. The previous implementation passed a
13
+ `@redis/client` `RedisCluster` instance to `@keyv/valkey`, which expects an
14
+ `iovalkey` `Cluster` instance. This caused the cluster client to not be
15
+ recognized correctly, as the two libraries have incompatible object models.
16
+ - 2f0519c: Added a new `CachedUserInfoService` decorator that wraps `DefaultUserInfoService` with a 5-second TTL cache and in-flight request coalescing. The decorator is wired in via `userInfoServiceFactory` using a shared root-level cache. Repeated `getUserInfo()` calls for the same user token within the TTL window return the cached result without making an HTTP call to the auth backend. Note that custom `UserInfoService` implementations registered via their own factory will not benefit from this cache automatically.
17
+ - 744fa1f: Removed duplicated entries that appeared in both `dependencies` and `devDependencies`.
18
+ - e9b78e9: Removed the `uuid` dependency and replaced usage with the built-in `crypto.randomUUID()`.
19
+ - 6209065: Added `context` and `propagation` to the alpha `TracingService`. Plugins can bridge OpenTelemetry context across async boundaries via `tracing.propagation.extract(tracing.context.active(), carrier)` followed by `tracing.context.with(ctx, fn)`, and read propagated baggage via `tracing.propagation.getActiveBaggage()` or `tracing.propagation.getBaggage(ctx)`.
20
+ - Updated dependencies
21
+ - @backstage/errors@1.3.1
22
+ - @backstage/integration-aws-node@0.2.0
23
+ - @backstage/backend-plugin-api@1.9.1
24
+ - @backstage/backend-app-api@1.7.0
25
+ - @backstage/cli-node@0.3.2
26
+ - @backstage/integration@2.0.2
27
+ - @backstage/plugin-permission-node@0.11.0
28
+ - @backstage/plugin-auth-node@0.7.1
29
+ - @backstage/plugin-permission-common@0.9.9
30
+ - @backstage/config@1.3.8
31
+ - @backstage/config-loader@1.10.11
32
+ - @backstage/plugin-events-node@0.4.22
33
+
3
34
  ## 0.17.1-next.2
4
35
 
5
36
  ### Patch Changes
@@ -2,11 +2,39 @@
2
2
 
3
3
  var api = require('@opentelemetry/api');
4
4
 
5
+ function toOtelContext(ctx) {
6
+ return ctx;
7
+ }
8
+ function fromOtelContext(ctx) {
9
+ return ctx;
10
+ }
11
+ function wrapOtelBaggage(baggage) {
12
+ if (!baggage) return void 0;
13
+ return {
14
+ getAllEntries: () => baggage.getAllEntries().map(([key, entry]) => [key, { value: entry.value }])
15
+ };
16
+ }
5
17
  class DefaultTracingService {
6
18
  tracer;
7
19
  pluginId;
8
20
  captureEndUser;
9
21
  httpAuth;
22
+ context = {
23
+ active: () => fromOtelContext(api.context.active()),
24
+ // `otelContext.with` is synchronous: it activates `ctx`, invokes `fn`,
25
+ // then restores the previous active context before this call returns.
26
+ // When `fn` is async, the AsyncLocalStorage context manager installed
27
+ // by the OTel SDK is what keeps `ctx` active across the callback's
28
+ // `await`s. If no context manager is registered (e.g. in a test that
29
+ // does not wire up the OTel SDK) the `await` continuations will run
30
+ // outside `ctx`.
31
+ with: async (ctx, fn) => api.context.with(toOtelContext(ctx), fn)
32
+ };
33
+ propagation = {
34
+ extract: (ctx, carrier) => fromOtelContext(api.propagation.extract(toOtelContext(ctx), carrier)),
35
+ getBaggage: (ctx) => wrapOtelBaggage(api.propagation.getBaggage(toOtelContext(ctx))),
36
+ getActiveBaggage: () => wrapOtelBaggage(api.propagation.getActiveBaggage())
37
+ };
10
38
  constructor(opts) {
11
39
  this.tracer = api.trace.getTracerProvider().getTracer(opts.name, opts.version, { schemaUrl: opts.schemaUrl });
12
40
  this.pluginId = opts.pluginId;
@@ -16,7 +44,8 @@ class DefaultTracingService {
16
44
  static create(opts) {
17
45
  return new DefaultTracingService(opts);
18
46
  }
19
- async startActiveSpan(name, fn, options = {}) {
47
+ async startActiveSpan(name, optionsOrFn, maybeFn) {
48
+ const [options, fn] = typeof optionsOrFn === "function" ? [{}, optionsOrFn] : [optionsOrFn, maybeFn];
20
49
  let credentials = options.credentials;
21
50
  if (!credentials && options.request) {
22
51
  credentials = await this.httpAuth.credentials(options.request);
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultTracingService.cjs.js","sources":["../../../../src/alpha/entrypoints/tracing/DefaultTracingService.ts"],"sourcesContent":["/*\n * Copyright 2026 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 { SpanKind, SpanStatusCode, Tracer, trace } from '@opentelemetry/api';\nimport {\n BackstageCredentials,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport {\n TracingService,\n TracingServiceAttributes,\n TracingServiceSpan,\n TracingServiceSpanKind,\n TracingServiceSpanOptions,\n TracingServiceSpanStatus,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * Options for creating a {@link DefaultTracingService}.\n *\n * @alpha\n */\nexport interface DefaultTracingServiceOptions {\n name: string;\n version?: string;\n schemaUrl?: string;\n pluginId: string;\n captureEndUser: boolean;\n httpAuth: HttpAuthService;\n}\n\n/**\n * Default implementation of the {@link TracingService} interface.\n *\n * @alpha\n */\nexport class DefaultTracingService implements TracingService {\n private readonly tracer: Tracer;\n private readonly pluginId: string;\n private readonly captureEndUser: boolean;\n private readonly httpAuth: HttpAuthService;\n\n private constructor(opts: DefaultTracingServiceOptions) {\n this.tracer = trace\n .getTracerProvider()\n .getTracer(opts.name, opts.version, { schemaUrl: opts.schemaUrl });\n this.pluginId = opts.pluginId;\n this.captureEndUser = opts.captureEndUser;\n this.httpAuth = opts.httpAuth;\n }\n\n static create(opts: DefaultTracingServiceOptions): TracingService {\n return new DefaultTracingService(opts);\n }\n\n async startActiveSpan<T>(\n name: string,\n fn: (span: TracingServiceSpan) => T | Promise<T>,\n options: TracingServiceSpanOptions = {},\n ): Promise<T> {\n let credentials = options.credentials;\n if (!credentials && options.request) {\n credentials = await this.httpAuth.credentials(options.request);\n }\n\n const principalAttributes = this.getPrincipalAttributes(credentials);\n const attributes: TracingServiceAttributes = {\n 'backstage.plugin.id': this.pluginId,\n ...options.attributes,\n ...principalAttributes,\n };\n\n return this.tracer.startActiveSpan(\n name,\n { kind: toSpanKind(options.kind), attributes },\n async span => {\n try {\n const wrapped: TracingServiceSpan = {\n setAttribute(key, value) {\n span.setAttribute(key, value);\n },\n setStatus(status) {\n span.setStatus({\n code: toSpanStatusCode(status.code),\n message: status.message,\n });\n },\n };\n const result = await fn(wrapped);\n span.end();\n return result;\n } catch (err) {\n const error = err as Error;\n span.recordException(error);\n span.setAttribute('error.type', error.name || 'Error');\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message || String(error),\n });\n span.end();\n throw err;\n }\n },\n );\n }\n\n private getPrincipalAttributes(\n credentials: BackstageCredentials | undefined,\n ): TracingServiceAttributes {\n if (!credentials) return {};\n const principal = credentials.principal as\n | { type?: string; userEntityRef?: string; subject?: string }\n | undefined;\n if (!principal?.type) return {};\n const attrs: TracingServiceAttributes = {\n 'backstage.principal.type': principal.type,\n };\n if (!this.captureEndUser) return attrs;\n if (principal.type === 'user' && principal.userEntityRef) {\n attrs['enduser.id'] = principal.userEntityRef;\n } else if (principal.type === 'service' && principal.subject) {\n attrs['enduser.id'] = principal.subject;\n }\n return attrs;\n }\n}\n\nfunction toSpanKind(\n kind: TracingServiceSpanKind | undefined,\n): SpanKind | undefined {\n switch (kind) {\n case 'internal':\n return SpanKind.INTERNAL;\n case 'server':\n return SpanKind.SERVER;\n case 'client':\n return SpanKind.CLIENT;\n case 'producer':\n return SpanKind.PRODUCER;\n case 'consumer':\n return SpanKind.CONSUMER;\n default:\n return undefined;\n }\n}\n\nfunction toSpanStatusCode(\n code: TracingServiceSpanStatus['code'],\n): SpanStatusCode {\n switch (code) {\n case 'ok':\n return SpanStatusCode.OK;\n case 'error':\n return SpanStatusCode.ERROR;\n default:\n return SpanStatusCode.UNSET;\n }\n}\n"],"names":["trace","SpanStatusCode","SpanKind"],"mappings":"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"}
1
+ {"version":3,"file":"DefaultTracingService.cjs.js","sources":["../../../../src/alpha/entrypoints/tracing/DefaultTracingService.ts"],"sourcesContent":["/*\n * Copyright 2026 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 Context,\n SpanKind,\n SpanStatusCode,\n Tracer,\n context as otelContext,\n propagation as otelPropagation,\n trace,\n} from '@opentelemetry/api';\nimport {\n BackstageCredentials,\n HttpAuthService,\n} from '@backstage/backend-plugin-api';\nimport {\n TracingService,\n TracingServiceAttributes,\n TracingServiceBaggage,\n TracingServiceContext,\n TracingServiceContextAPI,\n TracingServicePropagationAPI,\n TracingServiceSpan,\n TracingServiceSpanKind,\n TracingServiceSpanOptions,\n TracingServiceSpanStatus,\n} from '@backstage/backend-plugin-api/alpha';\n\n/**\n * Options for creating a {@link DefaultTracingService}.\n *\n * @alpha\n */\nexport interface DefaultTracingServiceOptions {\n name: string;\n version?: string;\n schemaUrl?: string;\n pluginId: string;\n captureEndUser: boolean;\n httpAuth: HttpAuthService;\n}\n\n// `TracingServiceContext` is an opaque handle for an OTel `Context`. Internally\n// the value *is* the OTel context; we just narrow the type so consumers can't\n// poke at it directly.\nfunction toOtelContext(ctx: TracingServiceContext): Context {\n return ctx as unknown as Context;\n}\nfunction fromOtelContext(ctx: Context): TracingServiceContext {\n return ctx as unknown as TracingServiceContext;\n}\n\nfunction wrapOtelBaggage(\n baggage: ReturnType<typeof otelPropagation.getActiveBaggage>,\n): TracingServiceBaggage | undefined {\n if (!baggage) return undefined;\n return {\n getAllEntries: () =>\n baggage\n .getAllEntries()\n .map(([key, entry]) => [key, { value: entry.value }]),\n };\n}\n\n/**\n * Default implementation of the {@link TracingService} interface.\n *\n * @alpha\n */\nexport class DefaultTracingService implements TracingService {\n private readonly tracer: Tracer;\n private readonly pluginId: string;\n private readonly captureEndUser: boolean;\n private readonly httpAuth: HttpAuthService;\n\n readonly context: TracingServiceContextAPI = {\n active: () => fromOtelContext(otelContext.active()),\n // `otelContext.with` is synchronous: it activates `ctx`, invokes `fn`,\n // then restores the previous active context before this call returns.\n // When `fn` is async, the AsyncLocalStorage context manager installed\n // by the OTel SDK is what keeps `ctx` active across the callback's\n // `await`s. If no context manager is registered (e.g. in a test that\n // does not wire up the OTel SDK) the `await` continuations will run\n // outside `ctx`.\n with: async <T>(\n ctx: TracingServiceContext,\n fn: () => T | Promise<T>,\n ): Promise<T> => otelContext.with(toOtelContext(ctx), fn),\n };\n\n readonly propagation: TracingServicePropagationAPI = {\n extract: (\n ctx: TracingServiceContext,\n carrier: Record<string, string | string[] | undefined>,\n ): TracingServiceContext =>\n fromOtelContext(otelPropagation.extract(toOtelContext(ctx), carrier)),\n getBaggage: (ctx: TracingServiceContext) =>\n wrapOtelBaggage(otelPropagation.getBaggage(toOtelContext(ctx))),\n getActiveBaggage: () => wrapOtelBaggage(otelPropagation.getActiveBaggage()),\n };\n\n private constructor(opts: DefaultTracingServiceOptions) {\n this.tracer = trace\n .getTracerProvider()\n .getTracer(opts.name, opts.version, { schemaUrl: opts.schemaUrl });\n this.pluginId = opts.pluginId;\n this.captureEndUser = opts.captureEndUser;\n this.httpAuth = opts.httpAuth;\n }\n\n static create(opts: DefaultTracingServiceOptions): TracingService {\n return new DefaultTracingService(opts);\n }\n\n startActiveSpan<T>(\n name: string,\n fn: (span: TracingServiceSpan) => T | Promise<T>,\n ): Promise<T>;\n startActiveSpan<T>(\n name: string,\n options: TracingServiceSpanOptions,\n fn: (span: TracingServiceSpan) => T | Promise<T>,\n ): Promise<T>;\n async startActiveSpan<T>(\n name: string,\n optionsOrFn:\n | TracingServiceSpanOptions\n | ((span: TracingServiceSpan) => T | Promise<T>),\n maybeFn?: (span: TracingServiceSpan) => T | Promise<T>,\n ): Promise<T> {\n const [options, fn]: [\n TracingServiceSpanOptions,\n (span: TracingServiceSpan) => T | Promise<T>,\n ] =\n typeof optionsOrFn === 'function'\n ? [{}, optionsOrFn]\n : [optionsOrFn, maybeFn!];\n\n let credentials = options.credentials;\n if (!credentials && options.request) {\n credentials = await this.httpAuth.credentials(options.request);\n }\n\n const principalAttributes = this.getPrincipalAttributes(credentials);\n const attributes: TracingServiceAttributes = {\n 'backstage.plugin.id': this.pluginId,\n ...options.attributes,\n ...principalAttributes,\n };\n\n return this.tracer.startActiveSpan(\n name,\n { kind: toSpanKind(options.kind), attributes },\n async span => {\n try {\n const wrapped: TracingServiceSpan = {\n setAttribute(key, value) {\n span.setAttribute(key, value);\n },\n setStatus(status) {\n span.setStatus({\n code: toSpanStatusCode(status.code),\n message: status.message,\n });\n },\n };\n const result = await fn(wrapped);\n span.end();\n return result;\n } catch (err) {\n const error = err as Error;\n span.recordException(error);\n span.setAttribute('error.type', error.name || 'Error');\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message || String(error),\n });\n span.end();\n throw err;\n }\n },\n );\n }\n\n private getPrincipalAttributes(\n credentials: BackstageCredentials | undefined,\n ): TracingServiceAttributes {\n if (!credentials) return {};\n const principal = credentials.principal as\n | { type?: string; userEntityRef?: string; subject?: string }\n | undefined;\n if (!principal?.type) return {};\n const attrs: TracingServiceAttributes = {\n 'backstage.principal.type': principal.type,\n };\n if (!this.captureEndUser) return attrs;\n if (principal.type === 'user' && principal.userEntityRef) {\n attrs['enduser.id'] = principal.userEntityRef;\n } else if (principal.type === 'service' && principal.subject) {\n attrs['enduser.id'] = principal.subject;\n }\n return attrs;\n }\n}\n\nfunction toSpanKind(\n kind: TracingServiceSpanKind | undefined,\n): SpanKind | undefined {\n switch (kind) {\n case 'internal':\n return SpanKind.INTERNAL;\n case 'server':\n return SpanKind.SERVER;\n case 'client':\n return SpanKind.CLIENT;\n case 'producer':\n return SpanKind.PRODUCER;\n case 'consumer':\n return SpanKind.CONSUMER;\n default:\n return undefined;\n }\n}\n\nfunction toSpanStatusCode(\n code: TracingServiceSpanStatus['code'],\n): SpanStatusCode {\n switch (code) {\n case 'ok':\n return SpanStatusCode.OK;\n case 'error':\n return SpanStatusCode.ERROR;\n default:\n return SpanStatusCode.UNSET;\n }\n}\n"],"names":["otelContext","otelPropagation","trace","SpanStatusCode","SpanKind"],"mappings":"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"}
@@ -160,14 +160,14 @@ class CacheManager {
160
160
  }
161
161
  valkeyOptions.cluster = {
162
162
  rootNodes: clusterConfig.get("rootNodes"),
163
- defaults: clusterConfig.getOptional("defaults"),
164
- minimizeConnections: clusterConfig.getOptionalBoolean(
165
- "minimizeConnections"
166
- ),
167
- useReplicas: clusterConfig.getOptionalBoolean("useReplicas"),
168
- maxCommandRedirections: clusterConfig.getOptionalNumber(
169
- "maxCommandRedirections"
170
- )
163
+ options: {
164
+ redisOptions: clusterConfig.getOptional("defaults"),
165
+ scaleReads: clusterConfig.getOptionalBoolean("useReplicas") ? "slave" : void 0,
166
+ maxRedirections: clusterConfig.getOptionalNumber(
167
+ "maxCommandRedirections"
168
+ ),
169
+ lazyConnect: clusterConfig.getOptionalBoolean("minimizeConnections")
170
+ }
171
171
  };
172
172
  }
173
173
  return valkeyOptions;
@@ -260,7 +260,7 @@ class CacheManager {
260
260
  }
261
261
  createValkeyStoreFactory() {
262
262
  const KeyvValkey = require("@keyv/valkey").default;
263
- const { createCluster } = require("@keyv/redis");
263
+ const { Cluster } = require("iovalkey");
264
264
  const stores = {};
265
265
  return (pluginId, defaultTtl) => {
266
266
  if (this.storeOptions?.type !== "valkey") {
@@ -271,7 +271,10 @@ class CacheManager {
271
271
  if (!stores[pluginId]) {
272
272
  const valkeyOptions = this.storeOptions?.client;
273
273
  if (this.storeOptions?.cluster) {
274
- const cluster = createCluster(this.storeOptions?.cluster);
274
+ const cluster = new Cluster(
275
+ this.storeOptions.cluster.rootNodes,
276
+ this.storeOptions.cluster.options
277
+ );
275
278
  stores[pluginId] = new KeyvValkey(cluster, valkeyOptions);
276
279
  } else {
277
280
  stores[pluginId] = new KeyvValkey(this.connection, valkeyOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"CacheManager.cjs.js","sources":["../../../src/entrypoints/cache/CacheManager.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 LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport Keyv from 'keyv';\nimport { DefaultCacheClient } from './CacheClient';\nimport {\n CacheManagerOptions,\n ttlToMilliseconds,\n CacheStoreOptions,\n RedisCacheStoreOptions,\n InfinispanClientBehaviorOptions,\n InfinispanServerConfig,\n ValkeyCacheStoreOptions,\n} from './types';\nimport { InfinispanOptionsMapper } from './providers/infinispan/InfinispanOptionsMapper';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { ConfigReader, readDurationFromConfig } from '@backstage/config';\nimport {\n InfinispanClientCacheInterface,\n InfinispanKeyvStore,\n} from './providers/infinispan/InfinispanKeyvStore';\n\ntype StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv;\n\n/**\n * Implements a Cache Manager which will automatically create new cache clients\n * for plugins when requested. All requested cache clients are created with the\n * connection details provided.\n *\n * @public\n */\nexport class CacheManager {\n /**\n * Keys represent supported `backend.cache.store` values, mapped to factories\n * that return Keyv instances appropriate to the store.\n */\n private readonly storeFactories = {\n redis: this.createRedisStoreFactory(),\n valkey: this.createValkeyStoreFactory(),\n memcache: this.createMemcacheStoreFactory(),\n memory: this.createMemoryStoreFactory(),\n infinispan: this.createInfinispanStoreFactory(),\n };\n\n private readonly logger?: LoggerService;\n private readonly store: keyof CacheManager['storeFactories'];\n private readonly connection: string;\n private readonly errorHandler: CacheManagerOptions['onError'];\n private readonly defaultTtl?: number;\n private readonly storeOptions?: CacheStoreOptions;\n\n /**\n * Creates a new {@link CacheManager} instance by reading from the `backend`\n * config section, specifically the `.cache` key.\n *\n * @param config - The loaded application configuration.\n * @param options - Optional configuration for the CacheManager.\n * @returns A new CacheManager instance.\n */\n static fromConfig(\n config: RootConfigService,\n options: CacheManagerOptions = {},\n ): CacheManager {\n // If no `backend.cache` config is provided, instantiate the CacheManager\n // with an in-memory cache client.\n const store = config.getOptionalString('backend.cache.store') || 'memory';\n const defaultTtlConfig = config.getOptional('backend.cache.defaultTtl');\n const connectionString =\n config.getOptionalString('backend.cache.connection') || '';\n const logger = options.logger?.child({\n type: 'cacheManager',\n });\n\n if (config.has('backend.cache.useRedisSets')) {\n logger?.warn(\n \"The 'backend.cache.useRedisSets' configuration key is deprecated and no longer has any effect. The underlying '@keyv/redis' and '@keyv/valkey' libraries no longer support redis sets.\",\n );\n }\n\n let defaultTtl: number | undefined;\n if (defaultTtlConfig !== undefined) {\n if (typeof defaultTtlConfig === 'number') {\n defaultTtl = defaultTtlConfig;\n } else {\n defaultTtl = durationToMilliseconds(\n readDurationFromConfig(config, { key: 'backend.cache.defaultTtl' }),\n );\n }\n }\n\n // Read store-specific options from config\n const storeOptions = CacheManager.parseStoreOptions(store, config, logger);\n\n return new CacheManager(\n store,\n connectionString,\n options.onError,\n logger,\n defaultTtl,\n storeOptions,\n );\n }\n\n /**\n * Parse store-specific options from configuration.\n *\n * @param store - The cache store type ('redis', 'valkey', 'memcache', 'infinispan', or 'memory')\n * @param config - The configuration service\n * @param logger - Optional logger for warnings\n * @returns The parsed store options\n */\n private static parseStoreOptions(\n store: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): CacheStoreOptions | undefined {\n const storeConfigPath = `backend.cache.${store}`;\n\n if (store !== 'memory' && !config.has(storeConfigPath)) {\n logger?.warn(\n `No configuration found for cache store '${store}' at '${storeConfigPath}'.`,\n );\n }\n\n switch (store) {\n case 'redis':\n return CacheManager.parseRedisOptions(storeConfigPath, config, logger);\n case 'valkey':\n return CacheManager.parseValkeyOptions(storeConfigPath, config, logger);\n case 'infinispan':\n return InfinispanOptionsMapper.parseInfinispanOptions(\n storeConfigPath,\n config,\n logger,\n );\n default:\n return undefined;\n }\n }\n\n /**\n * Parse Redis-specific options from configuration.\n */\n private static parseRedisOptions(\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): RedisCacheStoreOptions {\n const redisOptions: RedisCacheStoreOptions = {\n type: 'redis',\n };\n\n const redisConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n redisOptions.client = {\n namespace: redisConfig.getOptionalString('client.namespace'),\n keyPrefixSeparator:\n redisConfig.getOptionalString('client.keyPrefixSeparator') || ':',\n clearBatchSize: redisConfig.getOptionalNumber('client.clearBatchSize'),\n useUnlink: redisConfig.getOptionalBoolean('client.useUnlink'),\n noNamespaceAffectsAll: redisConfig.getOptionalBoolean(\n 'client.noNamespaceAffectsAll',\n ),\n };\n\n if (redisConfig.has('cluster')) {\n const clusterConfig = redisConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Redis cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return redisOptions;\n }\n\n redisOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n defaults: clusterConfig.getOptional('defaults'),\n minimizeConnections: clusterConfig.getOptionalBoolean(\n 'minimizeConnections',\n ),\n useReplicas: clusterConfig.getOptionalBoolean('useReplicas'),\n maxCommandRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n };\n }\n\n return redisOptions;\n }\n\n /**\n * Parse Valkey-specific options from configuration.\n */\n private static parseValkeyOptions(\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): ValkeyCacheStoreOptions {\n const valkeyOptions: ValkeyCacheStoreOptions = {\n type: 'valkey',\n };\n\n const valkeyConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n valkeyOptions.client = {\n keyPrefix: valkeyConfig.getOptionalString('client.keyPrefix'),\n };\n\n if (valkeyConfig.has('cluster')) {\n const clusterConfig = valkeyConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Valkey cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return valkeyOptions;\n }\n\n valkeyOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n defaults: clusterConfig.getOptional('defaults'),\n minimizeConnections: clusterConfig.getOptionalBoolean(\n 'minimizeConnections',\n ),\n useReplicas: clusterConfig.getOptionalBoolean('useReplicas'),\n maxCommandRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n };\n }\n\n return valkeyOptions;\n }\n\n /**\n * Construct the full namespace based on the options and pluginId.\n *\n * @param pluginId - The plugin ID to namespace\n * @param storeOptions - Optional cache store configuration options\n * @returns The constructed namespace string combining the configured namespace with pluginId\n */\n private static constructNamespace(\n pluginId: string,\n storeOptions: RedisCacheStoreOptions | ValkeyCacheStoreOptions | undefined,\n ): string {\n let prefix: string;\n switch (storeOptions?.type) {\n case 'redis':\n prefix = storeOptions?.client?.namespace\n ? `${storeOptions.client.namespace}${\n storeOptions.client.keyPrefixSeparator ?? ':'\n }`\n : '';\n break;\n case 'valkey':\n prefix = storeOptions.client?.keyPrefix ?? '';\n break;\n default:\n prefix = '';\n }\n\n return `${prefix}${pluginId}`;\n }\n\n /** @internal */\n constructor(\n store: string,\n connectionString: string,\n errorHandler: CacheManagerOptions['onError'],\n logger?: LoggerService,\n defaultTtl?: number,\n storeOptions?: CacheStoreOptions,\n ) {\n if (!this.storeFactories.hasOwnProperty(store)) {\n throw new Error(`Unknown cache store: ${store}`);\n }\n this.logger = logger;\n this.store = store as keyof CacheManager['storeFactories'];\n this.connection = connectionString;\n this.errorHandler = errorHandler;\n this.defaultTtl = defaultTtl;\n this.storeOptions = storeOptions;\n }\n\n /**\n * Generates a PluginCacheManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the cache manager should be created for.\n * Plugin names should be unique.\n */\n forPlugin(pluginId: string): CacheService {\n const clientFactory = (options: CacheServiceOptions) => {\n const ttl = options.defaultTtl ?? this.defaultTtl;\n return this.getClientWithTtl(\n pluginId,\n ttl !== undefined ? ttlToMilliseconds(ttl) : undefined,\n );\n };\n\n return new DefaultCacheClient(clientFactory({}), clientFactory, {});\n }\n\n private getClientWithTtl(pluginId: string, ttl: number | undefined): Keyv {\n return this.storeFactories[this.store](pluginId, ttl);\n }\n\n private createRedisStoreFactory(): StoreFactory {\n const KeyvRedis = require('@keyv/redis').default;\n const { createCluster } = require('@keyv/redis');\n const stores: Record<string, typeof KeyvRedis> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'redis') {\n throw new Error(\n `Internal error: Wrong config type passed to redis factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const redisOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Redis cluster\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvRedis(cluster, redisOptions);\n } else {\n // Create a regular Redis connection\n stores[pluginId] = new KeyvRedis(this.connection, redisOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create redis cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createValkeyStoreFactory(): StoreFactory {\n const KeyvValkey = require('@keyv/valkey').default;\n // `@keyv/valkey` doesn't export a `createCluster` function, but is compatible with the one from `@keyv/redis`\n // See https://keyv.org/docs/storage-adapters/valkey\n const { createCluster } = require('@keyv/redis');\n const stores: Record<string, typeof KeyvValkey> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'valkey') {\n throw new Error(\n `Internal error: Wrong config type passed to valkey factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const valkeyOptions = this.storeOptions?.client;\n if (this.storeOptions?.cluster) {\n // Create a Valkey cluster (Redis cluster under the hood)\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvValkey(cluster, valkeyOptions);\n } else {\n // Create a regular Valkey connection\n stores[pluginId] = new KeyvValkey(this.connection, valkeyOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create valkey cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createMemcacheStoreFactory(): StoreFactory {\n const KeyvMemcache = require('@keyv/memcache').default;\n const stores: Record<string, typeof KeyvMemcache> = {};\n\n return (pluginId, defaultTtl) => {\n if (!stores[pluginId]) {\n stores[pluginId] = new KeyvMemcache(this.connection);\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create memcache cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store: stores[pluginId],\n });\n };\n }\n\n private createMemoryStoreFactory(): StoreFactory {\n const store = new Map();\n return (pluginId, defaultTtl) =>\n new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store,\n });\n }\n\n private createInfinispanStoreFactory(): StoreFactory {\n const stores: Record<string, InfinispanKeyvStore> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'infinispan') {\n throw new Error(\n `Internal error: Wrong config type passed to infinispan factory: ${this.storeOptions?.type}`,\n );\n }\n\n if (!stores[pluginId]) {\n // Use sync version for testing environments\n const isTest =\n process.env.NODE_ENV === 'test' || typeof jest !== 'undefined';\n\n // Create the client promise ONCE and reuse it\n const clientPromise: Promise<InfinispanClientCacheInterface> = isTest\n ? this.createInfinispanClientSync()\n : this.createInfinispanClientAsync();\n\n this.logger?.info(\n `Creating Infinispan cache client for plugin ${pluginId} isTest = ${isTest}`,\n );\n const storeInstance = new InfinispanKeyvStore({\n clientPromise,\n logger: this.logger!,\n });\n\n stores[pluginId] = storeInstance;\n\n // Always provide an error handler to avoid stopping the process\n storeInstance.on('error', (err: Error) => {\n this.logger?.error('Failed to create infinispan cache client', err);\n this.errorHandler?.(err);\n });\n }\n\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n });\n };\n }\n\n /**\n * Creates an Infinispan client using dynamic import (production use).\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClientAsync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(false);\n }\n\n /**\n * Creates an Infinispan client using synchronous import (testing purposes).\n * @returns Promise that resolves to an Infinispan client\n */\n private createInfinispanClientSync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(true);\n }\n\n /**\n * Creates an Infinispan client based on the provided configuration.\n * @param useSync - Whether to use synchronous import (for testing) or dynamic import\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClient(\n useSync: boolean = false,\n ): Promise<InfinispanClientCacheInterface> {\n try {\n this.logger?.info('Creating Infinispan client');\n\n if (this.storeOptions?.type === 'infinispan') {\n // Import infinispan based on the useSync parameter\n const infinispan = useSync\n ? require('infinispan')\n : await import('infinispan');\n\n const client = await infinispan.client(\n this.storeOptions.servers as InfinispanServerConfig[],\n this.storeOptions.options as InfinispanClientBehaviorOptions,\n );\n\n this.logger?.info('Infinispan client created successfully');\n return client;\n }\n throw new Error('Infinispan store options are not defined');\n } catch (error: any) {\n this.logger?.error('Failed to create Infinispan client', {\n error: error.message,\n });\n throw error;\n }\n }\n}\n"],"names":["config","durationToMilliseconds","readDurationFromConfig","InfinispanOptionsMapper","ConfigReader","ttlToMilliseconds","DefaultCacheClient","Keyv","InfinispanKeyvStore"],"mappings":"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"}
1
+ {"version":3,"file":"CacheManager.cjs.js","sources":["../../../src/entrypoints/cache/CacheManager.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 LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport Keyv from 'keyv';\nimport { DefaultCacheClient } from './CacheClient';\nimport {\n CacheManagerOptions,\n ttlToMilliseconds,\n CacheStoreOptions,\n RedisCacheStoreOptions,\n InfinispanClientBehaviorOptions,\n InfinispanServerConfig,\n ValkeyCacheStoreOptions,\n} from './types';\nimport { InfinispanOptionsMapper } from './providers/infinispan/InfinispanOptionsMapper';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { ConfigReader, readDurationFromConfig } from '@backstage/config';\nimport {\n InfinispanClientCacheInterface,\n InfinispanKeyvStore,\n} from './providers/infinispan/InfinispanKeyvStore';\n\ntype StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv;\n\n/**\n * Implements a Cache Manager which will automatically create new cache clients\n * for plugins when requested. All requested cache clients are created with the\n * connection details provided.\n *\n * @public\n */\nexport class CacheManager {\n /**\n * Keys represent supported `backend.cache.store` values, mapped to factories\n * that return Keyv instances appropriate to the store.\n */\n private readonly storeFactories = {\n redis: this.createRedisStoreFactory(),\n valkey: this.createValkeyStoreFactory(),\n memcache: this.createMemcacheStoreFactory(),\n memory: this.createMemoryStoreFactory(),\n infinispan: this.createInfinispanStoreFactory(),\n };\n\n private readonly logger?: LoggerService;\n private readonly store: keyof CacheManager['storeFactories'];\n private readonly connection: string;\n private readonly errorHandler: CacheManagerOptions['onError'];\n private readonly defaultTtl?: number;\n private readonly storeOptions?: CacheStoreOptions;\n\n /**\n * Creates a new {@link CacheManager} instance by reading from the `backend`\n * config section, specifically the `.cache` key.\n *\n * @param config - The loaded application configuration.\n * @param options - Optional configuration for the CacheManager.\n * @returns A new CacheManager instance.\n */\n static fromConfig(\n config: RootConfigService,\n options: CacheManagerOptions = {},\n ): CacheManager {\n // If no `backend.cache` config is provided, instantiate the CacheManager\n // with an in-memory cache client.\n const store = config.getOptionalString('backend.cache.store') || 'memory';\n const defaultTtlConfig = config.getOptional('backend.cache.defaultTtl');\n const connectionString =\n config.getOptionalString('backend.cache.connection') || '';\n const logger = options.logger?.child({\n type: 'cacheManager',\n });\n\n if (config.has('backend.cache.useRedisSets')) {\n logger?.warn(\n \"The 'backend.cache.useRedisSets' configuration key is deprecated and no longer has any effect. The underlying '@keyv/redis' and '@keyv/valkey' libraries no longer support redis sets.\",\n );\n }\n\n let defaultTtl: number | undefined;\n if (defaultTtlConfig !== undefined) {\n if (typeof defaultTtlConfig === 'number') {\n defaultTtl = defaultTtlConfig;\n } else {\n defaultTtl = durationToMilliseconds(\n readDurationFromConfig(config, { key: 'backend.cache.defaultTtl' }),\n );\n }\n }\n\n // Read store-specific options from config\n const storeOptions = CacheManager.parseStoreOptions(store, config, logger);\n\n return new CacheManager(\n store,\n connectionString,\n options.onError,\n logger,\n defaultTtl,\n storeOptions,\n );\n }\n\n /**\n * Parse store-specific options from configuration.\n *\n * @param store - The cache store type ('redis', 'valkey', 'memcache', 'infinispan', or 'memory')\n * @param config - The configuration service\n * @param logger - Optional logger for warnings\n * @returns The parsed store options\n */\n private static parseStoreOptions(\n store: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): CacheStoreOptions | undefined {\n const storeConfigPath = `backend.cache.${store}`;\n\n if (store !== 'memory' && !config.has(storeConfigPath)) {\n logger?.warn(\n `No configuration found for cache store '${store}' at '${storeConfigPath}'.`,\n );\n }\n\n switch (store) {\n case 'redis':\n return CacheManager.parseRedisOptions(storeConfigPath, config, logger);\n case 'valkey':\n return CacheManager.parseValkeyOptions(storeConfigPath, config, logger);\n case 'infinispan':\n return InfinispanOptionsMapper.parseInfinispanOptions(\n storeConfigPath,\n config,\n logger,\n );\n default:\n return undefined;\n }\n }\n\n /**\n * Parse Redis-specific options from configuration.\n */\n private static parseRedisOptions(\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): RedisCacheStoreOptions {\n const redisOptions: RedisCacheStoreOptions = {\n type: 'redis',\n };\n\n const redisConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n redisOptions.client = {\n namespace: redisConfig.getOptionalString('client.namespace'),\n keyPrefixSeparator:\n redisConfig.getOptionalString('client.keyPrefixSeparator') || ':',\n clearBatchSize: redisConfig.getOptionalNumber('client.clearBatchSize'),\n useUnlink: redisConfig.getOptionalBoolean('client.useUnlink'),\n noNamespaceAffectsAll: redisConfig.getOptionalBoolean(\n 'client.noNamespaceAffectsAll',\n ),\n };\n\n if (redisConfig.has('cluster')) {\n const clusterConfig = redisConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Redis cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return redisOptions;\n }\n\n redisOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n defaults: clusterConfig.getOptional('defaults'),\n minimizeConnections: clusterConfig.getOptionalBoolean(\n 'minimizeConnections',\n ),\n useReplicas: clusterConfig.getOptionalBoolean('useReplicas'),\n maxCommandRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n };\n }\n\n return redisOptions;\n }\n\n /**\n * Parse Valkey-specific options from configuration.\n */\n private static parseValkeyOptions(\n storeConfigPath: string,\n config: RootConfigService,\n logger?: LoggerService,\n ): ValkeyCacheStoreOptions {\n const valkeyOptions: ValkeyCacheStoreOptions = {\n type: 'valkey',\n };\n\n const valkeyConfig =\n config.getOptionalConfig(storeConfigPath) ?? new ConfigReader({});\n\n valkeyOptions.client = {\n keyPrefix: valkeyConfig.getOptionalString('client.keyPrefix'),\n };\n\n if (valkeyConfig.has('cluster')) {\n const clusterConfig = valkeyConfig.getConfig('cluster');\n\n if (!clusterConfig.has('rootNodes')) {\n logger?.warn(\n `Valkey cluster config has no 'rootNodes' key, defaulting to non-clustered mode`,\n );\n return valkeyOptions;\n }\n\n valkeyOptions.cluster = {\n rootNodes: clusterConfig.get('rootNodes'),\n options: {\n redisOptions: clusterConfig.getOptional('defaults'),\n scaleReads: clusterConfig.getOptionalBoolean('useReplicas')\n ? 'slave'\n : undefined,\n maxRedirections: clusterConfig.getOptionalNumber(\n 'maxCommandRedirections',\n ),\n lazyConnect: clusterConfig.getOptionalBoolean('minimizeConnections'),\n },\n };\n }\n\n return valkeyOptions;\n }\n\n /**\n * Construct the full namespace based on the options and pluginId.\n *\n * @param pluginId - The plugin ID to namespace\n * @param storeOptions - Optional cache store configuration options\n * @returns The constructed namespace string combining the configured namespace with pluginId\n */\n private static constructNamespace(\n pluginId: string,\n storeOptions: RedisCacheStoreOptions | ValkeyCacheStoreOptions | undefined,\n ): string {\n let prefix: string;\n switch (storeOptions?.type) {\n case 'redis':\n prefix = storeOptions?.client?.namespace\n ? `${storeOptions.client.namespace}${\n storeOptions.client.keyPrefixSeparator ?? ':'\n }`\n : '';\n break;\n case 'valkey':\n prefix = storeOptions.client?.keyPrefix ?? '';\n break;\n default:\n prefix = '';\n }\n\n return `${prefix}${pluginId}`;\n }\n\n /** @internal */\n constructor(\n store: string,\n connectionString: string,\n errorHandler: CacheManagerOptions['onError'],\n logger?: LoggerService,\n defaultTtl?: number,\n storeOptions?: CacheStoreOptions,\n ) {\n if (!this.storeFactories.hasOwnProperty(store)) {\n throw new Error(`Unknown cache store: ${store}`);\n }\n this.logger = logger;\n this.store = store as keyof CacheManager['storeFactories'];\n this.connection = connectionString;\n this.errorHandler = errorHandler;\n this.defaultTtl = defaultTtl;\n this.storeOptions = storeOptions;\n }\n\n /**\n * Generates a PluginCacheManager for consumption by plugins.\n *\n * @param pluginId - The plugin that the cache manager should be created for.\n * Plugin names should be unique.\n */\n forPlugin(pluginId: string): CacheService {\n const clientFactory = (options: CacheServiceOptions) => {\n const ttl = options.defaultTtl ?? this.defaultTtl;\n return this.getClientWithTtl(\n pluginId,\n ttl !== undefined ? ttlToMilliseconds(ttl) : undefined,\n );\n };\n\n return new DefaultCacheClient(clientFactory({}), clientFactory, {});\n }\n\n private getClientWithTtl(pluginId: string, ttl: number | undefined): Keyv {\n return this.storeFactories[this.store](pluginId, ttl);\n }\n\n private createRedisStoreFactory(): StoreFactory {\n const KeyvRedis = require('@keyv/redis').default;\n const { createCluster } = require('@keyv/redis');\n const stores: Record<string, typeof KeyvRedis> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'redis') {\n throw new Error(\n `Internal error: Wrong config type passed to redis factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const redisOptions = this.storeOptions?.client || {\n keyPrefixSeparator: ':',\n };\n if (this.storeOptions?.cluster) {\n // Create a Redis cluster\n const cluster = createCluster(this.storeOptions?.cluster);\n stores[pluginId] = new KeyvRedis(cluster, redisOptions);\n } else {\n // Create a regular Redis connection\n stores[pluginId] = new KeyvRedis(this.connection, redisOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create redis cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createValkeyStoreFactory(): StoreFactory {\n const KeyvValkey = require('@keyv/valkey').default;\n const { Cluster } = require('iovalkey');\n const stores: Record<string, typeof KeyvValkey> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'valkey') {\n throw new Error(\n `Internal error: Wrong config type passed to valkey factory: ${this.storeOptions?.type}`,\n );\n }\n if (!stores[pluginId]) {\n const valkeyOptions = this.storeOptions?.client;\n if (this.storeOptions?.cluster) {\n // Create an iovalkey Cluster instance, which is the type that @keyv/valkey expects\n const cluster = new Cluster(\n this.storeOptions.cluster.rootNodes,\n this.storeOptions.cluster.options,\n );\n stores[pluginId] = new KeyvValkey(cluster, valkeyOptions);\n } else {\n // Create a regular Valkey connection\n stores[pluginId] = new KeyvValkey(this.connection, valkeyOptions);\n }\n\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create valkey cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: CacheManager.constructNamespace(pluginId, this.storeOptions),\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n useKeyPrefix: false,\n });\n };\n }\n\n private createMemcacheStoreFactory(): StoreFactory {\n const KeyvMemcache = require('@keyv/memcache').default;\n const stores: Record<string, typeof KeyvMemcache> = {};\n\n return (pluginId, defaultTtl) => {\n if (!stores[pluginId]) {\n stores[pluginId] = new KeyvMemcache(this.connection);\n // Always provide an error handler to avoid stopping the process\n stores[pluginId].on('error', (err: Error) => {\n this.logger?.error('Failed to create memcache cache client', err);\n this.errorHandler?.(err);\n });\n }\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store: stores[pluginId],\n });\n };\n }\n\n private createMemoryStoreFactory(): StoreFactory {\n const store = new Map();\n return (pluginId, defaultTtl) =>\n new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n emitErrors: false,\n store,\n });\n }\n\n private createInfinispanStoreFactory(): StoreFactory {\n const stores: Record<string, InfinispanKeyvStore> = {};\n\n return (pluginId, defaultTtl) => {\n if (this.storeOptions?.type !== 'infinispan') {\n throw new Error(\n `Internal error: Wrong config type passed to infinispan factory: ${this.storeOptions?.type}`,\n );\n }\n\n if (!stores[pluginId]) {\n // Use sync version for testing environments\n const isTest =\n process.env.NODE_ENV === 'test' || typeof jest !== 'undefined';\n\n // Create the client promise ONCE and reuse it\n const clientPromise: Promise<InfinispanClientCacheInterface> = isTest\n ? this.createInfinispanClientSync()\n : this.createInfinispanClientAsync();\n\n this.logger?.info(\n `Creating Infinispan cache client for plugin ${pluginId} isTest = ${isTest}`,\n );\n const storeInstance = new InfinispanKeyvStore({\n clientPromise,\n logger: this.logger!,\n });\n\n stores[pluginId] = storeInstance;\n\n // Always provide an error handler to avoid stopping the process\n storeInstance.on('error', (err: Error) => {\n this.logger?.error('Failed to create infinispan cache client', err);\n this.errorHandler?.(err);\n });\n }\n\n return new Keyv({\n namespace: pluginId,\n ttl: defaultTtl,\n store: stores[pluginId],\n emitErrors: false,\n });\n };\n }\n\n /**\n * Creates an Infinispan client using dynamic import (production use).\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClientAsync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(false);\n }\n\n /**\n * Creates an Infinispan client using synchronous import (testing purposes).\n * @returns Promise that resolves to an Infinispan client\n */\n private createInfinispanClientSync(): Promise<InfinispanClientCacheInterface> {\n return this.createInfinispanClient(true);\n }\n\n /**\n * Creates an Infinispan client based on the provided configuration.\n * @param useSync - Whether to use synchronous import (for testing) or dynamic import\n * @returns Promise that resolves to an Infinispan client\n */\n private async createInfinispanClient(\n useSync: boolean = false,\n ): Promise<InfinispanClientCacheInterface> {\n try {\n this.logger?.info('Creating Infinispan client');\n\n if (this.storeOptions?.type === 'infinispan') {\n // Import infinispan based on the useSync parameter\n const infinispan = useSync\n ? require('infinispan')\n : await import('infinispan');\n\n const client = await infinispan.client(\n this.storeOptions.servers as InfinispanServerConfig[],\n this.storeOptions.options as InfinispanClientBehaviorOptions,\n );\n\n this.logger?.info('Infinispan client created successfully');\n return client;\n }\n throw new Error('Infinispan store options are not defined');\n } catch (error: any) {\n this.logger?.error('Failed to create Infinispan client', {\n error: error.message,\n });\n throw error;\n }\n }\n}\n"],"names":["config","durationToMilliseconds","readDurationFromConfig","InfinispanOptionsMapper","ConfigReader","ttlToMilliseconds","DefaultCacheClient","Keyv","InfinispanKeyvStore"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs.js","sources":["../../../src/entrypoints/cache/types.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { RedisClusterOptions, KeyvRedisOptions } from '@keyv/redis';\nimport { KeyvValkeyOptions } from '@keyv/valkey';\n\n/**\n * Options for Redis cache store.\n *\n * @public\n */\nexport type RedisCacheStoreOptions = {\n type: 'redis';\n client?: KeyvRedisOptions;\n cluster?: RedisClusterOptions;\n};\n\n/**\n * Options for Valkey cache store.\n *\n * @public\n */\nexport type ValkeyCacheStoreOptions = {\n type: 'valkey';\n client?: KeyvValkeyOptions;\n cluster?: RedisClusterOptions;\n};\n\n/**\n * Union type of all cache store options.\n *\n * @public\n */\nexport type CacheStoreOptions =\n | RedisCacheStoreOptions\n | ValkeyCacheStoreOptions\n | InfinispanCacheStoreOptions;\n\n/**\n * Options given when constructing a {@link CacheManager}.\n *\n * @public\n */\nexport type CacheManagerOptions = {\n /**\n * An optional logger for use by the PluginCacheManager.\n */\n logger?: LoggerService;\n\n /**\n * An optional handler for connection errors emitted from the underlying data\n * store.\n */\n onError?: (err: Error) => void;\n};\n\nexport function ttlToMilliseconds(ttl: number | HumanDuration): number {\n return typeof ttl === 'number' ? ttl : durationToMilliseconds(ttl);\n}\n\n/**\n * Configuration for a single Infinispan server.\n */\nexport type InfinispanServerConfig = {\n host: string;\n port: number;\n};\n\n/**\n * Options for putting values into Infinispan cache.\n */\nexport type InfinispanPutOptions = {\n lifespan?: string;\n maxIdle?: string;\n previous?: boolean;\n flags?: string[];\n};\n/**\n * SSL/TLS options for the Infinispan client.\n */\nexport type InfinispanSslOptions = {\n enabled: boolean;\n secureProtocol?: string;\n trustCerts?: string[]; // Array of trusted CA certificates\n clientAuth?: InfinispanClientAuthOptions;\n cryptoStore?: InfinispanCryptoStoreOptions;\n sniHostName?: string;\n};\n\n/**\n * Authentication options for the Infinispan client.\n * This is used for client-side authentication with the Infinispan server.\n */\nexport type InfinispanClientAuthOptions = {\n key?: string;\n passphrase?: string;\n cert?: string;\n};\n\n/**\n * Options for the Infinispan client crypto store.\n * This is used for storing keys and certificates securely.\n */\nexport type InfinispanCryptoStoreOptions = {\n path?: string;\n passphrase?: string;\n};\n\n/**\n * Authentication options for the Infinispan client.\n */\nexport type InfinispanAuthOptions = {\n enabled: boolean;\n saslMechanism?: string;\n userName?: string;\n password?: string;\n token?: string;\n authzid?: string;\n};\n\n/**\n * Options for the Infinispan cache store, designed to be configured\n * in app-config.yaml under `backend.cache.infinispan`.\n */\nexport type InfinispanCacheStoreOptions = {\n type: 'infinispan';\n servers: InfinispanServerConfig | InfinispanServerConfig[];\n options?: InfinispanClientBehaviorOptions;\n};\n\nexport type InfinispanClusterConfig = {\n name?: string;\n servers: InfinispanServerConfig[];\n};\n\nexport type DataFormatOptions = {\n keyType: 'text/plain' | 'application/json';\n valueType: 'text/plain' | 'application/json';\n};\n\n/**\n * Detailed client behavior options for the Infinispan client.\n * @public\n */\nexport type InfinispanClientBehaviorOptions = {\n version?: '2.9' | '2.5' | '2.2';\n cacheName?: string;\n maxRetries?: number;\n connectionTimeout?: number;\n socketTimeout?: number;\n authentication?: InfinispanAuthOptions;\n ssl?: InfinispanSslOptions;\n mediaType?: 'text/plain' | 'application/json';\n topologyUpdates?: boolean;\n clusters?: InfinispanClusterConfig[];\n dataFormat: DataFormatOptions;\n};\n"],"names":["durationToMilliseconds"],"mappings":";;;;AAuEO,SAAS,kBAAkB,GAAA,EAAqC;AACrE,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,GAAW,GAAA,GAAMA,6BAAuB,GAAG,CAAA;AACnE;;;;"}
1
+ {"version":3,"file":"types.cjs.js","sources":["../../../src/entrypoints/cache/types.ts"],"sourcesContent":["/*\n * Copyright 2020 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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { RedisClusterOptions, KeyvRedisOptions } from '@keyv/redis';\nimport { KeyvValkeyOptions } from '@keyv/valkey';\nimport { ClusterNode, ClusterOptions } from 'iovalkey';\n\n/**\n * Options for Redis cache store.\n *\n * @public\n */\nexport type RedisCacheStoreOptions = {\n type: 'redis';\n client?: KeyvRedisOptions;\n cluster?: RedisClusterOptions;\n};\n\n/**\n * Options for Valkey cache store.\n *\n * @public\n */\nexport type ValkeyCacheStoreOptions = {\n type: 'valkey';\n client?: KeyvValkeyOptions;\n cluster?: {\n rootNodes: Array<ClusterNode>;\n options?: ClusterOptions;\n };\n};\n\n/**\n * Union type of all cache store options.\n *\n * @public\n */\nexport type CacheStoreOptions =\n | RedisCacheStoreOptions\n | ValkeyCacheStoreOptions\n | InfinispanCacheStoreOptions;\n\n/**\n * Options given when constructing a {@link CacheManager}.\n *\n * @public\n */\nexport type CacheManagerOptions = {\n /**\n * An optional logger for use by the PluginCacheManager.\n */\n logger?: LoggerService;\n\n /**\n * An optional handler for connection errors emitted from the underlying data\n * store.\n */\n onError?: (err: Error) => void;\n};\n\nexport function ttlToMilliseconds(ttl: number | HumanDuration): number {\n return typeof ttl === 'number' ? ttl : durationToMilliseconds(ttl);\n}\n\n/**\n * Configuration for a single Infinispan server.\n */\nexport type InfinispanServerConfig = {\n host: string;\n port: number;\n};\n\n/**\n * Options for putting values into Infinispan cache.\n */\nexport type InfinispanPutOptions = {\n lifespan?: string;\n maxIdle?: string;\n previous?: boolean;\n flags?: string[];\n};\n/**\n * SSL/TLS options for the Infinispan client.\n */\nexport type InfinispanSslOptions = {\n enabled: boolean;\n secureProtocol?: string;\n trustCerts?: string[]; // Array of trusted CA certificates\n clientAuth?: InfinispanClientAuthOptions;\n cryptoStore?: InfinispanCryptoStoreOptions;\n sniHostName?: string;\n};\n\n/**\n * Authentication options for the Infinispan client.\n * This is used for client-side authentication with the Infinispan server.\n */\nexport type InfinispanClientAuthOptions = {\n key?: string;\n passphrase?: string;\n cert?: string;\n};\n\n/**\n * Options for the Infinispan client crypto store.\n * This is used for storing keys and certificates securely.\n */\nexport type InfinispanCryptoStoreOptions = {\n path?: string;\n passphrase?: string;\n};\n\n/**\n * Authentication options for the Infinispan client.\n */\nexport type InfinispanAuthOptions = {\n enabled: boolean;\n saslMechanism?: string;\n userName?: string;\n password?: string;\n token?: string;\n authzid?: string;\n};\n\n/**\n * Options for the Infinispan cache store, designed to be configured\n * in app-config.yaml under `backend.cache.infinispan`.\n */\nexport type InfinispanCacheStoreOptions = {\n type: 'infinispan';\n servers: InfinispanServerConfig | InfinispanServerConfig[];\n options?: InfinispanClientBehaviorOptions;\n};\n\nexport type InfinispanClusterConfig = {\n name?: string;\n servers: InfinispanServerConfig[];\n};\n\nexport type DataFormatOptions = {\n keyType: 'text/plain' | 'application/json';\n valueType: 'text/plain' | 'application/json';\n};\n\n/**\n * Detailed client behavior options for the Infinispan client.\n * @public\n */\nexport type InfinispanClientBehaviorOptions = {\n version?: '2.9' | '2.5' | '2.2';\n cacheName?: string;\n maxRetries?: number;\n connectionTimeout?: number;\n socketTimeout?: number;\n authentication?: InfinispanAuthOptions;\n ssl?: InfinispanSslOptions;\n mediaType?: 'text/plain' | 'application/json';\n topologyUpdates?: boolean;\n clusters?: InfinispanClusterConfig[];\n dataFormat: DataFormatOptions;\n};\n"],"names":["durationToMilliseconds"],"mappings":";;;;AA2EO,SAAS,kBAAkB,GAAA,EAAqC;AACrE,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,GAAW,GAAA,GAAMA,6BAAuB,GAAG,CAAA;AACnE;;;;"}
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ var helpers = require('../auth/helpers.cjs.js');
4
+
5
+ const DEFAULT_TTL_MS = 5e3;
6
+ const SWEEP_INTERVAL_MS = 3e4;
7
+ class CachedUserInfoService {
8
+ #delegate;
9
+ #entries;
10
+ #ttlMs;
11
+ #lastSweep = Date.now();
12
+ constructor(delegate, options) {
13
+ this.#delegate = delegate;
14
+ this.#entries = options?.entries ?? /* @__PURE__ */ new Map();
15
+ this.#ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
16
+ }
17
+ async getUserInfo(credentials) {
18
+ const internalCredentials = helpers.toInternalBackstageCredentials(credentials);
19
+ const token = internalCredentials.token;
20
+ if (!token) {
21
+ return this.#delegate.getUserInfo(credentials);
22
+ }
23
+ const now = Date.now();
24
+ if (now - this.#lastSweep > SWEEP_INTERVAL_MS) {
25
+ this.#lastSweep = now;
26
+ for (const [key, entry] of this.#entries) {
27
+ if (entry.expiresAt <= now) {
28
+ this.#entries.delete(key);
29
+ }
30
+ }
31
+ }
32
+ const cached = this.#entries.get(token);
33
+ if (cached && cached.expiresAt > now) {
34
+ return cached.promise;
35
+ }
36
+ const promise = this.#delegate.getUserInfo(credentials).catch((error) => {
37
+ if (this.#entries.get(token)?.promise === promise) {
38
+ this.#entries.delete(token);
39
+ }
40
+ throw error;
41
+ });
42
+ this.#entries.set(token, {
43
+ promise,
44
+ expiresAt: now + this.#ttlMs
45
+ });
46
+ return promise;
47
+ }
48
+ }
49
+
50
+ exports.CachedUserInfoService = CachedUserInfoService;
51
+ //# sourceMappingURL=CachedUserInfoService.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CachedUserInfoService.cjs.js","sources":["../../../src/entrypoints/userInfo/CachedUserInfoService.ts"],"sourcesContent":["/*\n * Copyright 2026 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 BackstageUserInfo,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { toInternalBackstageCredentials } from '../auth/helpers';\n\nconst DEFAULT_TTL_MS = 5_000;\nconst SWEEP_INTERVAL_MS = 30_000;\n\nexport type UserInfoCacheEntry = {\n promise: Promise<BackstageUserInfo>;\n expiresAt: number;\n};\n\nexport class CachedUserInfoService implements UserInfoService {\n readonly #delegate: UserInfoService;\n readonly #entries: Map<string, UserInfoCacheEntry>;\n readonly #ttlMs: number;\n #lastSweep: number = Date.now();\n\n constructor(\n delegate: UserInfoService,\n options?: {\n entries?: Map<string, UserInfoCacheEntry>;\n ttlMs?: number;\n },\n ) {\n this.#delegate = delegate;\n this.#entries = options?.entries ?? new Map();\n this.#ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;\n }\n\n async getUserInfo(\n credentials: BackstageCredentials,\n ): Promise<BackstageUserInfo> {\n const internalCredentials = toInternalBackstageCredentials(credentials);\n const token = internalCredentials.token;\n if (!token) {\n return this.#delegate.getUserInfo(credentials);\n }\n\n const now = Date.now();\n\n if (now - this.#lastSweep > SWEEP_INTERVAL_MS) {\n this.#lastSweep = now;\n for (const [key, entry] of this.#entries) {\n if (entry.expiresAt <= now) {\n this.#entries.delete(key);\n }\n }\n }\n\n const cached = this.#entries.get(token);\n if (cached && cached.expiresAt > now) {\n return cached.promise;\n }\n\n const promise = this.#delegate.getUserInfo(credentials).catch(error => {\n if (this.#entries.get(token)?.promise === promise) {\n this.#entries.delete(token);\n }\n throw error;\n });\n\n this.#entries.set(token, {\n promise,\n expiresAt: now + this.#ttlMs,\n });\n\n return promise;\n }\n}\n"],"names":["toInternalBackstageCredentials"],"mappings":";;;;AAuBA,MAAM,cAAA,GAAiB,GAAA;AACvB,MAAM,iBAAA,GAAoB,GAAA;AAOnB,MAAM,qBAAA,CAAiD;AAAA,EACnD,SAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACT,UAAA,GAAqB,KAAK,GAAA,EAAI;AAAA,EAE9B,WAAA,CACE,UACA,OAAA,EAIA;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,EAAS,OAAA,oBAAW,IAAI,GAAA,EAAI;AAC5C,IAAA,IAAA,CAAK,MAAA,GAAS,SAAS,KAAA,IAAS,cAAA;AAAA,EAClC;AAAA,EAEA,MAAM,YACJ,WAAA,EAC4B;AAC5B,IAAA,MAAM,mBAAA,GAAsBA,uCAA+B,WAAW,CAAA;AACtE,IAAA,MAAM,QAAQ,mBAAA,CAAoB,KAAA;AAClC,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,WAAA,CAAY,WAAW,CAAA;AAAA,IAC/C;AAEA,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,IAAA,IAAI,GAAA,GAAM,IAAA,CAAK,UAAA,GAAa,iBAAA,EAAmB;AAC7C,MAAA,IAAA,CAAK,UAAA,GAAa,GAAA;AAClB,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,QAAA,EAAU;AACxC,QAAA,IAAI,KAAA,CAAM,aAAa,GAAA,EAAK;AAC1B,UAAA,IAAA,CAAK,QAAA,CAAS,OAAO,GAAG,CAAA;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AACtC,IAAA,IAAI,MAAA,IAAU,MAAA,CAAO,SAAA,GAAY,GAAA,EAAK;AACpC,MAAA,OAAO,MAAA,CAAO,OAAA;AAAA,IAChB;AAEA,IAAA,MAAM,UAAU,IAAA,CAAK,SAAA,CAAU,YAAY,WAAW,CAAA,CAAE,MAAM,CAAA,KAAA,KAAS;AACrE,MAAA,IAAI,KAAK,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA,EAAG,YAAY,OAAA,EAAS;AACjD,QAAA,IAAA,CAAK,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,MAC5B;AACA,MAAA,MAAM,KAAA;AAAA,IACR,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,KAAA,EAAO;AAAA,MACvB,OAAA;AAAA,MACA,SAAA,EAAW,MAAM,IAAA,CAAK;AAAA,KACvB,CAAA;AAED,IAAA,OAAO,OAAA;AAAA,EACT;AACF;;;;"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var CachedUserInfoService = require('./CachedUserInfoService.cjs.js');
4
5
  var DefaultUserInfoService = require('./DefaultUserInfoService.cjs.js');
5
6
 
6
7
  const userInfoServiceFactory = backendPluginApi.createServiceFactory({
@@ -8,8 +9,14 @@ const userInfoServiceFactory = backendPluginApi.createServiceFactory({
8
9
  deps: {
9
10
  discovery: backendPluginApi.coreServices.discovery
10
11
  },
11
- async factory({ discovery }) {
12
- return new DefaultUserInfoService.DefaultUserInfoService({ discovery });
12
+ createRootContext() {
13
+ return /* @__PURE__ */ new Map();
14
+ },
15
+ async factory({ discovery }, entries) {
16
+ return new CachedUserInfoService.CachedUserInfoService(
17
+ new DefaultUserInfoService.DefaultUserInfoService({ discovery }),
18
+ { entries }
19
+ );
13
20
  }
14
21
  });
15
22
 
@@ -1 +1 @@
1
- {"version":3,"file":"userInfoServiceFactory.cjs.js","sources":["../../../src/entrypoints/userInfo/userInfoServiceFactory.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 coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultUserInfoService } from './DefaultUserInfoService';\n\n/**\n * Authenticated user information retrieval.\n *\n * See {@link @backstage/code-plugin-api#UserInfoService}\n * and {@link https://backstage.io/docs/backend-system/core-services/user-info | the service docs}\n * for more information.\n *\n * @public\n */\nexport const userInfoServiceFactory = createServiceFactory({\n service: coreServices.userInfo,\n deps: {\n discovery: coreServices.discovery,\n },\n async factory({ discovery }) {\n return new DefaultUserInfoService({ discovery });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultUserInfoService"],"mappings":";;;;;AA+BO,MAAM,yBAAyBA,qCAAA,CAAqB;AAAA,EACzD,SAASC,6BAAA,CAAa,QAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,WAAWA,6BAAA,CAAa;AAAA,GAC1B;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,SAAA,EAAU,EAAG;AAC3B,IAAA,OAAO,IAAIC,6CAAA,CAAuB,EAAE,SAAA,EAAW,CAAA;AAAA,EACjD;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"userInfoServiceFactory.cjs.js","sources":["../../../src/entrypoints/userInfo/userInfoServiceFactory.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 coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport {\n CachedUserInfoService,\n UserInfoCacheEntry,\n} from './CachedUserInfoService';\nimport { DefaultUserInfoService } from './DefaultUserInfoService';\n\n/**\n * Authenticated user information retrieval.\n *\n * See {@link @backstage/code-plugin-api#UserInfoService}\n * and {@link https://backstage.io/docs/backend-system/core-services/user-info | the service docs}\n * for more information.\n *\n * @public\n */\nexport const userInfoServiceFactory = createServiceFactory({\n service: coreServices.userInfo,\n deps: {\n discovery: coreServices.discovery,\n },\n createRootContext() {\n return new Map<string, UserInfoCacheEntry>();\n },\n async factory({ discovery }, entries) {\n return new CachedUserInfoService(\n new DefaultUserInfoService({ discovery }),\n { entries },\n );\n },\n});\n"],"names":["createServiceFactory","coreServices","CachedUserInfoService","DefaultUserInfoService"],"mappings":";;;;;;AAmCO,MAAM,yBAAyBA,qCAAA,CAAqB;AAAA,EACzD,SAASC,6BAAA,CAAa,QAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,WAAWA,6BAAA,CAAa;AAAA,GAC1B;AAAA,EACA,iBAAA,GAAoB;AAClB,IAAA,2BAAW,GAAA,EAAgC;AAAA,EAC7C,CAAA;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,SAAA,IAAa,OAAA,EAAS;AACpC,IAAA,OAAO,IAAIC,2CAAA;AAAA,MACT,IAAIC,6CAAA,CAAuB,EAAE,SAAA,EAAW,CAAA;AAAA,MACxC,EAAE,OAAA;AAAQ,KACZ;AAAA,EACF;AACF,CAAC;;;;"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.17.1-next.2";
5
+ var version = "0.17.1";
6
6
  var packageinfo = {
7
7
  version: version};
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults",
3
- "version": "0.17.1-next.2",
3
+ "version": "0.17.1",
4
4
  "description": "Backend defaults used by Backstage backend apps",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -218,20 +218,20 @@
218
218
  "@aws-sdk/types": "^3.347.0",
219
219
  "@azure/identity": "^4.0.0",
220
220
  "@azure/storage-blob": "^12.5.0",
221
- "@backstage/backend-app-api": "1.7.0-next.0",
222
- "@backstage/backend-dev-utils": "0.1.7",
223
- "@backstage/backend-plugin-api": "1.9.1-next.1",
224
- "@backstage/cli-node": "0.3.2-next.1",
225
- "@backstage/config": "1.3.8-next.0",
226
- "@backstage/config-loader": "1.10.11-next.0",
227
- "@backstage/errors": "1.3.1-next.0",
228
- "@backstage/integration": "2.0.2-next.1",
229
- "@backstage/integration-aws-node": "0.2.0-next.1",
230
- "@backstage/plugin-auth-node": "0.7.1-next.1",
231
- "@backstage/plugin-events-node": "0.4.22-next.0",
232
- "@backstage/plugin-permission-common": "0.9.9-next.1",
233
- "@backstage/plugin-permission-node": "0.10.13-next.0",
234
- "@backstage/types": "1.2.2",
221
+ "@backstage/backend-app-api": "^1.7.0",
222
+ "@backstage/backend-dev-utils": "^0.1.7",
223
+ "@backstage/backend-plugin-api": "^1.9.1",
224
+ "@backstage/cli-node": "^0.3.2",
225
+ "@backstage/config": "^1.3.8",
226
+ "@backstage/config-loader": "^1.10.11",
227
+ "@backstage/errors": "^1.3.1",
228
+ "@backstage/integration": "^2.0.2",
229
+ "@backstage/integration-aws-node": "^0.2.0",
230
+ "@backstage/plugin-auth-node": "^0.7.1",
231
+ "@backstage/plugin-events-node": "^0.4.22",
232
+ "@backstage/plugin-permission-common": "^0.9.9",
233
+ "@backstage/plugin-permission-node": "^0.11.0",
234
+ "@backstage/types": "^1.2.2",
235
235
  "@google-cloud/storage": "^7.0.0",
236
236
  "@keyv/memcache": "^2.0.1",
237
237
  "@keyv/redis": "^4.0.1",
@@ -255,6 +255,7 @@
255
255
  "git-url-parse": "^15.0.0",
256
256
  "helmet": "^6.0.0",
257
257
  "infinispan": "^0.12.0",
258
+ "iovalkey": "^0.3.3",
258
259
  "is-glob": "^4.0.3",
259
260
  "jose": "^5.0.0",
260
261
  "keyv": "^5.2.1",
@@ -285,8 +286,8 @@
285
286
  },
286
287
  "devDependencies": {
287
288
  "@aws-sdk/util-stream-node": "^3.350.0",
288
- "@backstage/backend-test-utils": "1.11.3-next.2",
289
- "@backstage/cli": "0.36.2-next.1",
289
+ "@backstage/backend-test-utils": "^1.11.3",
290
+ "@backstage/cli": "^0.36.2",
290
291
  "@google-cloud/cloud-sql-connector": "^1.4.0",
291
292
  "@types/archiver": "^7.0.0",
292
293
  "@types/base64-stream": "^1.0.2",