@backstage/backend-defaults 0.15.1 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +50 -6
  2. package/config.d.ts +26 -0
  3. package/dist/PackageDiscoveryService.cjs.js +1 -1
  4. package/dist/PackageDiscoveryService.cjs.js.map +1 -1
  5. package/dist/entrypoints/auth/helpers.cjs.js +2 -2
  6. package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
  7. package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js +2 -2
  8. package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
  9. package/dist/entrypoints/cache/CacheClient.cjs.js +2 -2
  10. package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
  11. package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js +2 -2
  12. package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js.map +1 -1
  13. package/dist/entrypoints/database/connectors/postgres.cjs.js +191 -157
  14. package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
  15. package/dist/entrypoints/database/connectors/sqlite3.cjs.js +1 -1
  16. package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
  17. package/dist/entrypoints/discovery/SrvResolvers.cjs.js +2 -2
  18. package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -1
  19. package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -1
  20. package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +4 -4
  21. package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js +2 -2
  22. package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
  23. package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js +2 -2
  24. package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
  25. package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js +1 -1
  26. package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
  27. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +4 -4
  28. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
  29. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +6 -6
  30. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
  31. package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js +3 -3
  32. package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
  33. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +1 -1
  34. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
  35. package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js +2 -2
  36. package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
  37. package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js +2 -2
  38. package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
  39. package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js +2 -2
  40. package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
  41. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +2 -2
  42. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
  43. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +1 -1
  44. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
  45. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +3 -3
  46. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
  47. package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js +2 -2
  48. package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
  49. package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js +1 -1
  50. package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
  51. package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js +25 -7
  52. package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
  53. package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js +30 -13
  54. package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
  55. package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js +1 -1
  56. package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
  57. package/dist/entrypoints/urlReader/lib/tree/util.cjs.js +3 -3
  58. package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
  59. package/dist/entrypoints/urlReader/lib/util.cjs.js +3 -3
  60. package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
  61. package/dist/httpRouter.cjs.js +2 -0
  62. package/dist/httpRouter.cjs.js.map +1 -1
  63. package/dist/httpRouter.d.ts +10 -1
  64. package/dist/package.json.cjs.js +1 -1
  65. package/dist/rootHttpRouter.d.ts +2 -3
  66. package/dist/urlReader.d.ts +1 -1
  67. package/package.json +16 -15
  68. package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js +0 -12
  69. package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite3.cjs.js","sources":["../../../../src/entrypoints/database/connectors/sqlite3.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 { DevDataStore } from '@backstage/backend-dev-utils';\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config, ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { ensureDirSync } from 'fs-extra';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport path from 'path';\nimport { Connector } from '../types';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\n\n/**\n * Creates a knex SQLite3 database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport function createSqliteDatabaseClient(\n pluginId: string,\n dbConfig: Config,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n overrides?: Knex.Config,\n) {\n const knexConfig = buildSqliteDatabaseConfig(dbConfig, overrides);\n const connConfig = knexConfig.connection as Knex.Sqlite3ConnectionConfig;\n\n const filename = connConfig.filename ?? ':memory:';\n\n // If storage on disk is used, ensure that the directory exists\n if (filename !== ':memory:') {\n const directory = path.dirname(filename);\n ensureDirSync(directory);\n }\n\n let database: Knex;\n\n if (deps && filename === ':memory:') {\n // The dev store is used during watch mode to store and restore the database\n // across reloads. It is only available when running the backend through\n // `backstage-cli package start`.\n const devStore = DevDataStore.get();\n\n if (devStore) {\n const dataKey = `sqlite3-db-${pluginId}`;\n\n const connectionLoader = async () => {\n // If seed data is available, use it tconnectionLoader restore the database\n const { data: seedData } = await devStore.load(dataKey);\n\n return {\n ...(knexConfig.connection as Knex.Sqlite3ConnectionConfig),\n filename: seedData ?? ':memory:',\n };\n };\n\n database = knexFactory({\n ...knexConfig,\n connection: Object.assign(connectionLoader, {\n // This is a workaround for the knex SQLite driver always warning when using a config loader\n filename: ':memory:',\n }),\n });\n\n // If the dev store is available we save the database state on shutdown\n deps.lifecycle.addShutdownHook(async () => {\n const connection = await database.client.acquireConnection();\n const data = connection.serialize();\n await devStore.save(dataKey, data);\n });\n } else {\n database = knexFactory(knexConfig);\n }\n } else {\n database = knexFactory(knexConfig);\n }\n\n database.client.pool.on('createSuccess', (_eventId: any, resource: any) => {\n resource.run('PRAGMA foreign_keys = ON', () => {});\n });\n\n return database;\n}\n\n/**\n * Builds a knex SQLite3 connection config\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport function buildSqliteDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n): Knex.Config {\n const baseConfig = dbConfig.get<Knex.Config>();\n\n // Normalize config to always contain a connection object\n if (typeof baseConfig.connection === 'string') {\n baseConfig.connection = { filename: baseConfig.connection };\n }\n if (overrides && typeof overrides.connection === 'string') {\n overrides.connection = { filename: overrides.connection };\n }\n\n const config: Knex.Config = mergeDatabaseConfig(\n {\n connection: {},\n },\n baseConfig,\n {\n useNullAsDefault: true,\n },\n overrides,\n );\n\n return config;\n}\n\n/**\n * Provides a partial knex SQLite3 config to override database name.\n */\nexport function createSqliteNameOverride(name: string): Partial<Knex.Config> {\n return {\n connection: parseSqliteConnectionString(name),\n };\n}\n\n/**\n * Produces a partial knex SQLite3 connection config with database name.\n */\nexport function parseSqliteConnectionString(\n name: string,\n): Knex.Sqlite3ConnectionConfig {\n return {\n filename: name,\n };\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parseSqliteConnectionString(connection as string)\n : connection;\n}\n\nexport class Sqlite3Connector implements Connector {\n private readonly config: Config;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n async getClient(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginConfig = new ConfigReader(\n this.getConfigForPlugin(pluginId) as JsonObject,\n );\n\n const pluginDivisionMode = this.getPluginDivisionModeConfig();\n if (pluginDivisionMode !== 'database') {\n throw new Error(\n `The SQLite driver does not support plugin division mode '${pluginDivisionMode}'`,\n );\n }\n\n const databaseClientOverrides = mergeDatabaseConfig(\n {},\n this.getDatabaseOverrides(pluginId),\n );\n\n const client = createSqliteDatabaseClient(\n pluginId,\n pluginConfig,\n deps,\n databaseClientOverrides,\n );\n\n return client;\n }\n\n /**\n * Provides the canonical database name for a given plugin.\n *\n * This method provides the effective database name which is determined using global\n * and plugin specific database config. If no explicit database name is configured\n * and `pluginDivisionMode` is not `schema`, this method will provide a generated name\n * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is\n * `schema`, it will fallback to using the default database for the knex instance.\n *\n * @param pluginId - Lookup the database name for given plugin\n * @returns String representing the plugin's database name\n */\n private getDatabaseName(pluginId: string): string | undefined {\n const connection = this.getConnectionConfig(pluginId);\n\n const sqliteFilename: string | undefined = (\n connection as Knex.Sqlite3ConnectionConfig\n ).filename;\n\n if (sqliteFilename === ':memory:') {\n return sqliteFilename;\n }\n\n const sqliteDirectory =\n (connection as { directory?: string }).directory ?? '.';\n\n return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`);\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n private getRoleConfig(pluginId: string): string | undefined {\n return (\n this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n this.config.getOptionalString('role')\n );\n }\n\n /**\n * Provides the knexConfig which should be used for a given plugin.\n *\n * @param pluginId - Plugin to get the knexConfig for\n * @returns The merged knexConfig value or undefined if it isn't specified\n */\n private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {\n const pluginConfig = this.config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n\n const baseConfig = this.config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n\n return merge(baseConfig, pluginConfig);\n }\n\n private getPluginDivisionModeConfig(): string {\n return this.config.getOptionalString('pluginDivisionMode') ?? 'database';\n }\n\n /**\n * Provides a Knex connection plugin config by combining base and plugin\n * config.\n *\n * This method provides a baseConfig for a plugin database connector. If the\n * client type has not been overridden, the global connection config will be\n * included with plugin specific config as the base. Values from the plugin\n * connection take precedence over the base. Base database name is omitted for\n * all supported databases excluding SQLite unless `pluginDivisionMode` is set\n * to `schema`.\n */\n private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig {\n const { client, overridden } = this.getClientType(pluginId);\n\n let baseConnection = normalizeConnection(this.config.get('connection'));\n\n if (\n client.includes('sqlite3') &&\n 'filename' in baseConnection &&\n baseConnection.filename !== ':memory:'\n ) {\n throw new Error(\n '`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.',\n );\n }\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The\n // `database` property from the base connection is omitted unless `pluginDivisionMode`\n // is set to `schema`. SQLite3's `filename` property is an exception as this is used as a\n // directory elsewhere so we preserve `filename`.\n if (this.getPluginDivisionModeConfig() !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // get and normalize optional plugin specific database connection\n const connection = normalizeConnection(\n this.config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n return {\n // include base connection if client type has not been overridden\n ...(overridden ? {} : baseConnection),\n ...connection,\n } as Knex.StaticConnectionConfig;\n }\n\n /**\n * Provides a Knex database config for a given plugin.\n *\n * This method provides a Knex configuration object along with the plugin's\n * client type.\n *\n * @param pluginId - The plugin that the database config should correspond with\n */\n private getConfigForPlugin(pluginId: string): Knex.Config {\n const { client } = this.getClientType(pluginId);\n const role = this.getRoleConfig(pluginId);\n\n return {\n ...this.getAdditionalKnexConfig(pluginId),\n client,\n connection: this.getConnectionConfig(pluginId),\n ...(role && { role }),\n };\n }\n\n /**\n * Provides a partial `Knex.Config`• database name override for a given plugin.\n *\n * @param pluginId - Target plugin to get database name override\n * @returns Partial `Knex.Config` with database name override\n */\n private getDatabaseOverrides(pluginId: string): Knex.Config {\n const databaseName = this.getDatabaseName(pluginId);\n return databaseName ? createSqliteNameOverride(databaseName) : {};\n }\n}\n"],"names":["path","ensureDirSync","DevDataStore","knexFactory","mergeDatabaseConfig","ConfigReader","merge","omit"],"mappings":"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"}
1
+ {"version":3,"file":"sqlite3.cjs.js","sources":["../../../../src/entrypoints/database/connectors/sqlite3.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 { DevDataStore } from '@backstage/backend-dev-utils';\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config, ConfigReader } from '@backstage/config';\nimport { JsonObject } from '@backstage/types';\nimport { ensureDirSync } from 'fs-extra';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport path from 'node:path';\nimport { Connector } from '../types';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\n\n/**\n * Creates a knex SQLite3 database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport function createSqliteDatabaseClient(\n pluginId: string,\n dbConfig: Config,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n overrides?: Knex.Config,\n) {\n const knexConfig = buildSqliteDatabaseConfig(dbConfig, overrides);\n const connConfig = knexConfig.connection as Knex.Sqlite3ConnectionConfig;\n\n const filename = connConfig.filename ?? ':memory:';\n\n // If storage on disk is used, ensure that the directory exists\n if (filename !== ':memory:') {\n const directory = path.dirname(filename);\n ensureDirSync(directory);\n }\n\n let database: Knex;\n\n if (deps && filename === ':memory:') {\n // The dev store is used during watch mode to store and restore the database\n // across reloads. It is only available when running the backend through\n // `backstage-cli package start`.\n const devStore = DevDataStore.get();\n\n if (devStore) {\n const dataKey = `sqlite3-db-${pluginId}`;\n\n const connectionLoader = async () => {\n // If seed data is available, use it tconnectionLoader restore the database\n const { data: seedData } = await devStore.load(dataKey);\n\n return {\n ...(knexConfig.connection as Knex.Sqlite3ConnectionConfig),\n filename: seedData ?? ':memory:',\n };\n };\n\n database = knexFactory({\n ...knexConfig,\n connection: Object.assign(connectionLoader, {\n // This is a workaround for the knex SQLite driver always warning when using a config loader\n filename: ':memory:',\n }),\n });\n\n // If the dev store is available we save the database state on shutdown\n deps.lifecycle.addShutdownHook(async () => {\n const connection = await database.client.acquireConnection();\n const data = connection.serialize();\n await devStore.save(dataKey, data);\n });\n } else {\n database = knexFactory(knexConfig);\n }\n } else {\n database = knexFactory(knexConfig);\n }\n\n database.client.pool.on('createSuccess', (_eventId: any, resource: any) => {\n resource.run('PRAGMA foreign_keys = ON', () => {});\n });\n\n return database;\n}\n\n/**\n * Builds a knex SQLite3 connection config\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport function buildSqliteDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n): Knex.Config {\n const baseConfig = dbConfig.get<Knex.Config>();\n\n // Normalize config to always contain a connection object\n if (typeof baseConfig.connection === 'string') {\n baseConfig.connection = { filename: baseConfig.connection };\n }\n if (overrides && typeof overrides.connection === 'string') {\n overrides.connection = { filename: overrides.connection };\n }\n\n const config: Knex.Config = mergeDatabaseConfig(\n {\n connection: {},\n },\n baseConfig,\n {\n useNullAsDefault: true,\n },\n overrides,\n );\n\n return config;\n}\n\n/**\n * Provides a partial knex SQLite3 config to override database name.\n */\nexport function createSqliteNameOverride(name: string): Partial<Knex.Config> {\n return {\n connection: parseSqliteConnectionString(name),\n };\n}\n\n/**\n * Produces a partial knex SQLite3 connection config with database name.\n */\nexport function parseSqliteConnectionString(\n name: string,\n): Knex.Sqlite3ConnectionConfig {\n return {\n filename: name,\n };\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parseSqliteConnectionString(connection as string)\n : connection;\n}\n\nexport class Sqlite3Connector implements Connector {\n private readonly config: Config;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n async getClient(\n pluginId: string,\n deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginConfig = new ConfigReader(\n this.getConfigForPlugin(pluginId) as JsonObject,\n );\n\n const pluginDivisionMode = this.getPluginDivisionModeConfig();\n if (pluginDivisionMode !== 'database') {\n throw new Error(\n `The SQLite driver does not support plugin division mode '${pluginDivisionMode}'`,\n );\n }\n\n const databaseClientOverrides = mergeDatabaseConfig(\n {},\n this.getDatabaseOverrides(pluginId),\n );\n\n const client = createSqliteDatabaseClient(\n pluginId,\n pluginConfig,\n deps,\n databaseClientOverrides,\n );\n\n return client;\n }\n\n /**\n * Provides the canonical database name for a given plugin.\n *\n * This method provides the effective database name which is determined using global\n * and plugin specific database config. If no explicit database name is configured\n * and `pluginDivisionMode` is not `schema`, this method will provide a generated name\n * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is\n * `schema`, it will fallback to using the default database for the knex instance.\n *\n * @param pluginId - Lookup the database name for given plugin\n * @returns String representing the plugin's database name\n */\n private getDatabaseName(pluginId: string): string | undefined {\n const connection = this.getConnectionConfig(pluginId);\n\n const sqliteFilename: string | undefined = (\n connection as Knex.Sqlite3ConnectionConfig\n ).filename;\n\n if (sqliteFilename === ':memory:') {\n return sqliteFilename;\n }\n\n const sqliteDirectory =\n (connection as { directory?: string }).directory ?? '.';\n\n return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`);\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n private getRoleConfig(pluginId: string): string | undefined {\n return (\n this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n this.config.getOptionalString('role')\n );\n }\n\n /**\n * Provides the knexConfig which should be used for a given plugin.\n *\n * @param pluginId - Plugin to get the knexConfig for\n * @returns The merged knexConfig value or undefined if it isn't specified\n */\n private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {\n const pluginConfig = this.config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n\n const baseConfig = this.config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n\n return merge(baseConfig, pluginConfig);\n }\n\n private getPluginDivisionModeConfig(): string {\n return this.config.getOptionalString('pluginDivisionMode') ?? 'database';\n }\n\n /**\n * Provides a Knex connection plugin config by combining base and plugin\n * config.\n *\n * This method provides a baseConfig for a plugin database connector. If the\n * client type has not been overridden, the global connection config will be\n * included with plugin specific config as the base. Values from the plugin\n * connection take precedence over the base. Base database name is omitted for\n * all supported databases excluding SQLite unless `pluginDivisionMode` is set\n * to `schema`.\n */\n private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig {\n const { client, overridden } = this.getClientType(pluginId);\n\n let baseConnection = normalizeConnection(this.config.get('connection'));\n\n if (\n client.includes('sqlite3') &&\n 'filename' in baseConnection &&\n baseConnection.filename !== ':memory:'\n ) {\n throw new Error(\n '`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.',\n );\n }\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The\n // `database` property from the base connection is omitted unless `pluginDivisionMode`\n // is set to `schema`. SQLite3's `filename` property is an exception as this is used as a\n // directory elsewhere so we preserve `filename`.\n if (this.getPluginDivisionModeConfig() !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // get and normalize optional plugin specific database connection\n const connection = normalizeConnection(\n this.config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n return {\n // include base connection if client type has not been overridden\n ...(overridden ? {} : baseConnection),\n ...connection,\n } as Knex.StaticConnectionConfig;\n }\n\n /**\n * Provides a Knex database config for a given plugin.\n *\n * This method provides a Knex configuration object along with the plugin's\n * client type.\n *\n * @param pluginId - The plugin that the database config should correspond with\n */\n private getConfigForPlugin(pluginId: string): Knex.Config {\n const { client } = this.getClientType(pluginId);\n const role = this.getRoleConfig(pluginId);\n\n return {\n ...this.getAdditionalKnexConfig(pluginId),\n client,\n connection: this.getConnectionConfig(pluginId),\n ...(role && { role }),\n };\n }\n\n /**\n * Provides a partial `Knex.Config`• database name override for a given plugin.\n *\n * @param pluginId - Target plugin to get database name override\n * @returns Partial `Knex.Config` with database name override\n */\n private getDatabaseOverrides(pluginId: string): Knex.Config {\n const databaseName = this.getDatabaseName(pluginId);\n return databaseName ? createSqliteNameOverride(databaseName) : {};\n }\n}\n"],"names":["path","ensureDirSync","DevDataStore","knexFactory","mergeDatabaseConfig","ConfigReader","merge","omit"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var errors = require('@backstage/errors');
4
- var dns = require('dns');
4
+ var node_dns = require('node:dns');
5
5
 
6
6
  const PROTOCOL_SUFFIX = "+srv:";
7
7
  class SrvResolvers {
@@ -12,7 +12,7 @@ class SrvResolvers {
12
12
  this.#cache = /* @__PURE__ */ new Map();
13
13
  this.#cacheTtlMillis = options?.cacheTtlMillis ?? 1e3;
14
14
  this.#resolveSrv = options?.resolveSrv ?? ((host) => new Promise((resolve, reject) => {
15
- dns.resolveSrv(host, (err, result) => {
15
+ node_dns.resolveSrv(host, (err, result) => {
16
16
  if (err) {
17
17
  reject(err);
18
18
  } else {
@@ -1 +1 @@
1
- {"version":3,"file":"SrvResolvers.cjs.js","sources":["../../../src/entrypoints/discovery/SrvResolvers.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError, InputError, NotFoundError } from '@backstage/errors';\nimport { resolveSrv, SrvRecord } from 'dns';\n\nconst PROTOCOL_SUFFIX = '+srv:';\n\n/**\n * Helps with resolution and caching of SRV lookups.\n *\n * Supports URLs on the form `http+srv://myplugin.services.region.example.net/api/myplugin`\n */\nexport class SrvResolvers {\n readonly #cache: Map<string, Promise<SrvRecord[]>>;\n readonly #cacheTtlMillis: number;\n readonly #resolveSrv: (host: string) => Promise<SrvRecord[]>;\n\n constructor(options?: {\n resolveSrv?: (host: string) => Promise<SrvRecord[]>;\n cacheTtlMillis?: number;\n }) {\n this.#cache = new Map();\n this.#cacheTtlMillis = options?.cacheTtlMillis ?? 1000;\n this.#resolveSrv =\n options?.resolveSrv ??\n (host =>\n new Promise((resolve, reject) => {\n resolveSrv(host, (err, result) => {\n if (err) {\n reject(err);\n } else {\n resolve(result);\n }\n });\n }));\n }\n\n isSrvUrl(url: string): boolean {\n try {\n this.#parseSrvUrl(url);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get a resolver function for a given SRV form URL.\n *\n * @param url An SRV form URL, e.g. `http+srv://myplugin.services.region.example.net/api/myplugin`\n * @returns A function that returns resolved URLs, e.g. `http://1234abcd.region.example.net:8080/api/myplugin`\n */\n getResolver(url: string): () => Promise<string> {\n const { protocol, host, path } = this.#parseSrvUrl(url);\n return () =>\n this.#resolveHost(host).then(\n resolved => `${protocol}://${resolved}${path}`,\n );\n }\n\n /**\n * Attempts to parse out the relevant parts of an SRV URL.\n */\n #parseSrvUrl(url: string): { protocol: string; host: string; path: string } {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new InputError(\n `SRV resolver expected a valid URL starting with http(s)+srv:// but got '${url}'`,\n );\n }\n if (!parsedUrl.protocol?.endsWith(PROTOCOL_SUFFIX) || !parsedUrl.hostname) {\n throw new InputError(\n `SRV resolver expected a URL with protocol http(s)+srv:// but got '${url}'`,\n );\n }\n if (parsedUrl.port) {\n throw new InputError(\n `SRV resolver URLs cannot contain a port but got '${url}'`,\n );\n }\n if (parsedUrl.username || parsedUrl.password) {\n throw new InputError(\n `SRV resolver URLs cannot contain username or password but got '${url}'`,\n );\n }\n if (parsedUrl.search || parsedUrl.hash) {\n throw new InputError(\n `SRV resolver URLs cannot contain search params or a hash but got '${url}'`,\n );\n }\n\n const protocol = parsedUrl.protocol.substring(\n 0,\n parsedUrl.protocol.length - PROTOCOL_SUFFIX.length,\n );\n const host = parsedUrl.hostname;\n const path = parsedUrl.pathname.replace(/\\/+$/, '');\n\n if (!['http', 'https'].includes(protocol)) {\n throw new InputError(\n `SRV URLs must be based on http or https but got '${url}'`,\n );\n }\n\n return { protocol, host, path };\n }\n\n /**\n * Resolves a single SRV record name to a host:port string.\n */\n #resolveHost(host: string): Promise<string> {\n let records = this.#cache.get(host);\n if (!records) {\n records = this.#resolveSrv(host).then(\n result => {\n if (!result.length) {\n throw new NotFoundError(`No SRV records found for ${host}`);\n }\n return result;\n },\n err => {\n throw new ForwardedError(`Failed SRV resolution for ${host}`, err);\n },\n );\n this.#cache.set(host, records);\n setTimeout(() => {\n this.#cache.delete(host);\n }, this.#cacheTtlMillis);\n }\n\n return records.then(rs => {\n const r = this.#pickRandomRecord(rs);\n return `${r.name}:${r.port}`;\n });\n }\n\n /**\n * Among a set of records, pick one at random.\n *\n * This assumes that the set is not empty.\n *\n * Since this contract only ever returns a single record, the best it can do\n * is to pick weighted-randomly among the highest-priority records. In order\n * to be smarter than that, the caller would have to be able to make decisions\n * on the whole set of records.\n */\n #pickRandomRecord(allRecords: SrvRecord[]): SrvRecord {\n // Lowest priority number means highest priority\n const lowestPriority = allRecords.reduce(\n (acc, r) => Math.min(acc, r.priority),\n Number.MAX_SAFE_INTEGER,\n );\n const records = allRecords.filter(r => r.priority === lowestPriority);\n\n const totalWeight = records.reduce((acc, r) => acc + r.weight, 0);\n const targetWeight = Math.random() * totalWeight;\n\n // Just as a fallback, we expect the loop below to always find a result\n let result = records[0];\n let currentWeight = 0;\n\n for (const record of records) {\n currentWeight += record.weight;\n if (targetWeight <= currentWeight) {\n result = record;\n break;\n }\n }\n\n return result;\n }\n}\n"],"names":["resolveSrv","InputError","NotFoundError","ForwardedError"],"mappings":"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"}
1
+ {"version":3,"file":"SrvResolvers.cjs.js","sources":["../../../src/entrypoints/discovery/SrvResolvers.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError, InputError, NotFoundError } from '@backstage/errors';\nimport { resolveSrv, SrvRecord } from 'node:dns';\n\nconst PROTOCOL_SUFFIX = '+srv:';\n\n/**\n * Helps with resolution and caching of SRV lookups.\n *\n * Supports URLs on the form `http+srv://myplugin.services.region.example.net/api/myplugin`\n */\nexport class SrvResolvers {\n readonly #cache: Map<string, Promise<SrvRecord[]>>;\n readonly #cacheTtlMillis: number;\n readonly #resolveSrv: (host: string) => Promise<SrvRecord[]>;\n\n constructor(options?: {\n resolveSrv?: (host: string) => Promise<SrvRecord[]>;\n cacheTtlMillis?: number;\n }) {\n this.#cache = new Map();\n this.#cacheTtlMillis = options?.cacheTtlMillis ?? 1000;\n this.#resolveSrv =\n options?.resolveSrv ??\n (host =>\n new Promise((resolve, reject) => {\n resolveSrv(host, (err, result) => {\n if (err) {\n reject(err);\n } else {\n resolve(result);\n }\n });\n }));\n }\n\n isSrvUrl(url: string): boolean {\n try {\n this.#parseSrvUrl(url);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get a resolver function for a given SRV form URL.\n *\n * @param url An SRV form URL, e.g. `http+srv://myplugin.services.region.example.net/api/myplugin`\n * @returns A function that returns resolved URLs, e.g. `http://1234abcd.region.example.net:8080/api/myplugin`\n */\n getResolver(url: string): () => Promise<string> {\n const { protocol, host, path } = this.#parseSrvUrl(url);\n return () =>\n this.#resolveHost(host).then(\n resolved => `${protocol}://${resolved}${path}`,\n );\n }\n\n /**\n * Attempts to parse out the relevant parts of an SRV URL.\n */\n #parseSrvUrl(url: string): { protocol: string; host: string; path: string } {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new InputError(\n `SRV resolver expected a valid URL starting with http(s)+srv:// but got '${url}'`,\n );\n }\n if (!parsedUrl.protocol?.endsWith(PROTOCOL_SUFFIX) || !parsedUrl.hostname) {\n throw new InputError(\n `SRV resolver expected a URL with protocol http(s)+srv:// but got '${url}'`,\n );\n }\n if (parsedUrl.port) {\n throw new InputError(\n `SRV resolver URLs cannot contain a port but got '${url}'`,\n );\n }\n if (parsedUrl.username || parsedUrl.password) {\n throw new InputError(\n `SRV resolver URLs cannot contain username or password but got '${url}'`,\n );\n }\n if (parsedUrl.search || parsedUrl.hash) {\n throw new InputError(\n `SRV resolver URLs cannot contain search params or a hash but got '${url}'`,\n );\n }\n\n const protocol = parsedUrl.protocol.substring(\n 0,\n parsedUrl.protocol.length - PROTOCOL_SUFFIX.length,\n );\n const host = parsedUrl.hostname;\n const path = parsedUrl.pathname.replace(/\\/+$/, '');\n\n if (!['http', 'https'].includes(protocol)) {\n throw new InputError(\n `SRV URLs must be based on http or https but got '${url}'`,\n );\n }\n\n return { protocol, host, path };\n }\n\n /**\n * Resolves a single SRV record name to a host:port string.\n */\n #resolveHost(host: string): Promise<string> {\n let records = this.#cache.get(host);\n if (!records) {\n records = this.#resolveSrv(host).then(\n result => {\n if (!result.length) {\n throw new NotFoundError(`No SRV records found for ${host}`);\n }\n return result;\n },\n err => {\n throw new ForwardedError(`Failed SRV resolution for ${host}`, err);\n },\n );\n this.#cache.set(host, records);\n setTimeout(() => {\n this.#cache.delete(host);\n }, this.#cacheTtlMillis);\n }\n\n return records.then(rs => {\n const r = this.#pickRandomRecord(rs);\n return `${r.name}:${r.port}`;\n });\n }\n\n /**\n * Among a set of records, pick one at random.\n *\n * This assumes that the set is not empty.\n *\n * Since this contract only ever returns a single record, the best it can do\n * is to pick weighted-randomly among the highest-priority records. In order\n * to be smarter than that, the caller would have to be able to make decisions\n * on the whole set of records.\n */\n #pickRandomRecord(allRecords: SrvRecord[]): SrvRecord {\n // Lowest priority number means highest priority\n const lowestPriority = allRecords.reduce(\n (acc, r) => Math.min(acc, r.priority),\n Number.MAX_SAFE_INTEGER,\n );\n const records = allRecords.filter(r => r.priority === lowestPriority);\n\n const totalWeight = records.reduce((acc, r) => acc + r.weight, 0);\n const targetWeight = Math.random() * totalWeight;\n\n // Just as a fallback, we expect the loop below to always find a result\n let result = records[0];\n let currentWeight = 0;\n\n for (const record of records) {\n currentWeight += record.weight;\n if (targetWeight <= currentWeight) {\n result = record;\n break;\n }\n }\n\n return result;\n }\n}\n"],"names":["resolveSrv","InputError","NotFoundError","ForwardedError"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createRateLimitMiddleware.cjs.js","sources":["../../../../src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { NextFunction, Request, Response } from 'express';\nimport { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts';\nimport { Config } from '@backstage/config';\nimport { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts';\n\nexport const createRateLimitMiddleware = (options: {\n pluginId: string;\n config: Config;\n}) => {\n const { pluginId, config } = options;\n const configKey = `backend.rateLimit.plugin.${pluginId}`;\n const enabled = config.has(configKey);\n if (!enabled) {\n return (_req: Request, _res: Response, next: NextFunction) => {\n next();\n };\n }\n\n const rateLimitOptions = config.getConfig(configKey);\n\n return rateLimitMiddleware({\n store: RateLimitStoreFactory.create({ config, prefix: pluginId }),\n config: rateLimitOptions,\n });\n};\n"],"names":["rateLimitMiddleware","RateLimitStoreFactory"],"mappings":";;;;;AAoBO,MAAM,yBAAA,GAA4B,CAAC,OAAA,KAGpC;AACJ,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,OAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,4BAA4B,QAAQ,CAAA,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AACpC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAC,IAAA,EAAe,IAAA,EAAgB,IAAA,KAAuB;AAC5D,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA;AAEnD,EAAA,OAAOA,uCAAA,CAAoB;AAAA,IACzB,OAAOC,2CAAA,CAAsB,MAAA,CAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,UAAU,CAAA;AAAA,IAChE,MAAA,EAAQ;AAAA,GACT,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"createRateLimitMiddleware.cjs.js","sources":["../../../../src/entrypoints/httpRouter/http/createRateLimitMiddleware.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { NextFunction, Request, Response, RequestHandler } from 'express';\nimport { RateLimitStoreFactory } from '../../../lib/RateLimitStoreFactory.ts';\nimport { RootConfigService } from '@backstage/backend-plugin-api';\n\nimport { rateLimitMiddleware } from '../../../lib/rateLimitMiddleware.ts';\n\n/**\n * @public\n * Creates a middleware that applies rate limiting to requests based on the provided configuration.\n */\nexport const createRateLimitMiddleware = (options: {\n pluginId: string;\n config: RootConfigService;\n}): RequestHandler => {\n const { pluginId, config } = options;\n const configKey = `backend.rateLimit.plugin.${pluginId}`;\n const enabled = config.has(configKey);\n if (!enabled) {\n return (_req: Request, _res: Response, next: NextFunction) => {\n next();\n };\n }\n\n const rateLimitOptions = config.getConfig(configKey);\n\n return rateLimitMiddleware({\n store: RateLimitStoreFactory.create({ config, prefix: pluginId }),\n config: rateLimitOptions,\n });\n};\n"],"names":["rateLimitMiddleware","RateLimitStoreFactory"],"mappings":";;;;;AAyBO,MAAM,yBAAA,GAA4B,CAAC,OAAA,KAGpB;AACpB,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,OAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,4BAA4B,QAAQ,CAAA,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AACpC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAC,IAAA,EAAe,IAAA,EAAgB,IAAA,KAAuB;AAC5D,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA;AAEnD,EAAA,OAAOA,uCAAA,CAAoB;AAAA,IACzB,OAAOC,2CAAA,CAAsB,MAAA,CAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,UAAU,CAAA;AAAA,IAChE,MAAA,EAAQ;AAAA,GACT,CAAA;AACH;;;;"}
@@ -6,19 +6,19 @@ var createAuthIntegrationRouter = require('./http/createAuthIntegrationRouter.cj
6
6
  var createCredentialsBarrier = require('./http/createCredentialsBarrier.cjs.js');
7
7
  var createLifecycleMiddleware = require('./http/createLifecycleMiddleware.cjs.js');
8
8
  var createCookieAuthRefreshMiddleware = require('./http/createCookieAuthRefreshMiddleware.cjs.js');
9
+ var createRateLimitMiddleware = require('./http/createRateLimitMiddleware.cjs.js');
9
10
  require('express');
10
11
  require('lodash/trimEnd');
11
- require('http');
12
- require('https');
12
+ require('node:http');
13
+ require('node:https');
13
14
  require('fs-extra');
14
- require('path');
15
+ require('node:path');
15
16
  require('node-forge');
16
17
  var MiddlewareFactory = require('../rootHttpRouter/http/MiddlewareFactory.cjs.js');
17
18
  require('minimatch');
18
19
  require('helmet');
19
20
  require('lodash/kebabCase');
20
21
  require('../rootHttpRouter/rootHttpRouterServiceFactory.cjs.js');
21
- var createRateLimitMiddleware = require('./http/createRateLimitMiddleware.cjs.js');
22
22
 
23
23
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
24
24
 
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var errors = require('@backstage/errors');
4
- var crypto = require('crypto');
4
+ var node_crypto = require('node:crypto');
5
5
 
6
6
  function handleBadError(error, logger) {
7
- const logId = crypto.randomBytes(10).toString("hex");
7
+ const logId = node_crypto.randomBytes(10).toString("hex");
8
8
  logger.child({ logId }).error(`Filtered internal error with logId=${logId} from response`, error);
9
9
  const newError = new Error(`An internal error occurred logId=${logId}`);
10
10
  delete newError.stack;
@@ -1 +1 @@
1
- {"version":3,"file":"applyInternalErrorFilter.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { assertError } from '@backstage/errors';\nimport { randomBytes } from 'crypto';\n\nfunction handleBadError(error: Error, logger: LoggerService) {\n const logId = randomBytes(10).toString('hex');\n logger\n .child({ logId })\n .error(`Filtered internal error with logId=${logId} from response`, error);\n const newError = new Error(`An internal error occurred logId=${logId}`);\n delete newError.stack; // Trim the stack since it's not particularly useful\n return newError;\n}\n\n/**\n * Filters out certain known error types that should never be returned in responses.\n *\n * @internal\n */\nexport function applyInternalErrorFilter(\n error: unknown,\n logger: LoggerService,\n): Error {\n try {\n assertError(error);\n } catch (assertionError: unknown) {\n assertError(assertionError);\n return handleBadError(assertionError, logger);\n }\n\n const constructorName = error.constructor.name;\n\n // DatabaseError are thrown by the pg-protocol module\n if (constructorName === 'DatabaseError') {\n return handleBadError(error, logger);\n }\n\n return error;\n}\n"],"names":["randomBytes","assertError"],"mappings":";;;;;AAoBA,SAAS,cAAA,CAAe,OAAc,MAAA,EAAuB;AAC3D,EAAA,MAAM,KAAA,GAAQA,kBAAA,CAAY,EAAE,CAAA,CAAE,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAA,CACG,KAAA,CAAM,EAAE,KAAA,EAAO,EACf,KAAA,CAAM,CAAA,mCAAA,EAAsC,KAAK,CAAA,cAAA,CAAA,EAAkB,KAAK,CAAA;AAC3E,EAAA,MAAM,QAAA,GAAW,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AACtE,EAAA,OAAO,QAAA,CAAS,KAAA;AAChB,EAAA,OAAO,QAAA;AACT;AAOO,SAAS,wBAAA,CACd,OACA,MAAA,EACO;AACP,EAAA,IAAI;AACF,IAAAC,kBAAA,CAAY,KAAK,CAAA;AAAA,EACnB,SAAS,cAAA,EAAyB;AAChC,IAAAA,kBAAA,CAAY,cAAc,CAAA;AAC1B,IAAA,OAAO,cAAA,CAAe,gBAAgB,MAAM,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,eAAA,GAAkB,MAAM,WAAA,CAAY,IAAA;AAG1C,EAAA,IAAI,oBAAoB,eAAA,EAAiB;AACvC,IAAA,OAAO,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,KAAA;AACT;;;;"}
1
+ {"version":3,"file":"applyInternalErrorFilter.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { assertError } from '@backstage/errors';\nimport { randomBytes } from 'node:crypto';\n\nfunction handleBadError(error: Error, logger: LoggerService) {\n const logId = randomBytes(10).toString('hex');\n logger\n .child({ logId })\n .error(`Filtered internal error with logId=${logId} from response`, error);\n const newError = new Error(`An internal error occurred logId=${logId}`);\n delete newError.stack; // Trim the stack since it's not particularly useful\n return newError;\n}\n\n/**\n * Filters out certain known error types that should never be returned in responses.\n *\n * @internal\n */\nexport function applyInternalErrorFilter(\n error: unknown,\n logger: LoggerService,\n): Error {\n try {\n assertError(error);\n } catch (assertionError: unknown) {\n assertError(assertionError);\n return handleBadError(assertionError, logger);\n }\n\n const constructorName = error.constructor.name;\n\n // DatabaseError are thrown by the pg-protocol module\n if (constructorName === 'DatabaseError') {\n return handleBadError(error, logger);\n }\n\n return error;\n}\n"],"names":["randomBytes","assertError"],"mappings":";;;;;AAoBA,SAAS,cAAA,CAAe,OAAc,MAAA,EAAuB;AAC3D,EAAA,MAAM,KAAA,GAAQA,uBAAA,CAAY,EAAE,CAAA,CAAE,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAA,CACG,KAAA,CAAM,EAAE,KAAA,EAAO,EACf,KAAA,CAAM,CAAA,mCAAA,EAAsC,KAAK,CAAA,cAAA,CAAA,EAAkB,KAAK,CAAA;AAC3E,EAAA,MAAM,QAAA,GAAW,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AACtE,EAAA,OAAO,QAAA,CAAS,KAAA;AAChB,EAAA,OAAO,QAAA;AACT;AAOO,SAAS,wBAAA,CACd,OACA,MAAA,EACO;AACP,EAAA,IAAI;AACF,IAAAC,kBAAA,CAAY,KAAK,CAAA;AAAA,EACnB,SAAS,cAAA,EAAyB;AAChC,IAAAA,kBAAA,CAAY,cAAc,CAAA;AAC1B,IAAA,OAAO,cAAA,CAAe,gBAAgB,MAAM,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,eAAA,GAAkB,MAAM,WAAA,CAAY,IAAA;AAG1C,EAAA,IAAI,oBAAoB,eAAA,EAAiB;AACvC,IAAA,OAAO,cAAA,CAAe,OAAO,MAAM,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,KAAA;AACT;;;;"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var http = require('http');
4
- var https = require('https');
3
+ var http = require('node:http');
4
+ var https = require('node:https');
5
5
  var getGeneratedCertificate = require('./getGeneratedCertificate.cjs.js');
6
6
 
7
7
  function _interopNamespaceCompat(e) {
@@ -1 +1 @@
1
- {"version":3,"file":"createHttpServer.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/createHttpServer.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 * as http from 'http';\nimport * as https from 'https';\nimport { RequestListener } from 'http';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { HttpServerOptions, ExtendedHttpServer } from './types';\nimport { getGeneratedCertificate } from './getGeneratedCertificate';\n\n/**\n * Creates a Node.js HTTP or HTTPS server instance.\n *\n * @public\n */\nexport async function createHttpServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<ExtendedHttpServer> {\n const server = await createServer(listener, options, deps);\n return Object.assign(server, {\n start() {\n return new Promise<void>((resolve, reject) => {\n const handleStartupError = (error: Error) => {\n server.close();\n reject(error);\n };\n\n server.on('error', handleStartupError);\n\n const { host, port } = options.listen;\n server.listen(port, host, () => {\n server.off('error', handleStartupError);\n deps.logger.info(`Listening on ${host}:${port}`);\n resolve();\n });\n });\n },\n\n stop() {\n return new Promise<void>((resolve, reject) => {\n if (process.env.NODE_ENV === 'development') {\n // Ensure that various polling connections are shut down fast in development\n server.closeAllConnections();\n } else {\n server.closeIdleConnections();\n }\n server.close(error => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n },\n\n port() {\n const address = server.address();\n if (typeof address === 'string' || address === null) {\n throw new Error(`Unexpected server address '${address}'`);\n }\n return address.port;\n },\n });\n}\n\nasync function createServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<http.Server> {\n if (options.https) {\n const { certificate } = options.https;\n if (certificate.type === 'generated') {\n const credentials = await getGeneratedCertificate(\n certificate.hostname,\n deps.logger,\n );\n return https.createServer(credentials, listener);\n }\n return https.createServer(certificate, listener);\n }\n\n return http.createServer(listener);\n}\n"],"names":["getGeneratedCertificate","https","http"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,eAAsB,gBAAA,CACpB,QAAA,EACA,OAAA,EACA,IAAA,EAC6B;AAC7B,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,QAAA,EAAU,SAAS,IAAI,CAAA;AACzD,EAAA,OAAO,MAAA,CAAO,OAAO,MAAA,EAAQ;AAAA,IAC3B,KAAA,GAAQ;AACN,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiB;AAC3C,UAAA,MAAA,CAAO,KAAA,EAAM;AACb,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd,CAAA;AAEA,QAAA,MAAA,CAAO,EAAA,CAAG,SAAS,kBAAkB,CAAA;AAErC,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,OAAA,CAAQ,MAAA;AAC/B,QAAA,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,IAAA,EAAM,MAAM;AAC9B,UAAA,MAAA,CAAO,GAAA,CAAI,SAAS,kBAAkB,CAAA;AACtC,UAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,aAAA,EAAgB,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAC/C,UAAA,OAAA,EAAQ;AAAA,QACV,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,EAAe;AAE1C,UAAA,MAAA,CAAO,mBAAA,EAAoB;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,MAAA,CAAO,oBAAA,EAAqB;AAAA,QAC9B;AACA,QAAA,MAAA,CAAO,MAAM,CAAA,KAAA,KAAS;AACpB,UAAA,IAAI,KAAA,EAAO;AACT,YAAA,MAAA,CAAO,KAAK,CAAA;AAAA,UACd,CAAA,MAAO;AACL,YAAA,OAAA,EAAQ;AAAA,UACV;AAAA,QACF,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,MAAM,OAAA,GAAU,OAAO,OAAA,EAAQ;AAC/B,MAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,IAAA,EAAM;AACnD,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,MAC1D;AACA,MAAA,OAAO,OAAA,CAAQ,IAAA;AAAA,IACjB;AAAA,GACD,CAAA;AACH;AAEA,eAAe,YAAA,CACb,QAAA,EACA,OAAA,EACA,IAAA,EACsB;AACtB,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAM,EAAE,WAAA,EAAY,GAAI,OAAA,CAAQ,KAAA;AAChC,IAAA,IAAI,WAAA,CAAY,SAAS,WAAA,EAAa;AACpC,MAAA,MAAM,cAAc,MAAMA,+CAAA;AAAA,QACxB,WAAA,CAAY,QAAA;AAAA,QACZ,IAAA,CAAK;AAAA,OACP;AACA,MAAA,OAAOC,gBAAA,CAAM,YAAA,CAAa,WAAA,EAAa,QAAQ,CAAA;AAAA,IACjD;AACA,IAAA,OAAOA,gBAAA,CAAM,YAAA,CAAa,WAAA,EAAa,QAAQ,CAAA;AAAA,EACjD;AAEA,EAAA,OAAOC,eAAA,CAAK,aAAa,QAAQ,CAAA;AACnC;;;;"}
1
+ {"version":3,"file":"createHttpServer.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/createHttpServer.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 * as http from 'node:http';\nimport * as https from 'node:https';\nimport { RequestListener } from 'node:http';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { HttpServerOptions, ExtendedHttpServer } from './types';\nimport { getGeneratedCertificate } from './getGeneratedCertificate';\n\n/**\n * Creates a Node.js HTTP or HTTPS server instance.\n *\n * @public\n */\nexport async function createHttpServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<ExtendedHttpServer> {\n const server = await createServer(listener, options, deps);\n return Object.assign(server, {\n start() {\n return new Promise<void>((resolve, reject) => {\n const handleStartupError = (error: Error) => {\n server.close();\n reject(error);\n };\n\n server.on('error', handleStartupError);\n\n const { host, port } = options.listen;\n server.listen(port, host, () => {\n server.off('error', handleStartupError);\n deps.logger.info(`Listening on ${host}:${port}`);\n resolve();\n });\n });\n },\n\n stop() {\n return new Promise<void>((resolve, reject) => {\n if (process.env.NODE_ENV === 'development') {\n // Ensure that various polling connections are shut down fast in development\n server.closeAllConnections();\n } else {\n server.closeIdleConnections();\n }\n server.close(error => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n },\n\n port() {\n const address = server.address();\n if (typeof address === 'string' || address === null) {\n throw new Error(`Unexpected server address '${address}'`);\n }\n return address.port;\n },\n });\n}\n\nasync function createServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<http.Server> {\n if (options.https) {\n const { certificate } = options.https;\n if (certificate.type === 'generated') {\n const credentials = await getGeneratedCertificate(\n certificate.hostname,\n deps.logger,\n );\n return https.createServer(credentials, listener);\n }\n return https.createServer(certificate, listener);\n }\n\n return http.createServer(listener);\n}\n"],"names":["getGeneratedCertificate","https","http"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,eAAsB,gBAAA,CACpB,QAAA,EACA,OAAA,EACA,IAAA,EAC6B;AAC7B,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,QAAA,EAAU,SAAS,IAAI,CAAA;AACzD,EAAA,OAAO,MAAA,CAAO,OAAO,MAAA,EAAQ;AAAA,IAC3B,KAAA,GAAQ;AACN,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAAiB;AAC3C,UAAA,MAAA,CAAO,KAAA,EAAM;AACb,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd,CAAA;AAEA,QAAA,MAAA,CAAO,EAAA,CAAG,SAAS,kBAAkB,CAAA;AAErC,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,OAAA,CAAQ,MAAA;AAC/B,QAAA,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,IAAA,EAAM,MAAM;AAC9B,UAAA,MAAA,CAAO,GAAA,CAAI,SAAS,kBAAkB,CAAA;AACtC,UAAA,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,aAAA,EAAgB,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAC/C,UAAA,OAAA,EAAQ;AAAA,QACV,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,EAAe;AAE1C,UAAA,MAAA,CAAO,mBAAA,EAAoB;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,MAAA,CAAO,oBAAA,EAAqB;AAAA,QAC9B;AACA,QAAA,MAAA,CAAO,MAAM,CAAA,KAAA,KAAS;AACpB,UAAA,IAAI,KAAA,EAAO;AACT,YAAA,MAAA,CAAO,KAAK,CAAA;AAAA,UACd,CAAA,MAAO;AACL,YAAA,OAAA,EAAQ;AAAA,UACV;AAAA,QACF,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,MAAM,OAAA,GAAU,OAAO,OAAA,EAAQ;AAC/B,MAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,IAAA,EAAM;AACnD,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,MAC1D;AACA,MAAA,OAAO,OAAA,CAAQ,IAAA;AAAA,IACjB;AAAA,GACD,CAAA;AACH;AAEA,eAAe,YAAA,CACb,QAAA,EACA,OAAA,EACA,IAAA,EACsB;AACtB,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAM,EAAE,WAAA,EAAY,GAAI,OAAA,CAAQ,KAAA;AAChC,IAAA,IAAI,WAAA,CAAY,SAAS,WAAA,EAAa;AACpC,MAAA,MAAM,cAAc,MAAMA,+CAAA;AAAA,QACxB,WAAA,CAAY,QAAA;AAAA,QACZ,IAAA,CAAK;AAAA,OACP;AACA,MAAA,OAAOC,gBAAA,CAAM,YAAA,CAAa,WAAA,EAAa,QAAQ,CAAA;AAAA,IACjD;AACA,IAAA,OAAOA,gBAAA,CAAM,YAAA,CAAa,WAAA,EAAa,QAAQ,CAAA;AAAA,EACjD;AAEA,EAAA,OAAOC,eAAA,CAAK,aAAa,QAAQ,CAAA;AACnC;;;;"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var fs = require('fs-extra');
4
- var platformPath = require('path');
4
+ var platformPath = require('node:path');
5
5
  var forge = require('node-forge');
6
6
 
7
7
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -1 +1 @@
1
- {"version":3,"file":"getGeneratedCertificate.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/getGeneratedCertificate.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 fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport forge from 'node-forge';\n\nconst FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1000;\n\nconst IP_HOSTNAME_REGEX = /:|^\\d+\\.\\d+\\.\\d+\\.\\d+$/;\n\nexport async function getGeneratedCertificate(\n hostname: string,\n logger: LoggerService,\n) {\n const hasModules = await fs.pathExists('node_modules');\n let certPath;\n if (hasModules) {\n certPath = resolvePath(\n 'node_modules/.cache/backstage-backend/dev-cert.pem',\n );\n await fs.ensureDir(dirname(certPath));\n } else {\n certPath = resolvePath('.dev-cert.pem');\n }\n\n if (await fs.pathExists(certPath)) {\n try {\n const cert = await fs.readFile(certPath);\n\n const crt = forge.pki.certificateFromPem(cert.toString());\n const remainingMs = crt.validity.notAfter.getTime() - Date.now();\n if (remainingMs > FIVE_DAYS_IN_MS) {\n logger.info('Using existing self-signed certificate');\n return {\n key: cert,\n cert,\n };\n }\n } catch (error) {\n logger.warn(`Unable to use existing self-signed certificate, ${error}`);\n }\n }\n\n logger.info('Generating new self-signed certificate');\n const newCert = await generateCertificate(hostname);\n await fs.writeFile(certPath, newCert.cert + newCert.key, 'utf8');\n return newCert;\n}\n\nasync function generateCertificate(hostname: string) {\n const attributes = [\n {\n name: 'commonName',\n value: 'dev-cert',\n },\n ];\n\n const sans = [\n {\n type: 2, // DNS\n value: 'localhost',\n },\n {\n type: 2,\n value: 'localhost.localdomain',\n },\n {\n type: 2,\n value: '[::1]',\n },\n {\n type: 7, // IP\n ip: '127.0.0.1',\n },\n {\n type: 7,\n ip: 'fe80::1',\n },\n ];\n\n // Add hostname from backend.baseUrl if it doesn't already exist in our list of SANs\n if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {\n sans.push(\n IP_HOSTNAME_REGEX.test(hostname)\n ? {\n type: 7,\n ip: hostname,\n }\n : {\n type: 2,\n value: hostname,\n },\n );\n }\n\n const params = {\n algorithm: 'sha256',\n keySize: 2048,\n days: 30,\n extensions: [\n {\n name: 'keyUsage',\n keyCertSign: true,\n digitalSignature: true,\n nonRepudiation: true,\n keyEncipherment: true,\n dataEncipherment: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n codeSigning: true,\n timeStamping: true,\n },\n {\n name: 'subjectAltName',\n altNames: sans,\n },\n ],\n };\n\n return new Promise<{ key: string; cert: string }>((resolve, reject) =>\n require('selfsigned').generate(\n attributes,\n params,\n (err: Error, bundle: { private: string; cert: string }) => {\n if (err) {\n reject(err);\n } else {\n resolve({ key: bundle.private, cert: bundle.cert });\n }\n },\n ),\n );\n}\n"],"names":["fs","resolvePath","dirname","forge"],"mappings":"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"}
1
+ {"version":3,"file":"getGeneratedCertificate.cjs.js","sources":["../../../../src/entrypoints/rootHttpRouter/http/getGeneratedCertificate.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 fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'node:path';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport forge from 'node-forge';\n\nconst FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1000;\n\nconst IP_HOSTNAME_REGEX = /:|^\\d+\\.\\d+\\.\\d+\\.\\d+$/;\n\nexport async function getGeneratedCertificate(\n hostname: string,\n logger: LoggerService,\n) {\n const hasModules = await fs.pathExists('node_modules');\n let certPath;\n if (hasModules) {\n certPath = resolvePath(\n 'node_modules/.cache/backstage-backend/dev-cert.pem',\n );\n await fs.ensureDir(dirname(certPath));\n } else {\n certPath = resolvePath('.dev-cert.pem');\n }\n\n if (await fs.pathExists(certPath)) {\n try {\n const cert = await fs.readFile(certPath);\n\n const crt = forge.pki.certificateFromPem(cert.toString());\n const remainingMs = crt.validity.notAfter.getTime() - Date.now();\n if (remainingMs > FIVE_DAYS_IN_MS) {\n logger.info('Using existing self-signed certificate');\n return {\n key: cert,\n cert,\n };\n }\n } catch (error) {\n logger.warn(`Unable to use existing self-signed certificate, ${error}`);\n }\n }\n\n logger.info('Generating new self-signed certificate');\n const newCert = await generateCertificate(hostname);\n await fs.writeFile(certPath, newCert.cert + newCert.key, 'utf8');\n return newCert;\n}\n\nasync function generateCertificate(hostname: string) {\n const attributes = [\n {\n name: 'commonName',\n value: 'dev-cert',\n },\n ];\n\n const sans = [\n {\n type: 2, // DNS\n value: 'localhost',\n },\n {\n type: 2,\n value: 'localhost.localdomain',\n },\n {\n type: 2,\n value: '[::1]',\n },\n {\n type: 7, // IP\n ip: '127.0.0.1',\n },\n {\n type: 7,\n ip: 'fe80::1',\n },\n ];\n\n // Add hostname from backend.baseUrl if it doesn't already exist in our list of SANs\n if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {\n sans.push(\n IP_HOSTNAME_REGEX.test(hostname)\n ? {\n type: 7,\n ip: hostname,\n }\n : {\n type: 2,\n value: hostname,\n },\n );\n }\n\n const params = {\n algorithm: 'sha256',\n keySize: 2048,\n days: 30,\n extensions: [\n {\n name: 'keyUsage',\n keyCertSign: true,\n digitalSignature: true,\n nonRepudiation: true,\n keyEncipherment: true,\n dataEncipherment: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n codeSigning: true,\n timeStamping: true,\n },\n {\n name: 'subjectAltName',\n altNames: sans,\n },\n ],\n };\n\n return new Promise<{ key: string; cert: string }>((resolve, reject) =>\n require('selfsigned').generate(\n attributes,\n params,\n (err: Error, bundle: { private: string; cert: string }) => {\n if (err) {\n reject(err);\n } else {\n resolve({ key: bundle.private, cert: bundle.cert });\n }\n },\n ),\n );\n}\n"],"names":["fs","resolvePath","dirname","forge"],"mappings":"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"}
@@ -5,9 +5,9 @@ var integration = require('@backstage/integration');
5
5
  var errors = require('@backstage/errors');
6
6
  var credentialProviders = require('@aws-sdk/credential-providers');
7
7
  var clientCodecommit = require('@aws-sdk/client-codecommit');
8
- var stream = require('stream');
8
+ var node_stream = require('node:stream');
9
9
  var ReadUrlResponseFactory = require('./ReadUrlResponseFactory.cjs.js');
10
- var posix = require('path/posix');
10
+ var posix = require('node:path/posix');
11
11
  var abortController = require('@aws-sdk/abort-controller');
12
12
 
13
13
  function parseUrl(url, requireGitPath = false) {
@@ -161,7 +161,7 @@ class AwsCodeCommitUrlReader {
161
161
  throw new errors.NotModifiedError();
162
162
  }
163
163
  return ReadUrlResponseFactory.ReadUrlResponseFactory.fromReadable(
164
- stream.Readable.from([response?.fileContent]),
164
+ node_stream.Readable.from([response?.fileContent]),
165
165
  {
166
166
  etag: response.commitId
167
167
  }
@@ -241,7 +241,7 @@ class AwsCodeCommitUrlReader {
241
241
  commitSpecifier
242
242
  });
243
243
  const response = await codeCommitClient.send(getFileCommand);
244
- const objectData = await stream.Readable.from([response?.fileContent]);
244
+ const objectData = await node_stream.Readable.from([response?.fileContent]);
245
245
  responses.push({
246
246
  data: objectData,
247
247
  path: posix.relative(
@@ -1 +1 @@
1
- {"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.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 { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n assertError,\n ForwardedError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n private readonly credsManager: AwsCredentialsManager;\n private readonly integration: AwsCodeCommitIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AwsCredentialsManager,\n integration: AwsCodeCommitIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent]),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent]);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url, true);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (error) {\n assertError(error);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","relative","assertError"],"mappings":"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"}
1
+ {"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.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 { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n assertError,\n ForwardedError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'node:stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'node:path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n private readonly credsManager: AwsCredentialsManager;\n private readonly integration: AwsCodeCommitIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AwsCredentialsManager,\n integration: AwsCodeCommitIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent]),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent]);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url, true);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (error) {\n assertError(error);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","relative","assertError"],"mappings":"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"}
@@ -7,8 +7,8 @@ var credentialProviders = require('@aws-sdk/credential-providers');
7
7
  var clientS3 = require('@aws-sdk/client-s3');
8
8
  var abortController = require('@aws-sdk/abort-controller');
9
9
  var ReadUrlResponseFactory = require('./ReadUrlResponseFactory.cjs.js');
10
- var stream = require('stream');
11
- var posix = require('path/posix');
10
+ var node_stream = require('node:stream');
11
+ var posix = require('node:path/posix');
12
12
 
13
13
  const DEFAULT_REGION = "us-east-1";
14
14
  function parseUrl(url, config) {
@@ -138,16 +138,16 @@ class AwsS3UrlReader {
138
138
  });
139
139
  return s3;
140
140
  }
141
- async retrieveS3ObjectData(stream$1) {
141
+ async retrieveS3ObjectData(stream) {
142
142
  return new Promise((resolve, reject) => {
143
143
  try {
144
144
  const chunks = [];
145
- stream$1.on("data", (chunk) => chunks.push(chunk));
146
- stream$1.on(
145
+ stream.on("data", (chunk) => chunks.push(chunk));
146
+ stream.on(
147
147
  "error",
148
148
  (e) => reject(new errors.ForwardedError("Unable to read stream", e))
149
149
  );
150
- stream$1.on("end", () => resolve(stream.Readable.from(Buffer.concat(chunks))));
150
+ stream.on("end", () => resolve(node_stream.Readable.from(Buffer.concat(chunks))));
151
151
  } catch (e) {
152
152
  throw new errors.ForwardedError("Unable to parse the response data", e);
153
153
  }