refactor: convert constructor parameter properties for erasableSyntaxOnly compatibility

Signed-off-by: Paul Schultz <pschultz@pobox.com>
This commit is contained in:
Paul Schultz
2025-09-16 12:29:49 -05:00
parent b3a437e15d
commit 05f60e1e0a
167 changed files with 1826 additions and 679 deletions
@@ -0,0 +1,63 @@
---
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-kubernetes-react': patch
'@backstage/plugin-notifications-backend': patch
'@backstage/plugin-notifications-node': patch
'@backstage/plugin-permission-react': patch
'@backstage/plugin-scaffolder-backend-module-gcp': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-search-backend-module-elasticsearch': patch
'@backstage/plugin-search-backend-module-pg': patch
'@backstage/plugin-search-backend': patch
'@backstage/plugin-search-backend-node': patch
'@backstage/plugin-search-react': patch
'@backstage/plugin-signals': patch
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-events-backend': patch
'@backstage/plugin-catalog-backend-module-backstage-openapi': patch
'@backstage/plugin-events-node': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-notifications-backend-module-email': patch
'@backstage/plugin-events-backend-module-aws-sqs': patch
'@backstage/plugin-devtools-backend': patch
'@backstage/plugin-catalog-backend-module-unprocessed': patch
'@backstage/plugin-catalog-backend-module-azure': patch
'@backstage/plugin-catalog-backend-module-aws': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-techdocs-node': patch
'@backstage/plugin-catalog-unprocessed-entities': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-backend-module-ldap': patch
'@backstage/plugin-bitbucket-cloud-common': patch
'@backstage/plugin-auth-node': patch
'@backstage/backend-app-api': patch
'@backstage/backend-defaults': patch
'@backstage/config-loader': patch
'@backstage/core-app-api': patch
'@backstage/core-plugin-api': patch
'@backstage/frontend-app-api': patch
'@backstage/config': patch
'@backstage/backend-dynamic-feature-service': patch
'@backstage/core-components': patch
'@backstage/cli': patch
'@backstage/cli-node': patch
'@backstage/catalog-model': patch
'@backstage/integration': patch
'@backstage/frontend-plugin-api': patch
'@backstage/integration-aws-node': patch
'@backstage/repo-tools': patch
'@backstage/backend-test-utils': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-events-backend-module-kafka': patch
'@backstage/plugin-kubernetes-node': patch
'@backstage/plugin-mcp-actions-backend': patch
'@backstage/plugin-scaffolder-node-test-utils': patch
'@backstage/plugin-scaffolder-node': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-user-settings-backend': patch
---
Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
+6 -2
View File
@@ -20,12 +20,16 @@ import { DiscoveryApi } from '@backstage/core-plugin-api';
export class AuthProxyDiscoveryApi implements DiscoveryApi {
private urlPatternDiscovery: UrlPatternDiscovery;
private readonly isAuthProxyingEnabled?: boolean;
private readonly authProxyUrl?: string;
constructor(
baseUrl: string,
private readonly isAuthProxyingEnabled?: boolean,
private readonly authProxyUrl?: string,
isAuthProxyingEnabled?: boolean,
authProxyUrl?: string,
) {
this.isAuthProxyingEnabled = isAuthProxyingEnabled;
this.authProxyUrl = authProxyUrl;
this.urlPatternDiscovery = UrlPatternDiscovery.compile(
`${baseUrl}/api/{{ pluginId }}`,
);
@@ -30,11 +30,15 @@ class Node<T> {
);
}
private constructor(
readonly value: T,
readonly consumes: Set<string>,
readonly provides: Set<string>,
) {}
readonly value: T;
readonly consumes: Set<string>;
readonly provides: Set<string>;
private constructor(value: T, consumes: Set<string>, provides: Set<string>) {
this.value = value;
this.consumes = consumes;
this.provides = provides;
}
}
/** @internal */
@@ -80,10 +80,13 @@ async function findClosestPackageDir(
/** @internal */
export class PackageDiscoveryService {
constructor(
private readonly config: RootConfigService,
private readonly logger: RootLoggerService,
) {}
private readonly config: RootConfigService;
private readonly logger: RootLoggerService;
constructor(config: RootConfigService, logger: RootLoggerService) {
this.config = config;
this.logger = logger;
}
getDependencyNames(path: string) {
const { dependencies } = require(path) as BackstagePackageJson;
@@ -28,12 +28,22 @@ import {
} from '@backstage/backend-plugin-api/alpha';
export class DefaultActionsService implements ActionsService {
private readonly discovery: DiscoveryService;
private readonly config: RootConfigService;
private readonly logger: LoggerService;
private readonly auth: AuthService;
private constructor(
private readonly discovery: DiscoveryService,
private readonly config: RootConfigService,
private readonly logger: LoggerService,
private readonly auth: AuthService,
) {}
discovery: DiscoveryService,
config: RootConfigService,
logger: LoggerService,
auth: AuthService,
) {
this.discovery = discovery;
this.config = config;
this.logger = logger;
this.auth = auth;
}
static create({
discovery,
@@ -39,12 +39,22 @@ export class DefaultActionsRegistryService implements ActionsRegistryService {
private actions: Map<string, ActionsRegistryActionOptions<any, any>> =
new Map();
private readonly logger: LoggerService;
private readonly httpAuth: HttpAuthService;
private readonly auth: AuthService;
private readonly metadata: PluginMetadataService;
private constructor(
private readonly logger: LoggerService,
private readonly httpAuth: HttpAuthService,
private readonly auth: AuthService,
private readonly metadata: PluginMetadataService,
) {}
logger: LoggerService,
httpAuth: HttpAuthService,
auth: AuthService,
metadata: PluginMetadataService,
) {
this.logger = logger;
this.httpAuth = httpAuth;
this.auth = auth;
this.metadata = metadata;
}
static create({
httpAuth,
@@ -81,7 +81,11 @@ export type WinstonRootAuditorServiceOptions = {
* ```
*/
export class WinstonRootAuditorService {
private constructor(private readonly winstonLogger: WinstonLogger) {}
private readonly winstonLogger: WinstonLogger;
private constructor(winstonLogger: WinstonLogger) {
this.winstonLogger = winstonLogger;
}
/**
* Creates a {@link WinstonRootAuditorService} instance.
@@ -38,14 +38,28 @@ import { UserTokenHandler } from './user/UserTokenHandler';
/** @internal */
export class DefaultAuthService implements AuthService {
private readonly userTokenHandler: UserTokenHandler;
private readonly pluginTokenHandler: PluginTokenHandler;
private readonly externalTokenHandler: ExternalAuthTokenHandler;
private readonly pluginId: string;
private readonly disableDefaultAuthPolicy: boolean;
private readonly pluginKeySource: PluginKeySource;
constructor(
private readonly userTokenHandler: UserTokenHandler,
private readonly pluginTokenHandler: PluginTokenHandler,
private readonly externalTokenHandler: ExternalAuthTokenHandler,
private readonly pluginId: string,
private readonly disableDefaultAuthPolicy: boolean,
private readonly pluginKeySource: PluginKeySource,
) {}
userTokenHandler: UserTokenHandler,
pluginTokenHandler: PluginTokenHandler,
externalTokenHandler: ExternalAuthTokenHandler,
pluginId: string,
disableDefaultAuthPolicy: boolean,
pluginKeySource: PluginKeySource,
) {
this.userTokenHandler = userTokenHandler;
this.pluginTokenHandler = pluginTokenHandler;
this.externalTokenHandler = externalTokenHandler;
this.pluginId = pluginId;
this.disableDefaultAuthPolicy = disableDefaultAuthPolicy;
this.pluginKeySource = pluginKeySource;
}
async authenticate(
token: string,
@@ -30,7 +30,11 @@ export class JwksClient {
#keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;
#keyStoreUpdated: number = 0;
constructor(private readonly getEndpoint: () => Promise<URL>) {}
private readonly getEndpoint: () => Promise<URL>;
constructor(getEndpoint: () => Promise<URL>) {
this.getEndpoint = getEndpoint;
}
get getKey() {
if (!this.#keyStore) {
@@ -38,13 +38,14 @@ interface AnyJWK extends Record<string, string> {
}
class FakeTokenFactory {
private readonly keys = new Array<AnyJWK>();
private readonly options: {
issuer: string;
keyDurationSeconds: number;
};
constructor(
private readonly options: {
issuer: string;
keyDurationSeconds: number;
},
) {}
constructor(options: { issuer: string; keyDurationSeconds: number }) {
this.options = options;
}
async issueToken(params: {
claims: {
@@ -140,14 +140,24 @@ export class ExternalAuthTokenHandler {
return new ExternalAuthTokenHandler(ownPluginId, contexts);
}
private readonly ownPluginId: string;
private readonly contexts: {
context: unknown;
handler: ExternalTokenHandler<unknown>;
allAccessRestrictions?: AccessRestrictionsMap;
}[];
constructor(
private readonly ownPluginId: string,
private readonly contexts: {
ownPluginId: string,
contexts: {
context: unknown;
handler: ExternalTokenHandler<unknown>;
allAccessRestrictions?: AccessRestrictionsMap;
}[],
) {}
) {
this.ownPluginId = ownPluginId;
this.contexts = contexts;
}
async verifyToken(token: string): Promise<
| {
@@ -31,13 +31,14 @@ interface AnyJWK extends Record<string, string> {
}
class FakeTokenFactory {
private readonly keys = new Array<AnyJWK>();
private readonly options: {
issuer: string;
keyDurationSeconds: number;
};
constructor(
private readonly options: {
issuer: string;
keyDurationSeconds: number;
},
) {}
constructor(options: { issuer: string; keyDurationSeconds: number }) {
this.options = options;
}
async issueToken(params: {
claims: {
@@ -77,14 +77,28 @@ export class DefaultPluginTokenHandler implements PluginTokenHandler {
);
}
private readonly logger: LoggerService;
private readonly ownPluginId: string;
private readonly keySource: PluginKeySource;
private readonly algorithm: string;
private readonly keyDurationSeconds: number;
private readonly discovery: DiscoveryService;
private constructor(
private readonly logger: LoggerService,
private readonly ownPluginId: string,
private readonly keySource: PluginKeySource,
private readonly algorithm: string,
private readonly keyDurationSeconds: number,
private readonly discovery: DiscoveryService,
) {}
logger: LoggerService,
ownPluginId: string,
keySource: PluginKeySource,
algorithm: string,
keyDurationSeconds: number,
discovery: DiscoveryService,
) {
this.logger = logger;
this.ownPluginId = ownPluginId;
this.keySource = keySource;
this.algorithm = algorithm;
this.keyDurationSeconds = keyDurationSeconds;
this.discovery = discovery;
}
async verifyToken(
token: string,
@@ -62,10 +62,13 @@ export class DatabaseKeyStore implements KeyStore {
return new DatabaseKeyStore(client, logger);
}
private constructor(
private readonly client: Knex,
private readonly logger: LoggerService,
) {}
private readonly client: Knex;
private readonly logger: LoggerService;
private constructor(client: Knex, logger: LoggerService) {
this.client = client;
this.logger = logger;
}
async addKey(options: {
id: string;
@@ -33,13 +33,22 @@ const KEY_EXPIRATION_MARGIN_FACTOR = 3;
export class DatabasePluginKeySource implements PluginKeySource {
private privateKeyPromise?: Promise<JWK>;
private keyExpiry?: Date;
private readonly keyStore: KeyStore;
private readonly logger: LoggerService;
private readonly keyDurationSeconds: number;
private readonly algorithm: string;
constructor(
private readonly keyStore: KeyStore,
private readonly logger: LoggerService,
private readonly keyDurationSeconds: number,
private readonly algorithm: string,
) {}
keyStore: KeyStore,
logger: LoggerService,
keyDurationSeconds: number,
algorithm: string,
) {
this.keyStore = keyStore;
this.logger = logger;
this.keyDurationSeconds = keyDurationSeconds;
this.algorithm = algorithm;
}
public static async create(options: {
logger: LoggerService;
@@ -67,10 +67,13 @@ const SECONDS_IN_MS = 1000;
* private and public key paths in the `create` method.
*/
export class StaticConfigPluginKeySource implements PluginKeySource {
private constructor(
private readonly keyPairs: KeyPair[],
private readonly keyDurationSeconds: number,
) {}
private readonly keyPairs: KeyPair[];
private readonly keyDurationSeconds: number;
private constructor(keyPairs: KeyPair[], keyDurationSeconds: number) {
this.keyPairs = keyPairs;
this.keyDurationSeconds = keyDurationSeconds;
}
public static async create(options: {
sourceConfig: Config;
@@ -44,10 +44,13 @@ export class UserTokenHandler {
return new UserTokenHandler(jwksClient, options.logger);
}
constructor(
private readonly jwksClient: JwksClient,
private readonly logger: LoggerService,
) {}
private readonly jwksClient: JwksClient;
private readonly logger: LoggerService;
constructor(jwksClient: JwksClient, logger: LoggerService) {
this.jwksClient = jwksClient;
this.logger = logger;
}
async verifyToken(token: string) {
const verifyOpts = this.#getTokenVerificationOptions(token);
@@ -52,16 +52,24 @@ export type DatabaseManagerOptions = {
* Testable implementation class for {@link DatabaseManager} below.
*/
export class DatabaseManagerImpl {
private readonly config: Config;
private readonly connectors: Record<string, Connector>;
private readonly options?: DatabaseManagerOptions;
private readonly databaseCache: Map<string, Promise<Knex>>;
private readonly keepaliveIntervals: Map<string, NodeJS.Timeout>;
constructor(
private readonly config: Config,
private readonly connectors: Record<string, Connector>,
private readonly options?: DatabaseManagerOptions,
private readonly databaseCache: Map<string, Promise<Knex>> = new Map(),
private readonly keepaliveIntervals: Map<
string,
NodeJS.Timeout
> = new Map(),
config: Config,
connectors: Record<string, Connector>,
options?: DatabaseManagerOptions,
databaseCache: Map<string, Promise<Knex>> = new Map(),
keepaliveIntervals: Map<string, NodeJS.Timeout> = new Map(),
) {
this.config = config;
this.connectors = connectors;
this.options = options;
this.databaseCache = databaseCache;
this.keepaliveIntervals = keepaliveIntervals;
// If a rootLifecycle service was provided, register a shutdown hook to
// clean up any database connections.
if (options?.rootLifecycle !== undefined) {
@@ -262,7 +270,11 @@ export class DatabaseManager {
);
}
private constructor(private readonly impl: DatabaseManagerImpl) {}
private readonly impl: DatabaseManagerImpl;
private constructor(impl: DatabaseManagerImpl) {
this.impl = impl;
}
/**
* Generates a DatabaseService for consumption by plugins.
@@ -243,10 +243,13 @@ function normalizeConnection(
}
export class MysqlConnector implements Connector {
constructor(
private readonly config: Config,
private readonly prefix: string,
) {}
private readonly config: Config;
private readonly prefix: string;
constructor(config: Config, prefix: string) {
this.config = config;
this.prefix = prefix;
}
async getClient(
pluginId: string,
@@ -294,10 +294,13 @@ function normalizeConnection(
}
export class PgConnector implements Connector {
constructor(
private readonly config: Config,
private readonly prefix: string,
) {}
private readonly config: Config;
private readonly prefix: string;
constructor(config: Config, prefix: string) {
this.config = config;
this.prefix = prefix;
}
async getClient(
pluginId: string,
@@ -174,7 +174,11 @@ function normalizeConnection(
}
export class Sqlite3Connector implements Connector {
constructor(private readonly config: Config) {}
private readonly config: Config;
constructor(config: Config) {
this.config = config;
}
async getClient(
pluginId: string,
@@ -28,10 +28,13 @@ import {
/** @internal */
export class BackendPluginLifecycleImpl implements LifecycleService {
constructor(
private readonly logger: LoggerService,
private readonly pluginMetadata: PluginMetadataService,
) {}
private readonly logger: LoggerService;
private readonly pluginMetadata: PluginMetadataService;
constructor(logger: LoggerService, pluginMetadata: PluginMetadataService) {
this.logger = logger;
this.pluginMetadata = pluginMetadata;
}
#hasStarted = false;
#hasShutdown = false;
@@ -24,8 +24,10 @@ import {
/** @internal */
export class DefaultRootHealthService implements RootHealthService {
#state: 'init' | 'up' | 'down' = 'init';
readonly options: { lifecycle: RootLifecycleService };
constructor(readonly options: { lifecycle: RootLifecycleService }) {
constructor(options: { lifecycle: RootLifecycleService }) {
this.options = options;
options.lifecycle.addStartupHook(() => {
this.#state = 'up';
});
@@ -27,7 +27,11 @@ import {
/** @internal */
export class BackendLifecycleImpl implements RootLifecycleService {
constructor(private readonly logger: LoggerService) {}
private readonly logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
}
#hasStarted = false;
#startupTasks: Array<{
@@ -36,11 +36,19 @@ export class LocalTaskWorker {
status: 'idle',
};
private readonly taskId: string;
private readonly fn: SchedulerServiceTaskFunction;
private readonly logger: LoggerService;
constructor(
private readonly taskId: string,
private readonly fn: SchedulerServiceTaskFunction,
private readonly logger: LoggerService,
) {}
taskId: string,
fn: SchedulerServiceTaskFunction,
logger: LoggerService,
) {
this.taskId = taskId;
this.fn = fn;
this.logger = logger;
}
start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {
this.logger.info(
@@ -50,12 +50,19 @@ export class PluginTaskSchedulerImpl implements SchedulerService {
private readonly lastStarted: Gauge;
private readonly lastCompleted: Gauge;
private readonly pluginId: string;
private readonly databaseFactory: () => Promise<Knex>;
private readonly logger: LoggerService;
constructor(
private readonly pluginId: string,
private readonly databaseFactory: () => Promise<Knex>,
private readonly logger: LoggerService,
pluginId: string,
databaseFactory: () => Promise<Knex>,
logger: LoggerService,
rootLifecycle: RootLifecycleService,
) {
this.pluginId = pluginId;
this.databaseFactory = databaseFactory;
this.logger = logger;
const meter = metrics.getMeter('default');
this.counter = meter.createCounter('backend_tasks.task.runs.count', {
description: 'Total number of times a task has been run',
@@ -46,14 +46,25 @@ export class TaskWorker {
#workerState: TaskApiTasksResponse['workerState'] = {
status: 'idle',
};
private readonly taskId: string;
private readonly fn: SchedulerServiceTaskFunction;
private readonly knex: Knex;
private readonly logger: LoggerService;
private readonly workCheckFrequency: Duration;
constructor(
private readonly taskId: string,
private readonly fn: SchedulerServiceTaskFunction,
private readonly knex: Knex,
private readonly logger: LoggerService,
private readonly workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,
) {}
taskId: string,
fn: SchedulerServiceTaskFunction,
knex: Knex,
logger: LoggerService,
workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,
) {
this.taskId = taskId;
this.fn = fn;
this.knex = knex;
this.logger = logger;
this.workCheckFrequency = workCheckFrequency;
}
async start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {
try {
@@ -142,13 +142,23 @@ export class AwsCodeCommitUrlReader implements UrlReaderService {
});
};
private readonly credsManager: AwsCredentialsManager;
private readonly integration: AwsCodeCommitIntegration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
};
constructor(
private readonly credsManager: AwsCredentialsManager,
private readonly integration: AwsCodeCommitIntegration,
private readonly deps: {
credsManager: AwsCredentialsManager,
integration: AwsCodeCommitIntegration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
) {
this.credsManager = credsManager;
this.integration = integration;
this.deps = deps;
}
/**
* If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:
@@ -151,13 +151,23 @@ export class AwsS3UrlReader implements UrlReaderService {
});
};
private readonly credsManager: AwsCredentialsManager;
private readonly integration: AwsS3Integration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
};
constructor(
private readonly credsManager: AwsCredentialsManager,
private readonly integration: AwsS3Integration,
private readonly deps: {
credsManager: AwsCredentialsManager,
integration: AwsS3Integration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
) {
this.credsManager = credsManager;
this.integration = integration;
this.deps = deps;
}
/**
* If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:
@@ -91,13 +91,23 @@ export class AzureBlobStorageUrlReader implements UrlReaderService {
// private readonly blobServiceClient: BlobServiceClient;
private readonly credsManager: AzureCredentialsManager;
private readonly integration: AzureBlobStorageIntergation;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
};
constructor(
private readonly credsManager: AzureCredentialsManager,
private readonly integration: AzureBlobStorageIntergation,
private readonly deps: {
credsManager: AzureCredentialsManager,
integration: AzureBlobStorageIntergation,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
) {
this.credsManager = credsManager;
this.integration = integration;
this.deps = deps;
}
private async createContainerClient(
containerName: string,
@@ -62,13 +62,22 @@ export class AzureUrlReader implements UrlReaderService {
});
};
private readonly integration: AzureIntegration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
credentialsProvider: AzureDevOpsCredentialsProvider;
};
constructor(
private readonly integration: AzureIntegration,
private readonly deps: {
integration: AzureIntegration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
credentialsProvider: AzureDevOpsCredentialsProvider;
},
) {}
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
@@ -59,10 +59,15 @@ export class BitbucketCloudUrlReader implements UrlReaderService {
});
};
private readonly integration: BitbucketCloudIntegration;
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };
constructor(
private readonly integration: BitbucketCloudIntegration,
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },
integration: BitbucketCloudIntegration,
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.integration = integration;
this.deps = deps;
const { host, username, appPassword } = integration.config;
if (username && !appPassword) {
@@ -58,10 +58,16 @@ export class BitbucketServerUrlReader implements UrlReaderService {
});
};
private readonly integration: BitbucketServerIntegration;
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };
constructor(
private readonly integration: BitbucketServerIntegration,
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },
) {}
integration: BitbucketServerIntegration,
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
@@ -69,11 +69,16 @@ export class BitbucketUrlReader implements UrlReaderService {
});
};
private readonly integration: BitbucketIntegration;
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };
constructor(
private readonly integration: BitbucketIntegration,
integration: BitbucketIntegration,
logger: LoggerService,
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.integration = integration;
this.deps = deps;
const { host, token, username, appPassword } = integration.config;
const replacement =
host === 'bitbucket.org' ? 'bitbucketCloud' : 'bitbucketServer';
@@ -84,10 +84,16 @@ export class GerritUrlReader implements UrlReaderService {
});
};
private readonly integration: GerritIntegration;
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };
constructor(
private readonly integration: GerritIntegration,
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },
) {}
integration: GerritIntegration,
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
@@ -62,12 +62,20 @@ export class GiteaUrlReader implements UrlReaderService {
});
};
private readonly integration: GiteaIntegration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
};
constructor(
private readonly integration: GiteaIntegration,
private readonly deps: {
integration: GiteaIntegration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
@@ -77,13 +77,21 @@ export class GithubUrlReader implements UrlReaderService {
});
};
private readonly integration: GithubIntegration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
credentialsProvider: GithubCredentialsProvider;
};
constructor(
private readonly integration: GithubIntegration,
private readonly deps: {
integration: GithubIntegration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
credentialsProvider: GithubCredentialsProvider;
},
) {
this.integration = integration;
this.deps = deps;
if (!integration.config.apiBaseUrl && !integration.config.rawBaseUrl) {
throw new Error(
`GitHub integration '${integration.title}' must configure an explicit apiBaseUrl or rawBaseUrl`,
@@ -63,10 +63,16 @@ export class GitlabUrlReader implements UrlReaderService {
});
};
private readonly integration: GitLabIntegration;
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };
constructor(
private readonly integration: GitLabIntegration,
private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },
) {}
integration: GitLabIntegration,
deps: { treeResponseFactory: ReadTreeResponseFactory },
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
@@ -88,10 +88,16 @@ export class GoogleGcsUrlReader implements UrlReaderService {
return [{ reader, predicate }];
};
private readonly integration: GoogleGcsIntegrationConfig;
private readonly storage: GoogleCloud.Storage;
constructor(
private readonly integration: GoogleGcsIntegrationConfig,
private readonly storage: GoogleCloud.Storage,
) {}
integration: GoogleGcsIntegrationConfig,
storage: GoogleCloud.Storage,
) {
this.integration = integration;
this.storage = storage;
}
private readStreamFromUrl(url: string): Readable {
const { bucket, key } = parseURL(url);
@@ -64,12 +64,20 @@ export class HarnessUrlReader implements UrlReaderService {
});
};
private readonly integration: HarnessIntegration;
private readonly deps: {
treeResponseFactory: ReadTreeResponseFactory;
};
constructor(
private readonly integration: HarnessIntegration,
private readonly deps: {
integration: HarnessIntegration,
deps: {
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
) {
this.integration = integration;
this.deps = deps;
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
return response.buffer();
@@ -36,7 +36,11 @@ export class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory {
);
}
constructor(private readonly workDir: string) {}
private readonly workDir: string;
constructor(workDir: string) {
this.workDir = workDir;
}
async fromTarArchive(
options: ReadTreeResponseFactoryOptions & {
@@ -35,12 +35,13 @@ const pipeline = promisify(pipelineCb);
*/
export class ReadableArrayResponse implements UrlReaderServiceReadTreeResponse {
private read = false;
private readonly stream: FromReadableArrayOptions;
private readonly workDir: string;
public readonly etag: string;
constructor(
private readonly stream: FromReadableArrayOptions,
private readonly workDir: string,
public readonly etag: string,
) {
constructor(stream: FromReadableArrayOptions, workDir: string, etag: string) {
this.stream = stream;
this.workDir = workDir;
this.etag = etag;
}
@@ -37,15 +37,27 @@ const pipeline = promisify(pipelineCb);
*/
export class TarArchiveResponse implements UrlReaderServiceReadTreeResponse {
private read = false;
private readonly stream: Readable;
private readonly subPath: string;
private readonly workDir: string;
public readonly etag: string;
private readonly filter?: (path: string, info: { size: number }) => boolean;
private readonly stripFirstDirectory: boolean;
constructor(
private readonly stream: Readable,
private readonly subPath: string,
private readonly workDir: string,
public readonly etag: string,
private readonly filter?: (path: string, info: { size: number }) => boolean,
private readonly stripFirstDirectory: boolean = true,
stream: Readable,
subPath: string,
workDir: string,
etag: string,
filter?: (path: string, info: { size: number }) => boolean,
stripFirstDirectory: boolean = true,
) {
this.stream = stream;
this.subPath = subPath;
this.workDir = workDir;
this.etag = etag;
this.filter = filter;
this.stripFirstDirectory = stripFirstDirectory;
if (subPath) {
if (!subPath.endsWith('/')) {
this.subPath += '/';
@@ -32,14 +32,24 @@ import { resolveSafeChildPath } from '@backstage/backend-plugin-api';
*/
export class ZipArchiveResponse implements UrlReaderServiceReadTreeResponse {
private read = false;
private readonly stream: Readable;
private readonly subPath: string;
private readonly workDir: string;
public readonly etag: string;
private readonly filter?: (path: string, info: { size: number }) => boolean;
constructor(
private readonly stream: Readable,
private readonly subPath: string,
private readonly workDir: string,
public readonly etag: string,
private readonly filter?: (path: string, info: { size: number }) => boolean,
stream: Readable,
subPath: string,
workDir: string,
etag: string,
filter?: (path: string, info: { size: number }) => boolean,
) {
this.stream = stream;
this.subPath = subPath;
this.workDir = workDir;
this.etag = etag;
this.filter = filter;
if (subPath) {
if (!subPath.endsWith('/')) {
this.subPath += '/';
@@ -36,8 +36,10 @@ export type CommonJSModuleLoaderOptions = {
*/
export class CommonJSModuleLoader implements ModuleLoader {
private module: any;
public readonly options: CommonJSModuleLoaderOptions;
constructor(public readonly options: CommonJSModuleLoaderOptions) {
constructor(options: CommonJSModuleLoaderOptions) {
this.options = options;
this.module = require('node:module');
}
@@ -99,11 +99,18 @@ export class DynamicPluginManager implements DynamicPluginProvider {
private readonly _plugins: DynamicPlugin[];
private _availablePackages: ScannedPluginPackage[];
private readonly logger: LoggerService;
private readonly packages: ScannedPluginPackage[];
private readonly moduleLoader: ModuleLoader;
private constructor(
private readonly logger: LoggerService,
private readonly packages: ScannedPluginPackage[],
private readonly moduleLoader: ModuleLoader,
logger: LoggerService,
packages: ScannedPluginPackage[],
moduleLoader: ModuleLoader,
) {
this.logger = logger;
this.packages = packages;
this.moduleLoader = moduleLoader;
this._plugins = [];
this._availablePackages = packages;
}
@@ -304,7 +311,11 @@ export const dynamicPluginsServiceFactory = Object.assign(
);
class DynamicPluginsEnabledFeatureDiscoveryService {
constructor(private readonly dynamicPlugins: DynamicPluginProvider) {}
private readonly dynamicPlugins: DynamicPluginProvider;
constructor(dynamicPlugins: DynamicPluginProvider) {
this.dynamicPlugins = dynamicPlugins;
}
async getBackendFeatures(): Promise<{ features: Array<BackendFeature> }> {
return {
@@ -42,13 +42,22 @@ export class PluginScanner {
private configUnsubscribe?: () => void;
private rootDirectoryWatcher?: chokidar.FSWatcher;
private subscribers: (() => void)[] = [];
private readonly config: Config;
private readonly logger: LoggerService;
private readonly backstageRoot: string;
private readonly preferAlpha: boolean;
private constructor(
private readonly config: Config,
private readonly logger: LoggerService,
private readonly backstageRoot: string,
private readonly preferAlpha: boolean,
) {}
config: Config,
logger: LoggerService,
backstageRoot: string,
preferAlpha: boolean,
) {
this.config = config;
this.logger = logger;
this.backstageRoot = backstageRoot;
this.preferAlpha = preferAlpha;
}
static create(options: DynamicPluginScannerOptions): PluginScanner {
const scanner = new PluginScanner(
@@ -65,7 +65,11 @@ import {
export class MockActionsRegistry
implements ActionsRegistryService, ActionsService
{
private constructor(private readonly logger: LoggerService) {}
private readonly logger: LoggerService;
private constructor(logger: LoggerService) {
this.logger = logger;
}
static create(opts: { logger: LoggerService }) {
return new MockActionsRegistry(opts.logger);
+10 -2
View File
@@ -19,7 +19,11 @@ import { Entity, EntityPolicy } from './entity';
// Helper that requires that all of a set of policies can be successfully
// applied
class AllEntityPolicies implements EntityPolicy {
constructor(private readonly policies: EntityPolicy[]) {}
private readonly policies: EntityPolicy[];
constructor(policies: EntityPolicy[]) {
this.policies = policies;
}
async enforce(entity: Entity): Promise<Entity> {
let result = entity;
@@ -39,7 +43,11 @@ class AllEntityPolicies implements EntityPolicy {
// Helper that requires that at least one of a set of policies can be
// successfully applied
class AnyEntityPolicy implements EntityPolicy {
constructor(private readonly policies: EntityPolicy[]) {}
private readonly policies: EntityPolicy[];
constructor(policies: EntityPolicy[]) {
this.policies = policies;
}
async enforce(entity: Entity): Promise<Entity> {
for (const policy of this.policies) {
+9 -3
View File
@@ -133,10 +133,16 @@ export class Lockfile {
return new Lockfile(packages, data);
}
private readonly packages: Map<string, LockfileQueryEntry[]>;
private readonly data: LockfileData;
private constructor(
private readonly packages: Map<string, LockfileQueryEntry[]>,
private readonly data: LockfileData,
) {}
packages: Map<string, LockfileQueryEntry[]>,
data: LockfileData,
) {
this.packages = packages;
this.data = data;
}
/** Returns the name of all packages available in the lockfile */
get(name: string): LockfileQueryEntry[] | undefined {
+12 -4
View File
@@ -106,11 +106,19 @@ export class Lockfile {
return new Lockfile(packages, data, legacy);
}
private readonly packages: Map<string, LockfileQueryEntry[]>;
private readonly data: LockfileData;
private readonly legacy: boolean;
private constructor(
private readonly packages: Map<string, LockfileQueryEntry[]>,
private readonly data: LockfileData,
private readonly legacy: boolean = false,
) {}
packages: Map<string, LockfileQueryEntry[]>,
data: LockfileData,
legacy: boolean = false,
) {
this.packages = packages;
this.data = data;
this.legacy = legacy;
}
/** Get the entries for a single package in the lockfile */
get(name: string): LockfileQueryEntry[] | undefined {
@@ -58,10 +58,12 @@ export class GithubCreateAppServer {
return server.start();
}
private constructor(
private readonly actionUrl: string,
private readonly permissions: string[],
) {
private readonly actionUrl: string;
private readonly permissions: string[];
private constructor(actionUrl: string, permissions: string[]) {
this.actionUrl = actionUrl;
this.permissions = permissions;
const webhookId = crypto
.randomBytes(15)
.toString('base64')
@@ -27,11 +27,18 @@ export class ObservableConfigProxy implements Config {
return new ObservableConfigProxy(undefined, undefined, abortController);
}
private readonly parent?: ObservableConfigProxy;
private readonly parentKey?: string;
private readonly abortController?: AbortController;
private constructor(
private readonly parent?: ObservableConfigProxy,
private readonly parentKey?: string,
private readonly abortController?: AbortController,
parent?: ObservableConfigProxy,
parentKey?: string,
abortController?: AbortController,
) {
this.parent = parent;
this.parentKey = parentKey;
this.abortController = abortController;
if (parent && !parentKey) {
throw new Error('parentKey is required if parent is set');
}
@@ -37,10 +37,13 @@ export interface StaticConfigSourceOptions {
/** @internal */
class StaticObservableConfigSource implements ConfigSource {
constructor(
private readonly data: Observable<JsonObject>,
private readonly context: string,
) {}
private readonly data: Observable<JsonObject>;
private readonly context: string;
constructor(data: Observable<JsonObject>, context: string) {
this.data = data;
this.context = context;
}
async *readConfigData(
options?: ReadConfigDataOptions | undefined,
@@ -131,10 +134,16 @@ export class StaticConfigSource implements ConfigSource {
return new StaticConfigSource(data, context);
}
private readonly promise: JsonObject | PromiseLike<JsonObject>;
private readonly context: string;
private constructor(
private readonly promise: JsonObject | PromiseLike<JsonObject>,
private readonly context: string,
) {}
promise: JsonObject | PromiseLike<JsonObject>,
context: string,
) {
this.promise = promise;
this.context = context;
}
async *readConfigData(): AsyncConfigSourceGenerator {
yield { configs: [{ data: await this.promise, context: this.context }] };
+15 -5
View File
@@ -139,12 +139,22 @@ export class ConfigReader implements Config {
);
}
private readonly data: JsonObject | undefined;
private readonly context: string;
private readonly fallback?: ConfigReader;
private readonly prefix: string;
constructor(
private readonly data: JsonObject | undefined,
private readonly context: string = 'mock-config',
private readonly fallback?: ConfigReader,
private readonly prefix: string = '',
) {}
data: JsonObject | undefined,
context: string = 'mock-config',
fallback?: ConfigReader,
prefix: string = '',
) {
this.data = data;
this.context = context;
this.fallback = fallback;
this.prefix = prefix;
}
/** {@inheritdoc Config.has} */
has(key: string): boolean {
@@ -71,10 +71,16 @@ export class FrontendHostDiscovery implements DiscoveryApi {
);
}
private readonly endpoints: Map<string, DiscoveryApi>;
private readonly defaultEndpoint: DiscoveryApi;
private constructor(
private readonly endpoints: Map<string, DiscoveryApi>,
private readonly defaultEndpoint: DiscoveryApi,
) {}
endpoints: Map<string, DiscoveryApi>,
defaultEndpoint: DiscoveryApi,
) {
this.endpoints = endpoints;
this.defaultEndpoint = defaultEndpoint;
}
async getBaseUrl(pluginId: string): Promise<string> {
const endpoint = this.endpoints.get(pluginId);
@@ -27,10 +27,13 @@ import {
* @public
*/
export class ErrorAlerter implements ErrorApi {
constructor(
private readonly alertApi: AlertApi,
private readonly errorApi: ErrorApi,
) {}
private readonly alertApi: AlertApi;
private readonly errorApi: ErrorApi;
constructor(alertApi: AlertApi, errorApi: ErrorApi) {
this.alertApi = alertApi;
this.errorApi = errorApi;
}
post(error: ErrorApiError, context?: ErrorApiErrorContext) {
if (!context?.hidden) {
@@ -64,12 +64,22 @@ export class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware {
});
}
public readonly identityApi: IdentityApi;
public readonly allowUrl: (url: string) => boolean;
public readonly headerName: string;
public readonly headerValue: (pluginId: string) => string;
constructor(
public readonly identityApi: IdentityApi,
public readonly allowUrl: (url: string) => boolean,
public readonly headerName: string,
public readonly headerValue: (pluginId: string) => string,
) {}
identityApi: IdentityApi,
allowUrl: (url: string) => boolean,
headerName: string,
headerValue: (pluginId: string) => string,
) {
this.identityApi = identityApi;
this.allowUrl = allowUrl;
this.headerName = headerName;
this.headerValue = headerValue;
}
apply(next: typeof fetch): typeof fetch {
return async (input, init) => {
@@ -30,10 +30,13 @@ export const buckets = new Map<string, WebStorage>();
* @public
*/
export class WebStorage implements StorageApi {
constructor(
private readonly namespace: string,
private readonly errorApi: ErrorApi,
) {}
private readonly namespace: string;
private readonly errorApi: ErrorApi;
constructor(namespace: string, errorApi: ErrorApi) {
this.namespace = namespace;
this.errorApi = errorApi;
}
private static hasSubscribed = false;
@@ -170,16 +170,25 @@ function resolveBasePath(
}
export class RouteResolver {
private readonly routePaths: Map<RouteRef, string>;
private readonly routeParents: Map<RouteRef, RouteRef | undefined>;
private readonly routeObjects: BackstageRouteObject[];
private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;
private readonly appBasePath: string; // base path without a trailing slash
constructor(
private readonly routePaths: Map<RouteRef, string>,
private readonly routeParents: Map<RouteRef, RouteRef | undefined>,
private readonly routeObjects: BackstageRouteObject[],
private readonly routeBindings: Map<
ExternalRouteRef,
RouteRef | SubRouteRef
>,
private readonly appBasePath: string, // base path without a trailing slash
) {}
routePaths: Map<RouteRef, string>,
routeParents: Map<RouteRef, RouteRef | undefined>,
routeObjects: BackstageRouteObject[],
routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,
appBasePath: string, // base path without a trailing slash
) {
this.routePaths = routePaths;
this.routeParents = routeParents;
this.routeObjects = routeObjects;
this.routeBindings = routeBindings;
this.appBasePath = appBasePath;
}
resolve<Params extends AnyParams>(
anyRouteRef:
@@ -78,11 +78,12 @@ export interface AnsiChunk {
export class AnsiLine {
text: string;
readonly lineNumber: number;
readonly chunks: AnsiChunk[];
constructor(
readonly lineNumber: number = 1,
readonly chunks: AnsiChunk[] = [],
) {
constructor(lineNumber: number = 1, chunks: AnsiChunk[] = []) {
this.lineNumber = lineNumber;
this.chunks = chunks;
this.text = chunks
.map(c => c.text)
.join('')
@@ -96,13 +96,19 @@ export class UserIdentity implements IdentityApi {
return new UserIdentity(options.identity, options.authApi, options.profile);
}
private readonly identity: BackstageUserIdentity;
private readonly authApi: ProfileInfoApi & BackstageIdentityApi & SessionApi;
private readonly profile?: ProfileInfo;
private constructor(
private readonly identity: BackstageUserIdentity,
private readonly authApi: ProfileInfoApi &
BackstageIdentityApi &
SessionApi,
private readonly profile?: ProfileInfo,
) {}
identity: BackstageUserIdentity,
authApi: ProfileInfoApi & BackstageIdentityApi & SessionApi,
profile?: ProfileInfo,
) {
this.identity = identity;
this.authApi = authApi;
this.profile = profile;
}
/** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */
getUserId(): string {
@@ -65,14 +65,19 @@ const globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(
export const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';
export class Tracker implements AnalyticsTracker {
private readonly analyticsApi: AnalyticsApi;
private context: AnalyticsContextValue;
constructor(
private readonly analyticsApi: AnalyticsApi,
private context: AnalyticsContextValue = {
analyticsApi: AnalyticsApi,
context: AnalyticsContextValue = {
routeRef: 'unknown',
pluginId: 'root',
extension: 'App',
},
) {
this.analyticsApi = analyticsApi;
this.context = context;
// Only register a single beforeunload event across all trackers.
if (!globalEvents.beforeUnloadRegistered) {
// Before the page unloads, attempt to capture any deferred navigation
@@ -135,10 +135,13 @@ export interface ElementCollection {
}
class Collection implements ElementCollection {
constructor(
private readonly node: ReactNode,
private readonly featureFlagsApi: FeatureFlagsApi,
) {}
private readonly node: ReactNode;
private readonly featureFlagsApi: FeatureFlagsApi;
constructor(node: ReactNode, featureFlagsApi: FeatureFlagsApi) {
this.node = node;
this.featureFlagsApi = featureFlagsApi;
}
selectByComponentData(query: { key: string; withStrictError?: string }) {
const selection = selectChildren(
@@ -34,12 +34,22 @@ export class ExternalRouteRefImpl<
declare $$routeRefType: 'external';
readonly [routeRefType] = 'external';
private readonly id: string;
readonly params: ParamKeys<Params>;
readonly optional: Optional;
readonly defaultTarget: string | undefined;
constructor(
private readonly id: string,
readonly params: ParamKeys<Params>,
readonly optional: Optional,
readonly defaultTarget: string | undefined,
) {}
id: string,
params: ParamKeys<Params>,
optional: Optional,
defaultTarget: string | undefined,
) {
this.id = id;
this.params = params;
this.optional = optional;
this.defaultTarget = defaultTarget;
}
toString() {
return `routeRef{type=external,id=${this.id}}`;
@@ -32,10 +32,13 @@ export class RouteRefImpl<Params extends AnyParams>
declare $$routeRefType: 'absolute';
readonly [routeRefType] = 'absolute';
constructor(
private readonly id: string,
readonly params: ParamKeys<Params>,
) {}
private readonly id: string;
readonly params: ParamKeys<Params>;
constructor(id: string, params: ParamKeys<Params>) {
this.id = id;
this.params = params;
}
get title() {
return this.id;
@@ -36,12 +36,22 @@ export class SubRouteRefImpl<Params extends AnyParams>
declare $$routeRefType: 'sub';
readonly [routeRefType] = 'sub';
private readonly id: string;
readonly path: string;
readonly parent: RouteRef;
readonly params: ParamKeys<Params>;
constructor(
private readonly id: string,
readonly path: string,
readonly parent: RouteRef,
readonly params: ParamKeys<Params>,
) {}
id: string,
path: string,
parent: RouteRef,
params: ParamKeys<Params>,
) {
this.id = id;
this.path = path;
this.parent = parent;
this.params = params;
}
toString() {
return `routeRef{type=sub,id=${this.id}}`;
@@ -179,18 +179,31 @@ function resolveBasePath(
}
export class RouteResolver implements RouteResolutionApi {
private readonly routePaths: Map<RouteRef, string>;
private readonly routeParents: Map<RouteRef, RouteRef | undefined>;
private readonly routeObjects: BackstageRouteObject[];
private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;
private readonly appBasePath: string; // base path without a trailing slash
private readonly routeAliasResolver: RouteAliasResolver;
private readonly routeRefsById: Map<string, RouteRef | SubRouteRef>;
constructor(
private readonly routePaths: Map<RouteRef, string>,
private readonly routeParents: Map<RouteRef, RouteRef | undefined>,
private readonly routeObjects: BackstageRouteObject[],
private readonly routeBindings: Map<
ExternalRouteRef,
RouteRef | SubRouteRef
>,
private readonly appBasePath: string, // base path without a trailing slash
private readonly routeAliasResolver: RouteAliasResolver,
private readonly routeRefsById: Map<string, RouteRef | SubRouteRef>,
) {}
routePaths: Map<RouteRef, string>,
routeParents: Map<RouteRef, RouteRef | undefined>,
routeObjects: BackstageRouteObject[],
routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,
appBasePath: string, // base path without a trailing slash
routeAliasResolver: RouteAliasResolver,
routeRefsById: Map<string, RouteRef | SubRouteRef>,
) {
this.routePaths = routePaths;
this.routeParents = routeParents;
this.routeObjects = routeObjects;
this.routeBindings = routeBindings;
this.appBasePath = appBasePath;
this.routeAliasResolver = routeAliasResolver;
this.routeRefsById = routeRefsById;
}
resolve<TParams extends AnyRouteRefParams>(
anyRouteRef:
@@ -115,11 +115,13 @@ function deduplicateFeatures(
// Helps delay callers from reaching out to the API before the app tree has been materialized
class AppTreeApiProxy implements AppTreeApi {
#routeInfo?: RouteInfo;
private readonly tree: AppTree;
private readonly appBasePath: string;
constructor(
private readonly tree: AppTree,
private readonly appBasePath: string,
) {}
constructor(tree: AppTree, appBasePath: string) {
this.tree = tree;
this.appBasePath = appBasePath;
}
private checkIfInitialized() {
if (!this.#routeInfo) {
@@ -163,13 +165,16 @@ class RouteResolutionApiProxy implements RouteResolutionApi {
#delegate: RouteResolutionApi | undefined;
#routeObjects: BackstageRouteObject[] | undefined;
private readonly routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>;
private readonly appBasePath: string;
constructor(
private readonly routeBindings: Map<
ExternalRouteRef,
RouteRef | SubRouteRef
>,
private readonly appBasePath: string,
) {}
routeBindings: Map<ExternalRouteRef, RouteRef | SubRouteRef>,
appBasePath: string,
) {
this.routeBindings = routeBindings;
this.appBasePath = appBasePath;
}
resolve<TParams extends AnyRouteRefParams>(
anyRouteRef:
@@ -65,13 +65,18 @@ const globalEvents = getOrCreateGlobalSingleton<TempGlobalEvents>(
export const routableExtensionRenderedEvent = '_ROUTABLE-EXTENSION-RENDERED';
export class Tracker implements AnalyticsTracker {
private readonly analyticsApi: AnalyticsApi;
private context: AnalyticsContextValue;
constructor(
private readonly analyticsApi: AnalyticsApi,
private context: AnalyticsContextValue = {
analyticsApi: AnalyticsApi,
context: AnalyticsContextValue = {
pluginId: 'root',
extensionId: 'App',
},
) {
this.analyticsApi = analyticsApi;
this.context = context;
// Only register a single beforeunload event across all trackers.
if (!globalEvents.beforeUnloadRegistered) {
// Before the page unloads, attempt to capture any deferred navigation
@@ -71,13 +71,17 @@ class ExternalRouteRefImpl
implements InternalExternalRouteRef
{
readonly $$type = '@backstage/ExternalRouteRef' as any;
readonly params: string[];
readonly defaultTarget: string | undefined;
constructor(
readonly params: string[] = [],
readonly defaultTarget: string | undefined,
params: string[] = [],
defaultTarget: string | undefined,
creationSite: string,
) {
super(params, creationSite);
this.params = params;
this.defaultTarget = defaultTarget;
}
getDefaultTarget() {
@@ -199,14 +199,22 @@ export class DefaultAwsCredentialsManager implements AwsCredentialsManager {
);
}
private readonly accountCredentialProviders: Map<
string,
AwsCredentialProvider
>;
private readonly accountDefaults: AwsIntegrationDefaultAccountConfig;
private readonly mainAccountCredentialProvider: AwsCredentialProvider;
private constructor(
private readonly accountCredentialProviders: Map<
string,
AwsCredentialProvider
>,
private readonly accountDefaults: AwsIntegrationDefaultAccountConfig,
private readonly mainAccountCredentialProvider: AwsCredentialProvider,
) {}
accountCredentialProviders: Map<string, AwsCredentialProvider>,
accountDefaults: AwsIntegrationDefaultAccountConfig,
mainAccountCredentialProvider: AwsCredentialProvider,
) {
this.accountCredentialProviders = accountCredentialProviders;
this.accountDefaults = accountDefaults;
this.mainAccountCredentialProvider = mainAccountCredentialProvider;
}
/**
* Returns an {@link AwsCredentialProvider} for a given AWS account.
@@ -279,10 +279,16 @@ export class SingleInstanceGithubCredentialsProvider
);
};
private readonly githubAppCredentialsMux: GithubAppCredentialsMux;
private readonly token?: string;
private constructor(
private readonly githubAppCredentialsMux: GithubAppCredentialsMux,
private readonly token?: string,
) {}
githubAppCredentialsMux: GithubAppCredentialsMux,
token?: string,
) {
this.githubAppCredentialsMux = githubAppCredentialsMux;
this.token = token;
}
/**
* Returns {@link GithubCredentials} for a given URL.
@@ -41,12 +41,19 @@ const cacheEntrySchema = z.object({
export class PackageDocsCache {
// A map of package directory to package hash.
private keyCache: Map<string, string>;
private readonly lockfile: Lockfile;
// A map of package directory to cache entry.
private readonly cache: Map<string, CacheEntry>;
private readonly baseDirectory: string;
constructor(
private readonly lockfile: Lockfile,
// A map of package directory to cache entry.
private readonly cache: Map<string, CacheEntry>,
private readonly baseDirectory: string,
lockfile: Lockfile,
cache: Map<string, CacheEntry>,
baseDirectory: string,
) {
this.lockfile = lockfile;
this.cache = cache;
this.baseDirectory = baseDirectory;
this.keyCache = new Map();
}
static async loadAsync(baseDirectory: string, lockfile: Lockfile) {
@@ -66,14 +66,28 @@ export class AuthHelper {
);
}
private readonly teamName: string;
private readonly serviceTokens: ServiceToken[];
private readonly jwtHeaderName: string;
private readonly authorizationCookieName: string;
private readonly keySet: ReturnType<typeof createRemoteJWKSet>;
private readonly cache?: CacheService;
private constructor(
private readonly teamName: string,
private readonly serviceTokens: ServiceToken[],
private readonly jwtHeaderName: string,
private readonly authorizationCookieName: string,
private readonly keySet: ReturnType<typeof createRemoteJWKSet>,
private readonly cache?: CacheService,
) {}
teamName: string,
serviceTokens: ServiceToken[],
jwtHeaderName: string,
authorizationCookieName: string,
keySet: ReturnType<typeof createRemoteJWKSet>,
cache?: CacheService,
) {
this.teamName = teamName;
this.serviceTokens = serviceTokens;
this.jwtHeaderName = jwtHeaderName;
this.authorizationCookieName = authorizationCookieName;
this.keySet = keySet;
this.cache = cache;
}
async authenticate(req: express.Request): Promise<CloudflareAccessResult> {
// JWTs generated by Access are available in a request header as
@@ -49,11 +49,15 @@ export class FirestoreKeyStore implements KeyStore {
);
}
private constructor(
private readonly database: Firestore,
private readonly path: string,
private readonly timeout: number,
) {}
private readonly database: Firestore;
private readonly path: string;
private readonly timeout: number;
private constructor(database: Firestore, path: string, timeout: number) {
this.database = database;
this.path = path;
this.timeout = timeout;
}
static async verifyConnection(
keyStore: FirestoreKeyStore,
@@ -70,15 +70,31 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
);
}
public readonly logger: LoggerService;
public readonly tokenIssuer: TokenIssuer;
public readonly catalogIdentityClient: CatalogIdentityClient;
private readonly catalog: CatalogService;
private readonly auth: AuthService;
private readonly userInfo: UserInfoDatabase;
private readonly ownershipResolver?: AuthOwnershipResolver;
private constructor(
public readonly logger: LoggerService,
public readonly tokenIssuer: TokenIssuer,
public readonly catalogIdentityClient: CatalogIdentityClient,
private readonly catalog: CatalogService,
private readonly auth: AuthService,
private readonly userInfo: UserInfoDatabase,
private readonly ownershipResolver?: AuthOwnershipResolver,
) {}
logger: LoggerService,
tokenIssuer: TokenIssuer,
catalogIdentityClient: CatalogIdentityClient,
catalog: CatalogService,
auth: AuthService,
userInfo: UserInfoDatabase,
ownershipResolver?: AuthOwnershipResolver,
) {
this.logger = logger;
this.tokenIssuer = tokenIssuer;
this.catalogIdentityClient = catalogIdentityClient;
this.catalog = catalog;
this.auth = auth;
this.userInfo = userInfo;
this.ownershipResolver = ownershipResolver;
}
async issueToken(params: TokenParams) {
const { sub, ent = [sub], ...additionalClaims } = params.claims;
+21 -7
View File
@@ -28,14 +28,28 @@ import { OidcDatabase } from '../database/OidcDatabase';
import { json } from 'express';
export class OidcRouter {
private readonly oidc: OidcService;
private readonly logger: LoggerService;
private readonly auth: AuthService;
private readonly appUrl: string;
private readonly httpAuth: HttpAuthService;
private readonly config: RootConfigService;
private constructor(
private readonly oidc: OidcService,
private readonly logger: LoggerService,
private readonly auth: AuthService,
private readonly appUrl: string,
private readonly httpAuth: HttpAuthService,
private readonly config: RootConfigService,
) {}
oidc: OidcService,
logger: LoggerService,
auth: AuthService,
appUrl: string,
httpAuth: HttpAuthService,
config: RootConfigService,
) {
this.oidc = oidc;
this.logger = logger;
this.auth = auth;
this.appUrl = appUrl;
this.httpAuth = httpAuth;
this.config = config;
}
static create(options: {
auth: AuthService;
@@ -28,14 +28,28 @@ import { DateTime } from 'luxon';
import matcher from 'matcher';
export class OidcService {
private readonly auth: AuthService;
private readonly tokenIssuer: TokenIssuer;
private readonly baseUrl: string;
private readonly userInfo: UserInfoDatabase;
private readonly oidc: OidcDatabase;
private readonly config: RootConfigService;
private constructor(
private readonly auth: AuthService,
private readonly tokenIssuer: TokenIssuer,
private readonly baseUrl: string,
private readonly userInfo: UserInfoDatabase,
private readonly oidc: OidcDatabase,
private readonly config: RootConfigService,
) {}
auth: AuthService,
tokenIssuer: TokenIssuer,
baseUrl: string,
userInfo: UserInfoDatabase,
oidc: OidcDatabase,
config: RootConfigService,
) {
this.auth = auth;
this.tokenIssuer = tokenIssuer;
this.baseUrl = baseUrl;
this.userInfo = userInfo;
this.oidc = oidc;
this.config = config;
}
static create(options: {
auth: AuthService;
@@ -78,13 +78,22 @@ export class CookieScopeManager {
);
}
private readonly scopeTransform: (
requested: Iterable<string>,
granted: Iterable<string>,
) => string;
private readonly cookieManager?: OAuthCookieManager;
private constructor(
private readonly scopeTransform: (
scopeTransform: (
requested: Iterable<string>,
granted: Iterable<string>,
) => string,
private readonly cookieManager?: OAuthCookieManager,
) {}
cookieManager?: OAuthCookieManager,
) {
this.scopeTransform = scopeTransform;
this.cookieManager = cookieManager;
}
async start(
req: express.Request,
@@ -27,11 +27,19 @@ export class WithPagination<
TPage extends Models.Paginated<TResultItem>,
TResultItem,
> {
private readonly createUrl: (options: PaginationOptions) => URL;
private readonly fetch: (url: URL) => Promise<TPage>;
private readonly pagelen?: number;
constructor(
private readonly createUrl: (options: PaginationOptions) => URL,
private readonly fetch: (url: URL) => Promise<TPage>,
private readonly pagelen?: number,
) {}
createUrl: (options: PaginationOptions) => URL,
fetch: (url: URL) => Promise<TPage>,
pagelen?: number,
) {
this.createUrl = createUrl;
this.fetch = fetch;
this.pagelen = pagelen;
}
getPage(options?: PaginationOptions): Promise<TPage> {
const opts = { page: 1, pagelen: this.pagelen ?? 100, ...options };
@@ -105,13 +105,20 @@ export class AwsS3EntityProvider implements EntityProvider {
});
}
private readonly config: AwsS3Config;
private readonly integration: AwsS3Integration;
private readonly awsCredentialsManager: AwsCredentialsManager;
private constructor(
private readonly config: AwsS3Config,
private readonly integration: AwsS3Integration,
private readonly awsCredentialsManager: AwsCredentialsManager,
config: AwsS3Config,
integration: AwsS3Integration,
awsCredentialsManager: AwsCredentialsManager,
logger: LoggerService,
taskRunner: SchedulerServiceTaskRunner,
) {
this.config = config;
this.integration = integration;
this.awsCredentialsManager = awsCredentialsManager;
this.logger = logger.child({
target: this.getProviderName(),
});
@@ -105,13 +105,20 @@ export class AzureBlobStorageEntityProvider implements EntityProvider {
);
});
}
private readonly config: AzureBlobStorageConfig;
private readonly integration: AzureBlobStorageIntergation;
private readonly credentialsProvider: DefaultAzureCredentialsManager;
private constructor(
private readonly config: AzureBlobStorageConfig,
private readonly integration: AzureBlobStorageIntergation,
private readonly credentialsProvider: DefaultAzureCredentialsManager,
config: AzureBlobStorageConfig,
integration: AzureBlobStorageIntergation,
credentialsProvider: DefaultAzureCredentialsManager,
logger: LoggerService,
schedule: SchedulerServiceTaskRunner,
) {
this.config = config;
this.integration = integration;
this.credentialsProvider = credentialsProvider;
this.logger = logger.child({ target: this.getProviderName() });
this.scheduleFn = this.createScheduleFn(schedule);
}
@@ -97,13 +97,20 @@ export class AzureDevOpsEntityProvider implements EntityProvider {
});
}
private readonly config: AzureDevOpsConfig;
private readonly integration: AzureIntegration;
private readonly credentialsProvider: AzureDevOpsCredentialsProvider;
private constructor(
private readonly config: AzureDevOpsConfig,
private readonly integration: AzureIntegration,
private readonly credentialsProvider: AzureDevOpsCredentialsProvider,
config: AzureDevOpsConfig,
integration: AzureIntegration,
credentialsProvider: AzureDevOpsCredentialsProvider,
logger: LoggerService,
taskRunner: SchedulerServiceTaskRunner,
) {
this.config = config;
this.integration = integration;
this.credentialsProvider = credentialsProvider;
this.logger = logger.child({
target: this.getProviderName(),
});
@@ -171,14 +171,22 @@ const formatDefinition = (
export class InternalOpenApiDocumentationProvider implements EntityProvider {
private connection?: EntityProviderConnection;
private readonly scheduleFn: () => Promise<void>;
public readonly config: Config;
public readonly discovery: DiscoveryService;
public readonly logger: LoggerService;
public readonly auth: AuthService;
constructor(
public readonly config: Config,
public readonly discovery: DiscoveryService,
public readonly logger: LoggerService,
public readonly auth: AuthService,
config: Config,
discovery: DiscoveryService,
logger: LoggerService,
auth: AuthService,
taskRunner: SchedulerServiceTaskRunner,
) {
this.config = config;
this.discovery = discovery;
this.logger = logger;
this.auth = auth;
this.scheduleFn = this.createScheduleFn(taskRunner);
}
@@ -89,10 +89,13 @@ export class LdapClient {
});
}
constructor(
private readonly client: Client,
private readonly logger: LoggerService,
) {}
private readonly client: Client;
private readonly logger: LoggerService;
constructor(client: Client, logger: LoggerService) {
this.client = client;
this.logger = logger;
}
/**
* Performs an LDAP search operation.
@@ -107,10 +107,13 @@ export class MicrosoftGraphClient {
* @param tokenCredential - instance of `TokenCredential` that is used to acquire token for Graph API calls
*
*/
constructor(
private readonly baseUrl: string,
private readonly tokenCredential: TokenCredential,
) {}
private readonly baseUrl: string;
private readonly tokenCredential: TokenCredential;
constructor(baseUrl: string, tokenCredential: TokenCredential) {
this.baseUrl = baseUrl;
this.tokenCredential = tokenCredential;
}
/**
* Get a collection of resource from Graph API and
@@ -289,17 +289,27 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
return result;
}
constructor(
private options: {
id: string;
provider: MicrosoftGraphProviderConfig;
logger: LoggerService;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
providerConfigTransformer?: ProviderConfigTransformer;
},
) {}
private options: {
id: string;
provider: MicrosoftGraphProviderConfig;
logger: LoggerService;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
providerConfigTransformer?: ProviderConfigTransformer;
};
constructor(options: {
id: string;
provider: MicrosoftGraphProviderConfig;
logger: LoggerService;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
providerConfigTransformer?: ProviderConfigTransformer;
}) {
this.options = options;
}
/** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */
getProviderName() {
@@ -46,12 +46,19 @@ export class UnprocessedEntitiesModule {
private readonly httpAuth: HttpAuthService;
private readonly database: Knex;
private readonly router: Pick<HttpRouterService, 'use'>;
private readonly permissions: PermissionsService;
private constructor(
private readonly database: Knex,
private readonly router: Pick<HttpRouterService, 'use'>,
private readonly permissions: PermissionsService,
database: Knex,
router: Pick<HttpRouterService, 'use'>,
permissions: PermissionsService,
httpAuth: HttpAuthService,
) {
this.database = database;
this.router = router;
this.permissions = permissions;
this.moduleRouter = Router();
this.router.use(this.moduleRouter);
@@ -55,14 +55,20 @@ import { LoggerService } from '@backstage/backend-plugin-api';
const BATCH_SIZE = 50;
export class DefaultProcessingDatabase implements ProcessingDatabase {
constructor(
private readonly options: {
database: Knex;
logger: LoggerService;
refreshInterval: ProcessingIntervalFunction;
events: EventsService;
},
) {
private readonly options: {
database: Knex;
logger: LoggerService;
refreshInterval: ProcessingIntervalFunction;
events: EventsService;
};
constructor(options: {
database: Knex;
logger: LoggerService;
refreshInterval: ProcessingIntervalFunction;
events: EventsService;
}) {
this.options = options;
initDatabaseMetrics(options.database);
}
@@ -45,12 +45,14 @@ import {
const BATCH_SIZE = 50;
export class DefaultProviderDatabase implements ProviderDatabase {
constructor(
private readonly options: {
database: Knex;
logger: LoggerService;
},
) {}
private readonly options: {
database: Knex;
logger: LoggerService;
};
constructor(options: { database: Knex; logger: LoggerService }) {
this.options = options;
}
async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> {
try {
@@ -166,7 +166,11 @@ export class DefaultCatalogRulesEnforcer implements CatalogRulesEnforcer {
return new DefaultCatalogRulesEnforcer(rules);
}
constructor(private readonly rules: CatalogRule[]) {}
private readonly rules: CatalogRule[];
constructor(rules: CatalogRule[]) {
this.rules = rules;
}
/**
* Checks whether a specific entity/location combination is allowed
@@ -87,16 +87,25 @@ function addProcessorAttributes(
export class DefaultCatalogProcessingOrchestrator
implements CatalogProcessingOrchestrator
{
constructor(
private readonly options: {
processors: CatalogProcessor[];
integrations: ScmIntegrationRegistry;
logger: LoggerService;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
},
) {}
private readonly options: {
processors: CatalogProcessor[];
integrations: ScmIntegrationRegistry;
logger: LoggerService;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
};
constructor(options: {
processors: CatalogProcessor[];
integrations: ScmIntegrationRegistry;
logger: LoggerService;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
}) {
this.options = options;
}
async process(
request: EntityProcessingRequest,
@@ -24,7 +24,11 @@ import { isObject } from './util';
class SingleProcessorSubCache implements CatalogProcessorCache {
private newState?: JsonObject;
constructor(private readonly existingState?: JsonObject) {}
private readonly existingState?: JsonObject;
constructor(existingState?: JsonObject) {
this.existingState = existingState;
}
async get<ItemType extends JsonValue>(
key: string,
@@ -52,7 +56,11 @@ class SingleProcessorCache implements CatalogProcessorCache {
private newState?: JsonObject;
private subCaches: Map<string, SingleProcessorSubCache> = new Map();
constructor(private readonly existingState?: JsonObject) {}
private readonly existingState?: JsonObject;
constructor(existingState?: JsonObject) {
this.existingState = existingState;
}
async get<ItemType extends JsonValue>(
key: string,
@@ -99,7 +107,11 @@ class SingleProcessorCache implements CatalogProcessorCache {
export class ProcessorCacheManager {
private caches = new Map<string, SingleProcessorCache>();
constructor(private readonly existingState: JsonObject) {}
private readonly existingState: JsonObject;
constructor(existingState: JsonObject) {
this.existingState = existingState;
}
forProcessor(
processor: CatalogProcessor,
@@ -47,10 +47,13 @@ export class ProcessorOutputCollector {
private readonly refreshKeys = new Array<RefreshKeyData>();
private done = false;
constructor(
private readonly logger: LoggerService,
private readonly parentEntity: Entity,
) {}
private readonly logger: LoggerService;
private readonly parentEntity: Entity;
constructor(logger: LoggerService, parentEntity: Entity) {
this.logger = logger;
this.parentEntity = parentEntity;
}
generic(): (i: CatalogProcessorResult) => void {
return i => this.receive(this.logger, i);
@@ -29,13 +29,14 @@ import {
class Connection implements EntityProviderConnection {
readonly validateEntityEnvelope = entityEnvelopeSchemaValidator();
private readonly config: {
id: string;
providerDatabase: ProviderDatabase;
};
constructor(
private readonly config: {
id: string;
providerDatabase: ProviderDatabase;
},
) {}
constructor(config: { id: string; providerDatabase: ProviderDatabase }) {
this.config = config;
}
async applyMutation(mutation: EntityProviderMutation): Promise<void> {
const db = this.config.providerDatabase;
@@ -34,11 +34,13 @@ import {
const commitHashRegExp = /\b[0-9a-f]{40,}\b/;
/** @public */
export class AnnotateLocationEntityProcessor implements CatalogProcessor {
constructor(
private readonly options: {
integrations: ScmIntegrationRegistry;
},
) {}
private readonly options: {
integrations: ScmIntegrationRegistry;
};
constructor(options: { integrations: ScmIntegrationRegistry }) {
this.options = options;
}
getProcessorName(): string {
return 'AnnotateLocationEntityProcessor';
@@ -31,12 +31,17 @@ const AZURE_ACTIONS_ANNOTATION = 'dev.azure.com/project-repo';
/** @public */
export class AnnotateScmSlugEntityProcessor implements CatalogProcessor {
constructor(
private readonly opts: {
scmIntegrationRegistry: ScmIntegrationRegistry;
kinds?: string[];
},
) {}
private readonly opts: {
scmIntegrationRegistry: ScmIntegrationRegistry;
kinds?: string[];
};
constructor(opts: {
scmIntegrationRegistry: ScmIntegrationRegistry;
kinds?: string[];
}) {
this.opts = opts;
}
getProcessorName(): string {
return 'AnnotateScmSlugEntityProcessor';
@@ -41,7 +41,11 @@ export type PlaceholderProcessorOptions = {
* @public
*/
export class PlaceholderProcessor implements CatalogProcessor {
constructor(private readonly options: PlaceholderProcessorOptions) {}
private readonly options: PlaceholderProcessorOptions;
constructor(options: PlaceholderProcessorOptions) {
this.options = options;
}
getProcessorName(): string {
return 'PlaceholderProcessor';
@@ -46,13 +46,13 @@ export class UrlReaderProcessor implements CatalogProcessor {
// This limiter is used for only consuming a limited number of read streams
// concurrently.
#limiter: Limit;
private readonly options: {
reader: UrlReaderService;
logger: LoggerService;
};
constructor(
private readonly options: {
reader: UrlReaderService;
logger: LoggerService;
},
) {
constructor(options: { reader: UrlReaderService; logger: LoggerService }) {
this.options = options;
this.#limiter = limiterFactory(5);
}

Some files were not shown because too many files have changed in this diff Show More