@backstage/backend-defaults 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/config.d.ts +195 -0
- package/dist/CreateBackend.cjs.js.map +1 -1
- package/dist/PackageDiscoveryService.cjs.js +13 -3
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actions/DefaultActionsService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actions/actionsServiceFactory.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js.map +1 -1
- package/dist/cache.d.ts +20 -1
- package/dist/database.d.ts +1 -1
- package/dist/discovery.d.ts +1 -1
- package/dist/discoveryFeatureLoader.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/types.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/utils.cjs.js.map +1 -1
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
- package/dist/entrypoints/auth/authServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/jwks.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/legacy.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/static.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheManager.cjs.js +112 -7
- package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -1
- package/dist/entrypoints/cache/cacheServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js +141 -0
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js.map +1 -0
- package/dist/entrypoints/cache/providers/infinispan/InfinispanOptionsMapper.cjs.js +129 -0
- package/dist/entrypoints/cache/providers/infinispan/InfinispanOptionsMapper.cjs.js.map +1 -0
- package/dist/entrypoints/cache/types.cjs.js.map +1 -1
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mysql.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
- package/dist/entrypoints/database/databaseServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createAuthIntegrationRouter.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createCredentialsBarrier.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createLifecycleMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/logger/loggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/config.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js +3 -0
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/tables.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/types.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js.map +1 -1
- package/dist/httpAuth.d.ts +1 -1
- package/dist/lib/RateLimitStoreFactory.cjs.js.map +1 -1
- package/dist/lib/escapeRegExp.cjs.js.map +1 -1
- package/dist/lib/rateLimitMiddleware.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +2 -269
- package/dist/package.json.cjs.js.map +1 -1
- package/dist/urlReader.d.ts +1 -1
- package/package.json +12 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HarnessUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/HarnessUrlReader.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 {\n UrlReaderService,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceSearchOptions,\n} from '@backstage/backend-plugin-api';\nimport {\n getHarnessRequestOptions,\n getHarnessFileContentsUrl,\n HarnessIntegration,\n ScmIntegrations,\n getHarnessLatestCommitUrl,\n getHarnessArchiveUrl,\n parseHarnessUrl,\n} from '@backstage/integration';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport fetch, { Response } from 'node-fetch';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n assertError,\n AuthenticationError,\n NotFoundError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { Readable } from 'stream';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Harness code v1 api.\n *\n *\n * @public\n */\nexport class HarnessUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n return ScmIntegrations.fromConfig(config)\n .harness.list()\n .map(integration => {\n const reader = new HarnessUrlReader(integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return url.host === integration.config.host;\n };\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: HarnessIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n let response: Response;\n const blobUrl = getHarnessFileContentsUrl(this.integration.config, url);\n\n try {\n response = await fetch(blobUrl, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${blobUrl}, ${e}`);\n }\n\n if (response.ok) {\n // Harness Code returns the raw content object\n const jsonResponse = { data: response.body };\n if (jsonResponse) {\n return ReadUrlResponseFactory.fromReadable(\n Readable.from(jsonResponse.data),\n {\n etag: response.headers.get('ETag') ?? undefined,\n },\n );\n }\n\n throw new Error(`Unknown json: ${jsonResponse}`);\n }\n\n const message = `${url} x ${blobUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.status === 403) {\n throw new AuthenticationError();\n }\n\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const lastCommitHash = await this.getLastCommitHash(url);\n\n if (options?.etag && options.etag === lastCommitHash) {\n throw new NotModifiedError();\n }\n\n const archiveUri = getHarnessArchiveUrl(this.integration.config, url);\n\n let response: Response;\n try {\n response = await fetch(archiveUri, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${archiveUri}, ${e}`);\n }\n\n const parsedUri = parseHarnessUrl(this.integration.config, url);\n\n return this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(response.body),\n subpath: parsedUri.path,\n etag: lastCommitHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseHarnessUrl(this.integration.config, url);\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 { host } = this.integration.config;\n return `harness{host=${host},authed=${Boolean(\n this.integration.config.token || this.integration.config.apiKey,\n )}}`;\n }\n private async getLastCommitHash(url: string): Promise<string> {\n const commitUri = getHarnessLatestCommitUrl(this.integration.config, url);\n\n const response = await fetch(\n commitUri,\n getHarnessRequestOptions(this.integration.config),\n );\n if (!response.ok) {\n const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return (await response.json()).latest_commit.sha;\n }\n}\n"],"names":["ScmIntegrations","getHarnessFileContentsUrl","fetch","getHarnessRequestOptions","ReadUrlResponseFactory","Readable","NotFoundError","NotModifiedError","AuthenticationError","getHarnessArchiveUrl","parseHarnessUrl","assertError","getHarnessLatestCommitUrl"],"mappings":";;;;;;;;;;;;AAmDO,MAAM,gBAA6C,CAAA;AAAA,EAexD,WAAA,CACmB,aACA,IAGjB,EAAA;AAJiB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA;AAGhB,EAnBH,OAAO,OAAyB,GAAA,CAAC,EAAE,MAAA,EAAQ,qBAA0B,KAAA;AACnE,IAAO,OAAAA,2BAAA,CAAgB,WAAW,MAAM,CAAA,CACrC,QAAQ,IAAK,EAAA,CACb,IAAI,CAAe,WAAA,KAAA;AAClB,MAAM,MAAA,MAAA,GAAS,IAAI,gBAAA,CAAiB,WAAa,EAAA;AAAA,QAC/C;AAAA,OACD,CAAA;AACD,MAAM,MAAA,SAAA,GAAY,CAAC,GAAa,KAAA;AAC9B,QAAO,OAAA,GAAA,CAAI,IAAS,KAAA,WAAA,CAAY,MAAO,CAAA,IAAA;AAAA,OACzC;AACA,MAAO,OAAA,EAAE,QAAQ,SAAU,EAAA;AAAA,KAC5B,CAAA;AAAA,GACL;AAAA,EAQA,MAAM,KAAK,GAA8B,EAAA;AACvC,IAAA,MAAM,QAAW,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA;AACvC,IAAA,OAAO,SAAS,MAAO,EAAA;AAAA;AACzB,EAEA,MAAM,OACJ,CAAA,GAAA,EACA,OAC0C,EAAA;AAC1C,IAAI,IAAA,QAAA;AACJ,IAAA,MAAM,OAAU,GAAAC,qCAAA,CAA0B,IAAK,CAAA,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEtE,IAAI,IAAA;AACF,MAAW,QAAA,GAAA,MAAMC,uBAAM,OAAS,EAAA;AAAA,QAC9B,MAAQ,EAAA,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAK,CAAA,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAS,EAAA;AAAA,OAClB,CAAA;AAAA,aACM,CAAG,EAAA;AACV,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,eAAA,EAAkB,OAAO,CAAA,EAAA,EAAK,CAAC,CAAE,CAAA,CAAA;AAAA;AAGnD,IAAA,IAAI,SAAS,EAAI,EAAA;AAEf,MAAA,MAAM,YAAe,GAAA,EAAE,IAAM,EAAA,QAAA,CAAS,IAAK,EAAA;AAC3C,MAAA,IAAI,YAAc,EAAA;AAChB,QAAA,OAAOC,6CAAuB,CAAA,YAAA;AAAA,UAC5BC,eAAA,CAAS,IAAK,CAAA,YAAA,CAAa,IAAI,CAAA;AAAA,UAC/B;AAAA,YACE,IAAM,EAAA,QAAA,CAAS,OAAQ,CAAA,GAAA,CAAI,MAAM,CAAK,IAAA,KAAA;AAAA;AACxC,SACF;AAAA;AAGF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAiB,cAAA,EAAA,YAAY,CAAE,CAAA,CAAA;AAAA;AAGjD,IAAM,MAAA,OAAA,GAAU,CAAG,EAAA,GAAG,CAAM,GAAA,EAAA,OAAO,KAAK,QAAS,CAAA,MAAM,CAAI,CAAA,EAAA,QAAA,CAAS,UAAU,CAAA,CAAA;AAC9E,IAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,MAAM,MAAA,IAAIC,qBAAc,OAAO,CAAA;AAAA;AAGjC,IAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,MAAA,MAAM,IAAIC,uBAAiB,EAAA;AAAA;AAG7B,IAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,MAAA,MAAM,IAAIC,0BAAoB,EAAA;AAAA;AAGhC,IAAM,MAAA,IAAI,MAAM,OAAO,CAAA;AAAA;AACzB,EAEA,MAAM,QACJ,CAAA,GAAA,EACA,OAC2C,EAAA;AAC3C,IAAA,MAAM,cAAiB,GAAA,MAAM,IAAK,CAAA,iBAAA,CAAkB,GAAG,CAAA;AAEvD,IAAA,IAAI,OAAS,EAAA,IAAA,IAAQ,OAAQ,CAAA,IAAA,KAAS,cAAgB,EAAA;AACpD,MAAA,MAAM,IAAID,uBAAiB,EAAA;AAAA;AAG7B,IAAA,MAAM,UAAa,GAAAE,gCAAA,CAAqB,IAAK,CAAA,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEpE,IAAI,IAAA,QAAA;AACJ,IAAI,IAAA;AACF,MAAW,QAAA,GAAA,MAAMP,uBAAM,UAAY,EAAA;AAAA,QACjC,MAAQ,EAAA,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAK,CAAA,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAS,EAAA;AAAA,OAClB,CAAA;AAAA,aACM,CAAG,EAAA;AACV,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,eAAA,EAAkB,UAAU,CAAA,EAAA,EAAK,CAAC,CAAE,CAAA,CAAA;AAAA;AAGtD,IAAA,MAAM,SAAY,GAAAO,2BAAA,CAAgB,IAAK,CAAA,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE9D,IAAO,OAAA,IAAA,CAAK,IAAK,CAAA,mBAAA,CAAoB,cAAe,CAAA;AAAA,MAClD,MAAQ,EAAAL,eAAA,CAAS,IAAK,CAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACnC,SAAS,SAAU,CAAA,IAAA;AAAA,MACnB,IAAM,EAAA,cAAA;AAAA,MACN,QAAQ,OAAS,EAAA;AAAA,KAClB,CAAA;AAAA;AACH,EAEA,MAAM,MACJ,CAAA,GAAA,EACA,OACyC,EAAA;AACzC,IAAA,MAAM,EAAE,IAAK,EAAA,GAAIK,4BAAgB,IAAK,CAAA,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE7D,IAAI,IAAA,IAAA,CAAK,KAAM,CAAA,MAAM,CAAG,EAAA;AACtB,MAAM,MAAA,IAAI,MAAM,gCAAgC,CAAA;AAAA;AAGlD,IAAI,IAAA;AACF,MAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAE5C,MAAO,OAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL;AAAA,YACE,GAAA;AAAA,YACA,SAAS,IAAK,CAAA,MAAA;AAAA,YACd,gBAAgB,IAAK,CAAA;AAAA;AACvB,SACF;AAAA,QACA,IAAA,EAAM,KAAK,IAAQ,IAAA;AAAA,OACrB;AAAA,aACO,KAAO,EAAA;AACd,MAAAC,kBAAA,CAAY,KAAK,CAAA;AACjB,MAAI,IAAA,KAAA,CAAM,SAAS,eAAiB,EAAA;AAClC,QAAO,OAAA;AAAA,UACL,OAAO,EAAC;AAAA,UACR,IAAM,EAAA;AAAA,SACR;AAAA;AAEF,MAAM,MAAA,KAAA;AAAA;AACR;AACF,EAEA,QAAW,GAAA;AACT,IAAA,MAAM,EAAE,IAAA,EAAS,GAAA,IAAA,CAAK,WAAY,CAAA,MAAA;AAClC,IAAO,OAAA,CAAA,aAAA,EAAgB,IAAI,CAAW,QAAA,EAAA,OAAA;AAAA,MACpC,KAAK,WAAY,CAAA,MAAA,CAAO,KAAS,IAAA,IAAA,CAAK,YAAY,MAAO,CAAA;AAAA,KAC1D,CAAA,CAAA,CAAA;AAAA;AACH,EACA,MAAc,kBAAkB,GAA8B,EAAA;AAC5D,IAAA,MAAM,SAAY,GAAAC,qCAAA,CAA0B,IAAK,CAAA,WAAA,CAAY,QAAQ,GAAG,CAAA;AAExE,IAAA,MAAM,WAAW,MAAMV,sBAAA;AAAA,MACrB,SAAA;AAAA,MACAC,oCAAA,CAAyB,IAAK,CAAA,WAAA,CAAY,MAAM;AAAA,KAClD;AACA,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,OAAA,GAAU,qDAAqD,SAAS,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA,CAAA;AACzH,MAAI,IAAA,QAAA,CAAS,WAAW,GAAK,EAAA;AAC3B,QAAM,MAAA,IAAIG,qBAAc,OAAO,CAAA;AAAA;AAEjC,MAAM,MAAA,IAAI,MAAM,OAAO,CAAA;AAAA;AAGzB,IAAA,OAAA,CAAQ,MAAM,QAAA,CAAS,IAAK,EAAA,EAAG,aAAc,CAAA,GAAA;AAAA;AAEjD;;;;"}
|
|
1
|
+
{"version":3,"file":"HarnessUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/HarnessUrlReader.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 {\n UrlReaderService,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceSearchOptions,\n} from '@backstage/backend-plugin-api';\nimport {\n getHarnessRequestOptions,\n getHarnessFileContentsUrl,\n HarnessIntegration,\n ScmIntegrations,\n getHarnessLatestCommitUrl,\n getHarnessArchiveUrl,\n parseHarnessUrl,\n} from '@backstage/integration';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport fetch, { Response } from 'node-fetch';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n assertError,\n AuthenticationError,\n NotFoundError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { Readable } from 'stream';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Harness code v1 api.\n *\n *\n * @public\n */\nexport class HarnessUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n return ScmIntegrations.fromConfig(config)\n .harness.list()\n .map(integration => {\n const reader = new HarnessUrlReader(integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return url.host === integration.config.host;\n };\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: HarnessIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n let response: Response;\n const blobUrl = getHarnessFileContentsUrl(this.integration.config, url);\n\n try {\n response = await fetch(blobUrl, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${blobUrl}, ${e}`);\n }\n\n if (response.ok) {\n // Harness Code returns the raw content object\n const jsonResponse = { data: response.body };\n if (jsonResponse) {\n return ReadUrlResponseFactory.fromReadable(\n Readable.from(jsonResponse.data),\n {\n etag: response.headers.get('ETag') ?? undefined,\n },\n );\n }\n\n throw new Error(`Unknown json: ${jsonResponse}`);\n }\n\n const message = `${url} x ${blobUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.status === 403) {\n throw new AuthenticationError();\n }\n\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const lastCommitHash = await this.getLastCommitHash(url);\n\n if (options?.etag && options.etag === lastCommitHash) {\n throw new NotModifiedError();\n }\n\n const archiveUri = getHarnessArchiveUrl(this.integration.config, url);\n\n let response: Response;\n try {\n response = await fetch(archiveUri, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${archiveUri}, ${e}`);\n }\n\n const parsedUri = parseHarnessUrl(this.integration.config, url);\n\n return this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(response.body),\n subpath: parsedUri.path,\n etag: lastCommitHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseHarnessUrl(this.integration.config, url);\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 { host } = this.integration.config;\n return `harness{host=${host},authed=${Boolean(\n this.integration.config.token || this.integration.config.apiKey,\n )}}`;\n }\n private async getLastCommitHash(url: string): Promise<string> {\n const commitUri = getHarnessLatestCommitUrl(this.integration.config, url);\n\n const response = await fetch(\n commitUri,\n getHarnessRequestOptions(this.integration.config),\n );\n if (!response.ok) {\n const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return (await response.json()).latest_commit.sha;\n }\n}\n"],"names":["ScmIntegrations","getHarnessFileContentsUrl","fetch","getHarnessRequestOptions","ReadUrlResponseFactory","Readable","NotFoundError","NotModifiedError","AuthenticationError","getHarnessArchiveUrl","parseHarnessUrl","assertError","getHarnessLatestCommitUrl"],"mappings":";;;;;;;;;;;;AAmDO,MAAM,gBAAA,CAA6C;AAAA,EAexD,WAAA,CACmB,aACA,IAAA,EAGjB;AAJiB,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAGhB;AAAA,EAnBH,OAAO,OAAA,GAAyB,CAAC,EAAE,MAAA,EAAQ,qBAAoB,KAAM;AACnE,IAAA,OAAOA,2BAAA,CAAgB,WAAW,MAAM,CAAA,CACrC,QAAQ,IAAA,EAAK,CACb,IAAI,CAAA,WAAA,KAAe;AAClB,MAAA,MAAM,MAAA,GAAS,IAAI,gBAAA,CAAiB,WAAA,EAAa;AAAA,QAC/C;AAAA,OACD,CAAA;AACD,MAAA,MAAM,SAAA,GAAY,CAAC,GAAA,KAAa;AAC9B,QAAA,OAAO,GAAA,CAAI,IAAA,KAAS,WAAA,CAAY,MAAA,CAAO,IAAA;AAAA,MACzC,CAAA;AACA,MAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAAA,IAC7B,CAAC,CAAA;AAAA,EACL,CAAA;AAAA,EAQA,MAAM,KAAK,GAAA,EAA8B;AACvC,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACvC,IAAA,OAAO,SAAS,MAAA,EAAO;AAAA,EACzB;AAAA,EAEA,MAAM,OAAA,CACJ,GAAA,EACA,OAAA,EAC0C;AAC1C,IAAA,IAAI,QAAA;AACJ,IAAA,MAAM,OAAA,GAAUC,qCAAA,CAA0B,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEtE,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAMC,uBAAM,OAAA,EAAS;AAAA,QAC9B,MAAA,EAAQ,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAA,EAAS;AAAA,OAClB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,OAAO,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IACnD;AAEA,IAAA,IAAI,SAAS,EAAA,EAAI;AAEf,MAAA,MAAM,YAAA,GAAe,EAAE,IAAA,EAAM,QAAA,CAAS,IAAA,EAAK;AAC3C,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,OAAOC,6CAAA,CAAuB,YAAA;AAAA,UAC5BC,eAAA,CAAS,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA;AAAA,UAC/B;AAAA,YACE,IAAA,EAAM,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,IAAK;AAAA;AACxC,SACF;AAAA,MACF;AAEA,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,YAAY,CAAA,CAAE,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,GAAA,EAAM,OAAO,KAAK,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,UAAU,CAAA,CAAA;AAC9E,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,qBAAc,OAAO,CAAA;AAAA,IACjC;AAEA,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,uBAAA,EAAiB;AAAA,IAC7B;AAEA,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,0BAAA,EAAoB;AAAA,IAChC;AAEA,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAAA,EAEA,MAAM,QAAA,CACJ,GAAA,EACA,OAAA,EAC2C;AAC3C,IAAA,MAAM,cAAA,GAAiB,MAAM,IAAA,CAAK,iBAAA,CAAkB,GAAG,CAAA;AAEvD,IAAA,IAAI,OAAA,EAAS,IAAA,IAAQ,OAAA,CAAQ,IAAA,KAAS,cAAA,EAAgB;AACpD,MAAA,MAAM,IAAID,uBAAA,EAAiB;AAAA,IAC7B;AAEA,IAAA,MAAM,UAAA,GAAaE,gCAAA,CAAqB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEpE,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAMP,uBAAM,UAAA,EAAY;AAAA,QACjC,MAAA,EAAQ,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAA,EAAS;AAAA,OAClB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,UAAU,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IACtD;AAEA,IAAA,MAAM,SAAA,GAAYO,2BAAA,CAAgB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE9D,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,mBAAA,CAAoB,cAAA,CAAe;AAAA,MAClD,MAAA,EAAQL,eAAA,CAAS,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAAA,MACnC,SAAS,SAAA,CAAU,IAAA;AAAA,MACnB,IAAA,EAAM,cAAA;AAAA,MACN,QAAQ,OAAA,EAAS;AAAA,KAClB,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,MAAA,CACJ,GAAA,EACA,OAAA,EACyC;AACzC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAIK,4BAAgB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE7D,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,IAClD;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,OAAO,CAAA;AAE5C,MAAA,OAAO;AAAA,QACL,KAAA,EAAO;AAAA,UACL;AAAA,YACE,GAAA;AAAA,YACA,SAAS,IAAA,CAAK,MAAA;AAAA,YACd,gBAAgB,IAAA,CAAK;AAAA;AACvB,SACF;AAAA,QACA,IAAA,EAAM,KAAK,IAAA,IAAQ;AAAA,OACrB;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAAC,kBAAA,CAAY,KAAK,CAAA;AACjB,MAAA,IAAI,KAAA,CAAM,SAAS,eAAA,EAAiB;AAClC,QAAA,OAAO;AAAA,UACL,OAAO,EAAC;AAAA,UACR,IAAA,EAAM;AAAA,SACR;AAAA,MACF;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,QAAA,GAAW;AACT,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,IAAA,CAAK,WAAA,CAAY,MAAA;AAClC,IAAA,OAAO,CAAA,aAAA,EAAgB,IAAI,CAAA,QAAA,EAAW,OAAA;AAAA,MACpC,KAAK,WAAA,CAAY,MAAA,CAAO,KAAA,IAAS,IAAA,CAAK,YAAY,MAAA,CAAO;AAAA,KAC1D,CAAA,CAAA,CAAA;AAAA,EACH;AAAA,EACA,MAAc,kBAAkB,GAAA,EAA8B;AAC5D,IAAA,MAAM,SAAA,GAAYC,qCAAA,CAA0B,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAExE,IAAA,MAAM,WAAW,MAAMV,sBAAA;AAAA,MACrB,SAAA;AAAA,MACAC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM;AAAA,KAClD;AACA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,OAAA,GAAU,qDAAqD,SAAS,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA,CAAA;AACzH,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,MAAM,IAAIG,qBAAc,OAAO,CAAA;AAAA,MACjC;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAA,CAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,EAAG,aAAA,CAAc,GAAA;AAAA,EAC/C;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadUrlResponseFactory.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { ConflictError } from '@backstage/errors';\nimport { UrlReaderServiceReadUrlResponse } from '@backstage/backend-plugin-api';\nimport getRawBody from 'raw-body';\nimport { Readable } from 'stream';\nimport { ReadUrlResponseFactoryFromStreamOptions } from './types';\nimport { parseLastModified, responseToReadable } from './util';\n\n/**\n * Utility class for UrlReader implementations to create valid ReadUrlResponse\n * instances from common response primitives.\n *\n * @public\n */\nexport class ReadUrlResponseFactory {\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from a Readable stream.\n */\n static async fromReadable(\n stream: Readable,\n options?: ReadUrlResponseFactoryFromStreamOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // Reference to eventual buffer enables callers to call buffer() multiple\n // times without consequence.\n let buffer: Promise<Buffer>;\n\n // Prevent \"stream is not readable\" errors from bubbling up.\n const conflictError = new ConflictError(\n 'Cannot use buffer() and stream() from the same ReadUrlResponse',\n );\n let hasCalledStream = false;\n let hasCalledBuffer = false;\n\n return {\n buffer: () => {\n hasCalledBuffer = true;\n if (hasCalledStream) throw conflictError;\n if (buffer) return buffer;\n buffer = getRawBody(stream);\n return buffer;\n },\n stream: () => {\n hasCalledStream = true;\n if (hasCalledBuffer) throw conflictError;\n return stream;\n },\n etag: options?.etag,\n lastModifiedAt: options?.lastModifiedAt,\n };\n }\n\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from an old-style NodeJS.ReadableStream.\n */\n static async fromNodeJSReadable(\n oldStyleStream: NodeJS.ReadableStream,\n options?: ReadUrlResponseFactoryFromStreamOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const readable = Readable.from(oldStyleStream);\n return ReadUrlResponseFactory.fromReadable(readable, options);\n }\n\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from a native fetch response body.\n */\n static async fromResponse(\n response: Response,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const etag = response.headers.get('etag') || undefined;\n const lastModifiedAt = parseLastModified(\n response.headers.get('last-modified'),\n );\n\n return ReadUrlResponseFactory.fromReadable(responseToReadable(response), {\n etag,\n lastModifiedAt,\n });\n }\n}\n"],"names":["ConflictError","getRawBody","Readable","parseLastModified","responseToReadable"],"mappings":";;;;;;;;;;;AA6BO,MAAM,
|
|
1
|
+
{"version":3,"file":"ReadUrlResponseFactory.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { ConflictError } from '@backstage/errors';\nimport { UrlReaderServiceReadUrlResponse } from '@backstage/backend-plugin-api';\nimport getRawBody from 'raw-body';\nimport { Readable } from 'stream';\nimport { ReadUrlResponseFactoryFromStreamOptions } from './types';\nimport { parseLastModified, responseToReadable } from './util';\n\n/**\n * Utility class for UrlReader implementations to create valid ReadUrlResponse\n * instances from common response primitives.\n *\n * @public\n */\nexport class ReadUrlResponseFactory {\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from a Readable stream.\n */\n static async fromReadable(\n stream: Readable,\n options?: ReadUrlResponseFactoryFromStreamOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // Reference to eventual buffer enables callers to call buffer() multiple\n // times without consequence.\n let buffer: Promise<Buffer>;\n\n // Prevent \"stream is not readable\" errors from bubbling up.\n const conflictError = new ConflictError(\n 'Cannot use buffer() and stream() from the same ReadUrlResponse',\n );\n let hasCalledStream = false;\n let hasCalledBuffer = false;\n\n return {\n buffer: () => {\n hasCalledBuffer = true;\n if (hasCalledStream) throw conflictError;\n if (buffer) return buffer;\n buffer = getRawBody(stream);\n return buffer;\n },\n stream: () => {\n hasCalledStream = true;\n if (hasCalledBuffer) throw conflictError;\n return stream;\n },\n etag: options?.etag,\n lastModifiedAt: options?.lastModifiedAt,\n };\n }\n\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from an old-style NodeJS.ReadableStream.\n */\n static async fromNodeJSReadable(\n oldStyleStream: NodeJS.ReadableStream,\n options?: ReadUrlResponseFactoryFromStreamOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const readable = Readable.from(oldStyleStream);\n return ReadUrlResponseFactory.fromReadable(readable, options);\n }\n\n /**\n * Resolves a UrlReaderServiceReadUrlResponse from a native fetch response body.\n */\n static async fromResponse(\n response: Response,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const etag = response.headers.get('etag') || undefined;\n const lastModifiedAt = parseLastModified(\n response.headers.get('last-modified'),\n );\n\n return ReadUrlResponseFactory.fromReadable(responseToReadable(response), {\n etag,\n lastModifiedAt,\n });\n }\n}\n"],"names":["ConflictError","getRawBody","Readable","parseLastModified","responseToReadable"],"mappings":";;;;;;;;;;;AA6BO,MAAM,sBAAA,CAAuB;AAAA;AAAA;AAAA;AAAA,EAIlC,aAAa,YAAA,CACX,MAAA,EACA,OAAA,EAC0C;AAG1C,IAAA,IAAI,MAAA;AAGJ,IAAA,MAAM,gBAAgB,IAAIA,oBAAA;AAAA,MACxB;AAAA,KACF;AACA,IAAA,IAAI,eAAA,GAAkB,KAAA;AACtB,IAAA,IAAI,eAAA,GAAkB,KAAA;AAEtB,IAAA,OAAO;AAAA,MACL,QAAQ,MAAM;AACZ,QAAA,eAAA,GAAkB,IAAA;AAClB,QAAA,IAAI,iBAAiB,MAAM,aAAA;AAC3B,QAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,QAAA,MAAA,GAASC,4BAAW,MAAM,CAAA;AAC1B,QAAA,OAAO,MAAA;AAAA,MACT,CAAA;AAAA,MACA,QAAQ,MAAM;AACZ,QAAA,eAAA,GAAkB,IAAA;AAClB,QAAA,IAAI,iBAAiB,MAAM,aAAA;AAC3B,QAAA,OAAO,MAAA;AAAA,MACT,CAAA;AAAA,MACA,MAAM,OAAA,EAAS,IAAA;AAAA,MACf,gBAAgB,OAAA,EAAS;AAAA,KAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,kBAAA,CACX,cAAA,EACA,OAAA,EAC0C;AAC1C,IAAA,MAAM,QAAA,GAAWC,eAAA,CAAS,IAAA,CAAK,cAAc,CAAA;AAC7C,IAAA,OAAO,sBAAA,CAAuB,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,aACX,QAAA,EAC0C;AAC1C,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,IAAK,MAAA;AAC7C,IAAA,MAAM,cAAA,GAAiBC,sBAAA;AAAA,MACrB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,eAAe;AAAA,KACtC;AAEA,IAAA,OAAO,sBAAA,CAAuB,YAAA,CAAaC,uBAAA,CAAmB,QAAQ,CAAA,EAAG;AAAA,MACvE,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UrlReaderPredicateMux.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaderPredicateMux.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 {\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { UrlReaderPredicateTuple } from './types';\n\nfunction notAllowedMessage(url: string) {\n return (\n `Reading from '${url}' is not allowed. ` +\n `You may need to configure an integration for the target host, or add it ` +\n `to the configured list of allowed hosts at 'backend.reading.allow'`\n );\n}\n\n/**\n * A UrlReaderService implementation that selects from a set of readers\n * based on a predicate tied to each reader.\n */\nexport class UrlReaderPredicateMux implements UrlReaderService {\n private readonly readers: UrlReaderPredicateTuple[] = [];\n\n register(tuple: UrlReaderPredicateTuple): void {\n this.readers.push(tuple);\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return reader.readUrl(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return await reader.readTree(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return await reader.search(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n toString() {\n return `predicateMux{readers=${this.readers.map(t => t.reader).join(',')}`;\n }\n}\n"],"names":["NotAllowedError"],"mappings":";;;;AA4BA,SAAS,kBAAkB,
|
|
1
|
+
{"version":3,"file":"UrlReaderPredicateMux.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaderPredicateMux.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 {\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { UrlReaderPredicateTuple } from './types';\n\nfunction notAllowedMessage(url: string) {\n return (\n `Reading from '${url}' is not allowed. ` +\n `You may need to configure an integration for the target host, or add it ` +\n `to the configured list of allowed hosts at 'backend.reading.allow'`\n );\n}\n\n/**\n * A UrlReaderService implementation that selects from a set of readers\n * based on a predicate tied to each reader.\n */\nexport class UrlReaderPredicateMux implements UrlReaderService {\n private readonly readers: UrlReaderPredicateTuple[] = [];\n\n register(tuple: UrlReaderPredicateTuple): void {\n this.readers.push(tuple);\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return reader.readUrl(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return await reader.readTree(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const parsed = new URL(url);\n\n for (const { predicate, reader } of this.readers) {\n if (predicate(parsed)) {\n return await reader.search(url, options);\n }\n }\n\n throw new NotAllowedError(notAllowedMessage(url));\n }\n\n toString() {\n return `predicateMux{readers=${this.readers.map(t => t.reader).join(',')}`;\n }\n}\n"],"names":["NotAllowedError"],"mappings":";;;;AA4BA,SAAS,kBAAkB,GAAA,EAAa;AACtC,EAAA,OACE,iBAAiB,GAAG,CAAA,4JAAA,CAAA;AAIxB;AAMO,MAAM,qBAAA,CAAkD;AAAA,EAC5C,UAAqC,EAAC;AAAA,EAEvD,SAAS,KAAA,EAAsC;AAC7C,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,MAAM,OAAA,CACJ,GAAA,EACA,OAAA,EAC0C;AAC1C,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAE1B,IAAA,KAAA,MAAW,EAAE,SAAA,EAAW,MAAA,EAAO,IAAK,KAAK,OAAA,EAAS;AAChD,MAAA,IAAI,SAAA,CAAU,MAAM,CAAA,EAAG;AACrB,QAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,GAAA,EAAK,OAAO,CAAA;AAAA,MACpC;AAAA,IACF;AAEA,IAAA,MAAM,IAAIA,sBAAA,CAAgB,iBAAA,CAAkB,GAAG,CAAC,CAAA;AAAA,EAClD;AAAA,EAEA,MAAM,QAAA,CACJ,GAAA,EACA,OAAA,EAC2C;AAC3C,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAE1B,IAAA,KAAA,MAAW,EAAE,SAAA,EAAW,MAAA,EAAO,IAAK,KAAK,OAAA,EAAS;AAChD,MAAA,IAAI,SAAA,CAAU,MAAM,CAAA,EAAG;AACrB,QAAA,OAAO,MAAM,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,OAAO,CAAA;AAAA,MAC3C;AAAA,IACF;AAEA,IAAA,MAAM,IAAIA,sBAAA,CAAgB,iBAAA,CAAkB,GAAG,CAAC,CAAA;AAAA,EAClD;AAAA,EAEA,MAAM,MAAA,CACJ,GAAA,EACA,OAAA,EACyC;AACzC,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAE1B,IAAA,KAAA,MAAW,EAAE,SAAA,EAAW,MAAA,EAAO,IAAK,KAAK,OAAA,EAAS;AAChD,MAAA,IAAI,SAAA,CAAU,MAAM,CAAA,EAAG;AACrB,QAAA,OAAO,MAAM,MAAA,CAAO,MAAA,CAAO,GAAA,EAAK,OAAO,CAAA;AAAA,MACzC;AAAA,IACF;AAEA,IAAA,MAAM,IAAIA,sBAAA,CAAgB,iBAAA,CAAkB,GAAG,CAAC,CAAA;AAAA,EAClD;AAAA,EAEA,QAAA,GAAW;AACT,IAAA,OAAO,CAAA,qBAAA,EAAwB,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,MAAM,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,EAC1E;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UrlReaders.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaders.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 {\n LoggerService,\n RootConfigService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory } from './types';\nimport { UrlReaderPredicateMux } from './UrlReaderPredicateMux';\nimport { AzureUrlReader } from './AzureUrlReader';\nimport { BitbucketCloudUrlReader } from './BitbucketCloudUrlReader';\nimport { BitbucketServerUrlReader } from './BitbucketServerUrlReader';\nimport { BitbucketUrlReader } from './BitbucketUrlReader';\nimport { GerritUrlReader } from './GerritUrlReader';\nimport { GithubUrlReader } from './GithubUrlReader';\nimport { GitlabUrlReader } from './GitlabUrlReader';\nimport { DefaultReadTreeResponseFactory } from './tree';\nimport { FetchUrlReader } from './FetchUrlReader';\nimport { GoogleGcsUrlReader } from './GoogleGcsUrlReader';\nimport { AwsS3UrlReader } from './AwsS3UrlReader';\nimport { GiteaUrlReader } from './GiteaUrlReader';\nimport { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader';\nimport { HarnessUrlReader } from './HarnessUrlReader';\nimport { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader';\n\n/**\n * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.\n *\n * @public\n */\nexport type UrlReadersOptions = {\n /** Root config object */\n config: RootConfigService;\n /** Logger used by all the readers */\n logger: LoggerService;\n /** A list of factories used to construct individual readers that match on URLs */\n factories?: ReaderFactory[];\n};\n\n/**\n * Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.\n *\n * @public\n */\nexport class UrlReaders {\n /**\n * Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.\n */\n static create(options: UrlReadersOptions): UrlReaderService {\n const { logger, config, factories } = options;\n const mux = new UrlReaderPredicateMux();\n const treeResponseFactory = DefaultReadTreeResponseFactory.create({\n config,\n });\n for (const factory of factories ?? []) {\n const tuples = factory({ config, logger: logger, treeResponseFactory });\n\n for (const tuple of tuples) {\n mux.register(tuple);\n }\n }\n\n return mux;\n }\n\n /**\n * Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories\n * from this package.\n *\n * Any additional factories passed will be loaded before the default ones.\n */\n static default(options: UrlReadersOptions) {\n const { logger, config, factories = [] } = options;\n return UrlReaders.create({\n logger,\n config,\n factories: factories.concat([\n AzureUrlReader.factory,\n BitbucketCloudUrlReader.factory,\n BitbucketServerUrlReader.factory,\n BitbucketUrlReader.factory,\n GerritUrlReader.factory,\n GithubUrlReader.factory,\n GiteaUrlReader.factory,\n GitlabUrlReader.factory,\n GoogleGcsUrlReader.factory,\n HarnessUrlReader.factory,\n AwsS3UrlReader.factory,\n AzureBlobStorageUrlReader.factory,\n AwsCodeCommitUrlReader.factory,\n FetchUrlReader.factory,\n ]),\n });\n }\n}\n"],"names":["UrlReaderPredicateMux","DefaultReadTreeResponseFactory","AzureUrlReader","BitbucketCloudUrlReader","BitbucketServerUrlReader","BitbucketUrlReader","GerritUrlReader","GithubUrlReader","GiteaUrlReader","GitlabUrlReader","GoogleGcsUrlReader","HarnessUrlReader","AwsS3UrlReader","AzureBlobStorageUrlReader","AwsCodeCommitUrlReader","FetchUrlReader"],"mappings":";;;;;;;;;;;;;;;;;;;AA0DO,MAAM,
|
|
1
|
+
{"version":3,"file":"UrlReaders.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaders.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 {\n LoggerService,\n RootConfigService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory } from './types';\nimport { UrlReaderPredicateMux } from './UrlReaderPredicateMux';\nimport { AzureUrlReader } from './AzureUrlReader';\nimport { BitbucketCloudUrlReader } from './BitbucketCloudUrlReader';\nimport { BitbucketServerUrlReader } from './BitbucketServerUrlReader';\nimport { BitbucketUrlReader } from './BitbucketUrlReader';\nimport { GerritUrlReader } from './GerritUrlReader';\nimport { GithubUrlReader } from './GithubUrlReader';\nimport { GitlabUrlReader } from './GitlabUrlReader';\nimport { DefaultReadTreeResponseFactory } from './tree';\nimport { FetchUrlReader } from './FetchUrlReader';\nimport { GoogleGcsUrlReader } from './GoogleGcsUrlReader';\nimport { AwsS3UrlReader } from './AwsS3UrlReader';\nimport { GiteaUrlReader } from './GiteaUrlReader';\nimport { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader';\nimport { HarnessUrlReader } from './HarnessUrlReader';\nimport { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader';\n\n/**\n * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.\n *\n * @public\n */\nexport type UrlReadersOptions = {\n /** Root config object */\n config: RootConfigService;\n /** Logger used by all the readers */\n logger: LoggerService;\n /** A list of factories used to construct individual readers that match on URLs */\n factories?: ReaderFactory[];\n};\n\n/**\n * Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.\n *\n * @public\n */\nexport class UrlReaders {\n /**\n * Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.\n */\n static create(options: UrlReadersOptions): UrlReaderService {\n const { logger, config, factories } = options;\n const mux = new UrlReaderPredicateMux();\n const treeResponseFactory = DefaultReadTreeResponseFactory.create({\n config,\n });\n for (const factory of factories ?? []) {\n const tuples = factory({ config, logger: logger, treeResponseFactory });\n\n for (const tuple of tuples) {\n mux.register(tuple);\n }\n }\n\n return mux;\n }\n\n /**\n * Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories\n * from this package.\n *\n * Any additional factories passed will be loaded before the default ones.\n */\n static default(options: UrlReadersOptions) {\n const { logger, config, factories = [] } = options;\n return UrlReaders.create({\n logger,\n config,\n factories: factories.concat([\n AzureUrlReader.factory,\n BitbucketCloudUrlReader.factory,\n BitbucketServerUrlReader.factory,\n BitbucketUrlReader.factory,\n GerritUrlReader.factory,\n GithubUrlReader.factory,\n GiteaUrlReader.factory,\n GitlabUrlReader.factory,\n GoogleGcsUrlReader.factory,\n HarnessUrlReader.factory,\n AwsS3UrlReader.factory,\n AzureBlobStorageUrlReader.factory,\n AwsCodeCommitUrlReader.factory,\n FetchUrlReader.factory,\n ]),\n });\n }\n}\n"],"names":["UrlReaderPredicateMux","DefaultReadTreeResponseFactory","AzureUrlReader","BitbucketCloudUrlReader","BitbucketServerUrlReader","BitbucketUrlReader","GerritUrlReader","GithubUrlReader","GiteaUrlReader","GitlabUrlReader","GoogleGcsUrlReader","HarnessUrlReader","AwsS3UrlReader","AzureBlobStorageUrlReader","AwsCodeCommitUrlReader","FetchUrlReader"],"mappings":";;;;;;;;;;;;;;;;;;;AA0DO,MAAM,UAAA,CAAW;AAAA;AAAA;AAAA;AAAA,EAItB,OAAO,OAAO,OAAA,EAA8C;AAC1D,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU,GAAI,OAAA;AACtC,IAAA,MAAM,GAAA,GAAM,IAAIA,2CAAA,EAAsB;AACtC,IAAA,MAAM,mBAAA,GAAsBC,uDAA+B,MAAA,CAAO;AAAA,MAChE;AAAA,KACD,CAAA;AACD,IAAA,KAAA,MAAW,OAAA,IAAW,SAAA,IAAa,EAAC,EAAG;AACrC,MAAA,MAAM,SAAS,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAgB,qBAAqB,CAAA;AAEtE,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,QAAA,GAAA,CAAI,SAAS,KAAK,CAAA;AAAA,MACpB;AAAA,IACF;AAEA,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,QAAQ,OAAA,EAA4B;AACzC,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,GAAY,IAAG,GAAI,OAAA;AAC3C,IAAA,OAAO,WAAW,MAAA,CAAO;AAAA,MACvB,MAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA,EAAW,UAAU,MAAA,CAAO;AAAA,QAC1BC,6BAAA,CAAe,OAAA;AAAA,QACfC,+CAAA,CAAwB,OAAA;AAAA,QACxBC,iDAAA,CAAyB,OAAA;AAAA,QACzBC,qCAAA,CAAmB,OAAA;AAAA,QACnBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,6BAAA,CAAe,OAAA;AAAA,QACfC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,qCAAA,CAAmB,OAAA;AAAA,QACnBC,iCAAA,CAAiB,OAAA;AAAA,QACjBC,6BAAA,CAAe,OAAA;AAAA,QACfC,mDAAA,CAA0B,OAAA;AAAA,QAC1BC,6CAAA,CAAuB,OAAA;AAAA,QACvBC,6BAAA,CAAe;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadTreeResponseFactory.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.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 os from 'os';\nimport { Readable } from 'stream';\nimport { Config } from '@backstage/config';\nimport {\n ReadTreeResponseFactoryOptions,\n ReadTreeResponseFactory,\n FromReadableArrayOptions,\n} from '../types';\nimport { TarArchiveResponse } from './TarArchiveResponse';\nimport { ZipArchiveResponse } from './ZipArchiveResponse';\nimport { ReadableArrayResponse } from './ReadableArrayResponse';\nimport { UrlReaderServiceReadTreeResponse } from '@backstage/backend-plugin-api';\nimport { responseToReadable } from '../util';\n\nexport class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory {\n static create(options: { config: Config }): DefaultReadTreeResponseFactory {\n return new DefaultReadTreeResponseFactory(\n options.config.getOptionalString('backend.workingDirectory') ??\n os.tmpdir(),\n );\n }\n\n constructor(private readonly workDir: string) {}\n\n async fromTarArchive(\n options: ReadTreeResponseFactoryOptions & {\n stripFirstDirectory?: boolean;\n },\n ): Promise<UrlReaderServiceReadTreeResponse> {\n let stream: Readable;\n let etag: string;\n if ('stream' in options) {\n stream = options.stream;\n etag = options.etag;\n } else {\n stream = responseToReadable(options.response);\n etag = (options.etag ?? options.response.headers.get('etag')) || '';\n }\n\n return new TarArchiveResponse(\n stream,\n options.subpath ?? '',\n this.workDir,\n etag,\n options.filter,\n options.stripFirstDirectory ?? true,\n );\n }\n\n async fromZipArchive(\n options: ReadTreeResponseFactoryOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n let stream: Readable;\n let etag: string;\n if ('stream' in options) {\n stream = options.stream;\n etag = options.etag;\n } else {\n stream = responseToReadable(options.response);\n etag = (options.etag ?? options.response.headers.get('etag')) || '';\n }\n\n return new ZipArchiveResponse(\n stream,\n options.subpath ?? '',\n this.workDir,\n etag,\n options.filter,\n );\n }\n\n async fromReadableArray(\n options: FromReadableArrayOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n return new ReadableArrayResponse(options, this.workDir, '');\n }\n}\n"],"names":["os","responseToReadable","TarArchiveResponse","ZipArchiveResponse","ReadableArrayResponse"],"mappings":";;;;;;;;;;;;AA8BO,MAAM,
|
|
1
|
+
{"version":3,"file":"ReadTreeResponseFactory.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.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 os from 'os';\nimport { Readable } from 'stream';\nimport { Config } from '@backstage/config';\nimport {\n ReadTreeResponseFactoryOptions,\n ReadTreeResponseFactory,\n FromReadableArrayOptions,\n} from '../types';\nimport { TarArchiveResponse } from './TarArchiveResponse';\nimport { ZipArchiveResponse } from './ZipArchiveResponse';\nimport { ReadableArrayResponse } from './ReadableArrayResponse';\nimport { UrlReaderServiceReadTreeResponse } from '@backstage/backend-plugin-api';\nimport { responseToReadable } from '../util';\n\nexport class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory {\n static create(options: { config: Config }): DefaultReadTreeResponseFactory {\n return new DefaultReadTreeResponseFactory(\n options.config.getOptionalString('backend.workingDirectory') ??\n os.tmpdir(),\n );\n }\n\n constructor(private readonly workDir: string) {}\n\n async fromTarArchive(\n options: ReadTreeResponseFactoryOptions & {\n stripFirstDirectory?: boolean;\n },\n ): Promise<UrlReaderServiceReadTreeResponse> {\n let stream: Readable;\n let etag: string;\n if ('stream' in options) {\n stream = options.stream;\n etag = options.etag;\n } else {\n stream = responseToReadable(options.response);\n etag = (options.etag ?? options.response.headers.get('etag')) || '';\n }\n\n return new TarArchiveResponse(\n stream,\n options.subpath ?? '',\n this.workDir,\n etag,\n options.filter,\n options.stripFirstDirectory ?? true,\n );\n }\n\n async fromZipArchive(\n options: ReadTreeResponseFactoryOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n let stream: Readable;\n let etag: string;\n if ('stream' in options) {\n stream = options.stream;\n etag = options.etag;\n } else {\n stream = responseToReadable(options.response);\n etag = (options.etag ?? options.response.headers.get('etag')) || '';\n }\n\n return new ZipArchiveResponse(\n stream,\n options.subpath ?? '',\n this.workDir,\n etag,\n options.filter,\n );\n }\n\n async fromReadableArray(\n options: FromReadableArrayOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n return new ReadableArrayResponse(options, this.workDir, '');\n }\n}\n"],"names":["os","responseToReadable","TarArchiveResponse","ZipArchiveResponse","ReadableArrayResponse"],"mappings":";;;;;;;;;;;;AA8BO,MAAM,8BAAA,CAAkE;AAAA,EAQ7E,YAA6B,OAAA,EAAiB;AAAjB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAAkB;AAAA,EAP/C,OAAO,OAAO,OAAA,EAA6D;AACzE,IAAA,OAAO,IAAI,8BAAA;AAAA,MACT,QAAQ,MAAA,CAAO,iBAAA,CAAkB,0BAA0B,CAAA,IACzDA,oBAAG,MAAA;AAAO,KACd;AAAA,EACF;AAAA,EAIA,MAAM,eACJ,OAAA,EAG2C;AAC3C,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,YAAY,OAAA,EAAS;AACvB,MAAA,MAAA,GAAS,OAAA,CAAQ,MAAA;AACjB,MAAA,IAAA,GAAO,OAAA,CAAQ,IAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,MAAA,GAASC,uBAAA,CAAmB,QAAQ,QAAQ,CAAA;AAC5C,MAAA,IAAA,GAAA,CAAQ,QAAQ,IAAA,IAAQ,OAAA,CAAQ,SAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,KAAM,EAAA;AAAA,IACnE;AAEA,IAAA,OAAO,IAAIC,qCAAA;AAAA,MACT,MAAA;AAAA,MACA,QAAQ,OAAA,IAAW,EAAA;AAAA,MACnB,IAAA,CAAK,OAAA;AAAA,MACL,IAAA;AAAA,MACA,OAAA,CAAQ,MAAA;AAAA,MACR,QAAQ,mBAAA,IAAuB;AAAA,KACjC;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OAAA,EAC2C;AAC3C,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,YAAY,OAAA,EAAS;AACvB,MAAA,MAAA,GAAS,OAAA,CAAQ,MAAA;AACjB,MAAA,IAAA,GAAO,OAAA,CAAQ,IAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,MAAA,GAASD,uBAAA,CAAmB,QAAQ,QAAQ,CAAA;AAC5C,MAAA,IAAA,GAAA,CAAQ,QAAQ,IAAA,IAAQ,OAAA,CAAQ,SAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,KAAM,EAAA;AAAA,IACnE;AAEA,IAAA,OAAO,IAAIE,qCAAA;AAAA,MACT,MAAA;AAAA,MACA,QAAQ,OAAA,IAAW,EAAA;AAAA,MACnB,IAAA,CAAK,OAAA;AAAA,MACL,IAAA;AAAA,MACA,OAAA,CAAQ;AAAA,KACV;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,OAAA,EAC2C;AAC3C,IAAA,OAAO,IAAIC,2CAAA,CAAsB,OAAA,EAAS,IAAA,CAAK,SAAS,EAAE,CAAA;AAAA,EAC5D;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReadableArrayResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ReadableArrayResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport concatStream from 'concat-stream';\nimport platformPath, { dirname } from 'path';\nimport getRawBody from 'raw-body';\nimport fs from 'fs-extra';\nimport { promisify } from 'util';\nimport tar from 'tar';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport { FromReadableArrayOptions } from '../types';\n\nconst pipeline = promisify(pipelineCb);\n\n/**\n * Wraps a array of Readable objects into a tree response reader.\n */\nexport class ReadableArrayResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: FromReadableArrayOptions,\n private readonly workDir: string,\n public readonly etag: string,\n ) {\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n\n for (let i = 0; i < this.stream.length; i++) {\n if (!this.stream[i].path.endsWith('/')) {\n files.push({\n path: this.stream[i].path,\n content: () => getRawBody(this.stream[i].data),\n lastModifiedAt: this.stream[i]?.lastModifiedAt,\n });\n }\n }\n\n return files;\n }\n\n async archive(): Promise<NodeJS.ReadableStream> {\n const tmpDir = await this.dir();\n\n try {\n const data = await new Promise<Buffer>(async resolve => {\n await pipeline(\n tar.create({ cwd: tmpDir }, ['']),\n concatStream(resolve),\n );\n });\n return Readable.from(data);\n } finally {\n await fs.remove(tmpDir);\n }\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n for (let i = 0; i < this.stream.length; i++) {\n if (!this.stream[i].path.endsWith('/')) {\n const filePath = platformPath.join(dir, this.stream[i].path);\n await fs.mkdir(dirname(filePath), { recursive: true });\n await pipeline(this.stream[i].data, fs.createWriteStream(filePath));\n }\n }\n\n return dir;\n }\n}\n"],"names":["promisify","pipelineCb","getRawBody","tar","concatStream","Readable","fs","platformPath","dirname"],"mappings":";;;;;;;;;;;;;;;;;;AA8BA,MAAM,QAAA,GAAWA,eAAUC,eAAU,CAAA;AAK9B,MAAM,
|
|
1
|
+
{"version":3,"file":"ReadableArrayResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ReadableArrayResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport concatStream from 'concat-stream';\nimport platformPath, { dirname } from 'path';\nimport getRawBody from 'raw-body';\nimport fs from 'fs-extra';\nimport { promisify } from 'util';\nimport tar from 'tar';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport { FromReadableArrayOptions } from '../types';\n\nconst pipeline = promisify(pipelineCb);\n\n/**\n * Wraps a array of Readable objects into a tree response reader.\n */\nexport class ReadableArrayResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: FromReadableArrayOptions,\n private readonly workDir: string,\n public readonly etag: string,\n ) {\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n\n for (let i = 0; i < this.stream.length; i++) {\n if (!this.stream[i].path.endsWith('/')) {\n files.push({\n path: this.stream[i].path,\n content: () => getRawBody(this.stream[i].data),\n lastModifiedAt: this.stream[i]?.lastModifiedAt,\n });\n }\n }\n\n return files;\n }\n\n async archive(): Promise<NodeJS.ReadableStream> {\n const tmpDir = await this.dir();\n\n try {\n const data = await new Promise<Buffer>(async resolve => {\n await pipeline(\n tar.create({ cwd: tmpDir }, ['']),\n concatStream(resolve),\n );\n });\n return Readable.from(data);\n } finally {\n await fs.remove(tmpDir);\n }\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n for (let i = 0; i < this.stream.length; i++) {\n if (!this.stream[i].path.endsWith('/')) {\n const filePath = platformPath.join(dir, this.stream[i].path);\n await fs.mkdir(dirname(filePath), { recursive: true });\n await pipeline(this.stream[i].data, fs.createWriteStream(filePath));\n }\n }\n\n return dir;\n }\n}\n"],"names":["promisify","pipelineCb","getRawBody","tar","concatStream","Readable","fs","platformPath","dirname"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TarArchiveResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/TarArchiveResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport concatStream from 'concat-stream';\nimport fs from 'fs-extra';\nimport platformPath from 'path';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport tar, { Parse, ParseStream, ReadEntry } from 'tar';\nimport { promisify } from 'util';\nimport { stripFirstDirectoryFromPath } from './util';\n\n// Tar types for `Parse` is not a proper constructor, but it should be\nconst TarParseStream = Parse as unknown as { new (): ParseStream };\n\nconst pipeline = promisify(pipelineCb);\n\n/**\n * Wraps a tar archive stream into a tree response reader.\n */\nexport class TarArchiveResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: Readable,\n private readonly subPath: string,\n private readonly workDir: string,\n public readonly etag: string,\n private readonly filter?: (path: string, info: { size: number }) => boolean,\n private readonly stripFirstDirectory: boolean = true,\n ) {\n if (subPath) {\n if (!subPath.endsWith('/')) {\n this.subPath += '/';\n }\n if (subPath.startsWith('/')) {\n throw new TypeError(\n `TarArchiveResponse subPath must not start with a /, got '${subPath}'`,\n );\n }\n }\n\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n const parser = new TarParseStream();\n\n parser.on('entry', (entry: ReadEntry & Readable) => {\n if (entry.type === 'Directory') {\n entry.resume();\n return;\n }\n\n // File path relative to the root extracted directory. Will remove the\n // top level dir name from the path since its name is hard to predetermine.\n const relativePath = this.stripFirstDirectory\n ? stripFirstDirectoryFromPath(entry.path)\n : entry.path;\n\n if (this.subPath) {\n if (!relativePath.startsWith(this.subPath)) {\n entry.resume();\n return;\n }\n }\n\n const path = relativePath.slice(this.subPath.length);\n if (this.filter) {\n if (!this.filter(path, { size: entry.remain })) {\n entry.resume();\n return;\n }\n }\n\n const content = new Promise<Buffer>(async resolve => {\n await pipeline(entry, concatStream(resolve));\n });\n\n files.push({\n path,\n content: () => content,\n });\n\n entry.resume();\n });\n\n await pipeline(this.stream, parser);\n\n return files;\n }\n\n async archive(): Promise<Readable> {\n if (!this.subPath) {\n this.onlyOnce();\n\n return this.stream;\n }\n\n // TODO(Rugvip): method for repacking a tar with a subpath is to simply extract into a\n // tmp dir and recreate the archive. Would be nicer to stream things instead.\n const tmpDir = await this.dir();\n\n try {\n const data = await new Promise<Buffer>(async resolve => {\n await pipeline(\n tar.create({ cwd: tmpDir }, ['']),\n concatStream(resolve),\n );\n });\n return Readable.from(data);\n } finally {\n await fs.remove(tmpDir);\n }\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n // Equivalent of tar --strip-components=N\n // When no subPath is given, remove just 1 top level directory\n let strip = this.subPath ? this.subPath.split('/').length : 1;\n if (!this.stripFirstDirectory) {\n strip--;\n }\n\n let filterError: Error | undefined = undefined;\n await pipeline(\n this.stream,\n tar.extract({\n strip,\n cwd: dir,\n filter: (path, stat) => {\n // Filter errors will short-circuit the rest of the filtering and then throw\n if (filterError) {\n return false;\n }\n\n // File path relative to the root extracted directory. Will remove the\n // top level dir name from the path since its name is hard to predetermine.\n const relativePath = this.stripFirstDirectory\n ? stripFirstDirectoryFromPath(path)\n : path;\n if (this.subPath && !relativePath.startsWith(this.subPath)) {\n return false;\n }\n if (this.filter) {\n const innerPath = path.split('/').slice(strip).join('/');\n try {\n return this.filter(innerPath, { size: stat.size });\n } catch (error) {\n filterError = error;\n return false;\n }\n }\n return true;\n },\n }),\n );\n\n if (filterError) {\n // If the dir was provided we don't want to remove it, but if it wasn't it means\n // we created a temporary directory and we should remove it.\n if (!options?.targetDir) {\n await fs.remove(dir).catch(() => {});\n }\n throw filterError;\n }\n\n return dir;\n }\n}\n"],"names":["Parse","promisify","pipelineCb","stripFirstDirectoryFromPath","concatStream","tar","Readable","fs","platformPath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TarArchiveResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/TarArchiveResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport concatStream from 'concat-stream';\nimport fs from 'fs-extra';\nimport platformPath from 'path';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport tar, { Parse, ParseStream, ReadEntry } from 'tar';\nimport { promisify } from 'util';\nimport { stripFirstDirectoryFromPath } from './util';\n\n// Tar types for `Parse` is not a proper constructor, but it should be\nconst TarParseStream = Parse as unknown as { new (): ParseStream };\n\nconst pipeline = promisify(pipelineCb);\n\n/**\n * Wraps a tar archive stream into a tree response reader.\n */\nexport class TarArchiveResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: Readable,\n private readonly subPath: string,\n private readonly workDir: string,\n public readonly etag: string,\n private readonly filter?: (path: string, info: { size: number }) => boolean,\n private readonly stripFirstDirectory: boolean = true,\n ) {\n if (subPath) {\n if (!subPath.endsWith('/')) {\n this.subPath += '/';\n }\n if (subPath.startsWith('/')) {\n throw new TypeError(\n `TarArchiveResponse subPath must not start with a /, got '${subPath}'`,\n );\n }\n }\n\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n const parser = new TarParseStream();\n\n parser.on('entry', (entry: ReadEntry & Readable) => {\n if (entry.type === 'Directory') {\n entry.resume();\n return;\n }\n\n // File path relative to the root extracted directory. Will remove the\n // top level dir name from the path since its name is hard to predetermine.\n const relativePath = this.stripFirstDirectory\n ? stripFirstDirectoryFromPath(entry.path)\n : entry.path;\n\n if (this.subPath) {\n if (!relativePath.startsWith(this.subPath)) {\n entry.resume();\n return;\n }\n }\n\n const path = relativePath.slice(this.subPath.length);\n if (this.filter) {\n if (!this.filter(path, { size: entry.remain })) {\n entry.resume();\n return;\n }\n }\n\n const content = new Promise<Buffer>(async resolve => {\n await pipeline(entry, concatStream(resolve));\n });\n\n files.push({\n path,\n content: () => content,\n });\n\n entry.resume();\n });\n\n await pipeline(this.stream, parser);\n\n return files;\n }\n\n async archive(): Promise<Readable> {\n if (!this.subPath) {\n this.onlyOnce();\n\n return this.stream;\n }\n\n // TODO(Rugvip): method for repacking a tar with a subpath is to simply extract into a\n // tmp dir and recreate the archive. Would be nicer to stream things instead.\n const tmpDir = await this.dir();\n\n try {\n const data = await new Promise<Buffer>(async resolve => {\n await pipeline(\n tar.create({ cwd: tmpDir }, ['']),\n concatStream(resolve),\n );\n });\n return Readable.from(data);\n } finally {\n await fs.remove(tmpDir);\n }\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n // Equivalent of tar --strip-components=N\n // When no subPath is given, remove just 1 top level directory\n let strip = this.subPath ? this.subPath.split('/').length : 1;\n if (!this.stripFirstDirectory) {\n strip--;\n }\n\n let filterError: Error | undefined = undefined;\n await pipeline(\n this.stream,\n tar.extract({\n strip,\n cwd: dir,\n filter: (path, stat) => {\n // Filter errors will short-circuit the rest of the filtering and then throw\n if (filterError) {\n return false;\n }\n\n // File path relative to the root extracted directory. Will remove the\n // top level dir name from the path since its name is hard to predetermine.\n const relativePath = this.stripFirstDirectory\n ? stripFirstDirectoryFromPath(path)\n : path;\n if (this.subPath && !relativePath.startsWith(this.subPath)) {\n return false;\n }\n if (this.filter) {\n const innerPath = path.split('/').slice(strip).join('/');\n try {\n return this.filter(innerPath, { size: stat.size });\n } catch (error) {\n filterError = error;\n return false;\n }\n }\n return true;\n },\n }),\n );\n\n if (filterError) {\n // If the dir was provided we don't want to remove it, but if it wasn't it means\n // we created a temporary directory and we should remove it.\n if (!options?.targetDir) {\n await fs.remove(dir).catch(() => {});\n }\n throw filterError;\n }\n\n return dir;\n }\n}\n"],"names":["Parse","promisify","pipelineCb","stripFirstDirectoryFromPath","concatStream","tar","Readable","fs","platformPath"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZipArchiveResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ZipArchiveResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport archiver from 'archiver';\nimport yauzl, { Entry } from 'yauzl';\nimport fs from 'fs-extra';\nimport platformPath from 'path';\nimport { Readable } from 'stream';\nimport { streamToBuffer } from './util';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\n\n/**\n * Wraps a zip archive stream into a tree response reader.\n */\nexport class ZipArchiveResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: Readable,\n private readonly subPath: string,\n private readonly workDir: string,\n public readonly etag: string,\n private readonly filter?: (path: string, info: { size: number }) => boolean,\n ) {\n if (subPath) {\n if (!subPath.endsWith('/')) {\n this.subPath += '/';\n }\n if (subPath.startsWith('/')) {\n throw new TypeError(\n `ZipArchiveResponse subPath must not start with a /, got '${subPath}'`,\n );\n }\n }\n\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n // File path relative to the root extracted directory or a sub directory if subpath is set.\n private getInnerPath(path: string): string {\n return path.slice(this.subPath.length);\n }\n\n private shouldBeIncluded(entry: Entry): boolean {\n if (this.subPath) {\n if (!entry.fileName.startsWith(this.subPath)) {\n return false;\n }\n }\n if (this.filter) {\n return this.filter(this.getInnerPath(entry.fileName), {\n size: entry.uncompressedSize,\n });\n }\n return true;\n }\n\n private async streamToTemporaryFile(\n stream: Readable,\n ): Promise<{ fileName: string; cleanup: () => Promise<void> }> {\n const tmpDir = await fs.mkdtemp(\n platformPath.join(this.workDir, 'backstage-tmp'),\n );\n const tmpFile = platformPath.join(tmpDir, 'tmp.zip');\n\n const writeStream = fs.createWriteStream(tmpFile);\n\n return new Promise((resolve, reject) => {\n writeStream.on('error', reject);\n writeStream.on('finish', () => {\n writeStream.end();\n resolve({\n fileName: tmpFile,\n cleanup: () => fs.rm(tmpDir, { recursive: true }),\n });\n });\n stream.pipe(writeStream);\n });\n }\n\n private forEveryZipEntry(\n zip: string,\n callback: (entry: Entry, content: Readable) => Promise<void>,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n yauzl.open(zip, { lazyEntries: true }, (err, zipfile) => {\n if (err || !zipfile) {\n reject(err || new Error(`Failed to open zip file ${zip}`));\n return;\n }\n\n zipfile.on('entry', async (entry: Entry) => {\n // Check that the file is not a directory, and that is matches the filter.\n if (!entry.fileName.endsWith('/') && this.shouldBeIncluded(entry)) {\n zipfile.openReadStream(entry, async (openErr, readStream) => {\n if (openErr || !readStream) {\n reject(\n openErr ||\n new Error(`Failed to open zip entry ${entry.fileName}`),\n );\n return;\n }\n\n await callback(entry, readStream);\n zipfile.readEntry();\n });\n } else {\n zipfile.readEntry();\n }\n });\n zipfile.once('end', () => resolve());\n zipfile.on('error', e => reject(e));\n zipfile.readEntry();\n });\n });\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n files.push({\n path: this.getInnerPath(entry.fileName),\n content: async () => await streamToBuffer(content),\n lastModifiedAt: entry.lastModFileTime\n ? new Date(entry.lastModFileTime)\n : undefined,\n });\n });\n\n await temporary.cleanup();\n\n return files;\n }\n\n async archive(): Promise<Readable> {\n this.onlyOnce();\n\n if (!this.subPath) {\n return this.stream;\n }\n\n const archive = archiver('zip');\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n archive.append(await streamToBuffer(content), {\n name: this.getInnerPath(entry.fileName),\n });\n });\n\n archive.finalize();\n\n await temporary.cleanup();\n\n return archive;\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n const entryPath = this.getInnerPath(entry.fileName);\n const dirname = platformPath.dirname(entryPath);\n\n if (dirname) {\n await fs.mkdirp(resolveSafeChildPath(dir, dirname));\n }\n return new Promise(async (resolve, reject) => {\n const file = fs.createWriteStream(resolveSafeChildPath(dir, entryPath));\n file.on('finish', resolve);\n\n content.on('error', reject);\n content.pipe(file);\n });\n });\n\n await temporary.cleanup();\n\n return dir;\n }\n}\n"],"names":["fs","platformPath","yauzl","streamToBuffer","archiver","resolveSafeChildPath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ZipArchiveResponse.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/ZipArchiveResponse.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 {\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadTreeResponseDirOptions,\n UrlReaderServiceReadTreeResponseFile,\n} from '@backstage/backend-plugin-api';\nimport archiver from 'archiver';\nimport yauzl, { Entry } from 'yauzl';\nimport fs from 'fs-extra';\nimport platformPath from 'path';\nimport { Readable } from 'stream';\nimport { streamToBuffer } from './util';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\n\n/**\n * Wraps a zip archive stream into a tree response reader.\n */\nexport class ZipArchiveResponse implements UrlReaderServiceReadTreeResponse {\n private read = false;\n\n constructor(\n private readonly stream: Readable,\n private readonly subPath: string,\n private readonly workDir: string,\n public readonly etag: string,\n private readonly filter?: (path: string, info: { size: number }) => boolean,\n ) {\n if (subPath) {\n if (!subPath.endsWith('/')) {\n this.subPath += '/';\n }\n if (subPath.startsWith('/')) {\n throw new TypeError(\n `ZipArchiveResponse subPath must not start with a /, got '${subPath}'`,\n );\n }\n }\n\n this.etag = etag;\n }\n\n // Make sure the input stream is only read once\n private onlyOnce() {\n if (this.read) {\n throw new Error('Response has already been read');\n }\n this.read = true;\n }\n\n // File path relative to the root extracted directory or a sub directory if subpath is set.\n private getInnerPath(path: string): string {\n return path.slice(this.subPath.length);\n }\n\n private shouldBeIncluded(entry: Entry): boolean {\n if (this.subPath) {\n if (!entry.fileName.startsWith(this.subPath)) {\n return false;\n }\n }\n if (this.filter) {\n return this.filter(this.getInnerPath(entry.fileName), {\n size: entry.uncompressedSize,\n });\n }\n return true;\n }\n\n private async streamToTemporaryFile(\n stream: Readable,\n ): Promise<{ fileName: string; cleanup: () => Promise<void> }> {\n const tmpDir = await fs.mkdtemp(\n platformPath.join(this.workDir, 'backstage-tmp'),\n );\n const tmpFile = platformPath.join(tmpDir, 'tmp.zip');\n\n const writeStream = fs.createWriteStream(tmpFile);\n\n return new Promise((resolve, reject) => {\n writeStream.on('error', reject);\n writeStream.on('finish', () => {\n writeStream.end();\n resolve({\n fileName: tmpFile,\n cleanup: () => fs.rm(tmpDir, { recursive: true }),\n });\n });\n stream.pipe(writeStream);\n });\n }\n\n private forEveryZipEntry(\n zip: string,\n callback: (entry: Entry, content: Readable) => Promise<void>,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n yauzl.open(zip, { lazyEntries: true }, (err, zipfile) => {\n if (err || !zipfile) {\n reject(err || new Error(`Failed to open zip file ${zip}`));\n return;\n }\n\n zipfile.on('entry', async (entry: Entry) => {\n // Check that the file is not a directory, and that is matches the filter.\n if (!entry.fileName.endsWith('/') && this.shouldBeIncluded(entry)) {\n zipfile.openReadStream(entry, async (openErr, readStream) => {\n if (openErr || !readStream) {\n reject(\n openErr ||\n new Error(`Failed to open zip entry ${entry.fileName}`),\n );\n return;\n }\n\n await callback(entry, readStream);\n zipfile.readEntry();\n });\n } else {\n zipfile.readEntry();\n }\n });\n zipfile.once('end', () => resolve());\n zipfile.on('error', e => reject(e));\n zipfile.readEntry();\n });\n });\n }\n\n async files(): Promise<UrlReaderServiceReadTreeResponseFile[]> {\n this.onlyOnce();\n const files = Array<UrlReaderServiceReadTreeResponseFile>();\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n files.push({\n path: this.getInnerPath(entry.fileName),\n content: async () => await streamToBuffer(content),\n lastModifiedAt: entry.lastModFileTime\n ? new Date(entry.lastModFileTime)\n : undefined,\n });\n });\n\n await temporary.cleanup();\n\n return files;\n }\n\n async archive(): Promise<Readable> {\n this.onlyOnce();\n\n if (!this.subPath) {\n return this.stream;\n }\n\n const archive = archiver('zip');\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n archive.append(await streamToBuffer(content), {\n name: this.getInnerPath(entry.fileName),\n });\n });\n\n archive.finalize();\n\n await temporary.cleanup();\n\n return archive;\n }\n\n async dir(\n options?: UrlReaderServiceReadTreeResponseDirOptions,\n ): Promise<string> {\n this.onlyOnce();\n const dir =\n options?.targetDir ??\n (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-')));\n\n const temporary = await this.streamToTemporaryFile(this.stream);\n\n await this.forEveryZipEntry(temporary.fileName, async (entry, content) => {\n const entryPath = this.getInnerPath(entry.fileName);\n const dirname = platformPath.dirname(entryPath);\n\n if (dirname) {\n await fs.mkdirp(resolveSafeChildPath(dir, dirname));\n }\n return new Promise(async (resolve, reject) => {\n const file = fs.createWriteStream(resolveSafeChildPath(dir, entryPath));\n file.on('finish', resolve);\n\n content.on('error', reject);\n content.pipe(file);\n });\n });\n\n await temporary.cleanup();\n\n return dir;\n }\n}\n"],"names":["fs","platformPath","yauzl","streamToBuffer","archiver","resolveSafeChildPath"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/util.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 { Readable, pipeline as pipelineCb } from 'stream';\nimport { promisify } from 'util';\nimport concatStream from 'concat-stream';\n\nconst pipeline = promisify(pipelineCb);\n\n// Matches a directory name + one `/` at the start of any string,\n// containing any character except `/` one or more times, and ending with a `/`\n// e.g. Will match `dirA/` in `dirA/dirB/file.ext`\nconst directoryNameRegex = /^[^\\/]+\\//;\n// Removes the first segment of a forward-slash-separated path\nexport function stripFirstDirectoryFromPath(path: string): string {\n return path.replace(directoryNameRegex, '');\n}\n\n// Collect the stream into a buffer and return\nexport const streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise(async (resolve, reject) => {\n try {\n await pipeline(stream, concatStream(resolve));\n } catch (ex) {\n reject(ex);\n }\n });\n};\n"],"names":["promisify","pipelineCb","concatStream"],"mappings":";;;;;;;;;;AAoBA,MAAM,QAAA,GAAWA,eAAUC,eAAU,CAAA;AAKrC,MAAM,
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../../../../src/entrypoints/urlReader/lib/tree/util.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 { Readable, pipeline as pipelineCb } from 'stream';\nimport { promisify } from 'util';\nimport concatStream from 'concat-stream';\n\nconst pipeline = promisify(pipelineCb);\n\n// Matches a directory name + one `/` at the start of any string,\n// containing any character except `/` one or more times, and ending with a `/`\n// e.g. Will match `dirA/` in `dirA/dirB/file.ext`\nconst directoryNameRegex = /^[^\\/]+\\//;\n// Removes the first segment of a forward-slash-separated path\nexport function stripFirstDirectoryFromPath(path: string): string {\n return path.replace(directoryNameRegex, '');\n}\n\n// Collect the stream into a buffer and return\nexport const streamToBuffer = (stream: Readable): Promise<Buffer> => {\n return new Promise(async (resolve, reject) => {\n try {\n await pipeline(stream, concatStream(resolve));\n } catch (ex) {\n reject(ex);\n }\n });\n};\n"],"names":["promisify","pipelineCb","concatStream"],"mappings":";;;;;;;;;;AAoBA,MAAM,QAAA,GAAWA,eAAUC,eAAU,CAAA;AAKrC,MAAM,kBAAA,GAAqB,WAAA;AAEpB,SAAS,4BAA4B,IAAA,EAAsB;AAChE,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,kBAAA,EAAoB,EAAE,CAAA;AAC5C;AAGO,MAAM,cAAA,GAAiB,CAAC,MAAA,KAAsC;AACnE,EAAA,OAAO,IAAI,OAAA,CAAQ,OAAO,OAAA,EAAS,MAAA,KAAW;AAC5C,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,CAAS,MAAA,EAAQC,6BAAA,CAAa,OAAO,CAAC,CAAA;AAAA,IAC9C,SAAS,EAAA,EAAI;AACX,MAAA,MAAA,CAAO,EAAE,CAAA;AAAA,IACX;AAAA,EACF,CAAC,CAAA;AACH;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { PassThrough, Readable } from 'stream';\nimport { ReadableStream as WebReadableStream } from 'stream/web';\n\nexport function parseLastModified(\n value: string | null | undefined,\n): Date | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const result = new Date(value);\n result.toISOString(); // triggers exception if input was invalid\n return result;\n } catch {\n return undefined;\n }\n}\n\nexport function responseToReadable(response: Response): Readable {\n return response.body\n ? Readable.from(toWeb(response.body))\n : new PassThrough().end();\n}\n\n// The NodeJS ReadableStream is that fetch returns is super basic and not even\n// iterable. This function converts it to the smarter, iterable stream/web\n// variant instead.\nexport function toWeb(\n responseBody: ReadableStream<Uint8Array>,\n): WebReadableStream<Uint8Array> {\n const reader = responseBody.getReader();\n return new WebReadableStream({\n async pull(controller) {\n const { value, done } = await reader.read();\n if (value) {\n controller.enqueue(value);\n }\n if (done) {\n controller.close();\n }\n },\n });\n}\n"],"names":["Readable","PassThrough","WebReadableStream"],"mappings":";;;;;AAmBO,SAAS,kBACd,
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { PassThrough, Readable } from 'stream';\nimport { ReadableStream as WebReadableStream } from 'stream/web';\n\nexport function parseLastModified(\n value: string | null | undefined,\n): Date | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const result = new Date(value);\n result.toISOString(); // triggers exception if input was invalid\n return result;\n } catch {\n return undefined;\n }\n}\n\nexport function responseToReadable(response: Response): Readable {\n return response.body\n ? Readable.from(toWeb(response.body))\n : new PassThrough().end();\n}\n\n// The NodeJS ReadableStream is that fetch returns is super basic and not even\n// iterable. This function converts it to the smarter, iterable stream/web\n// variant instead.\nexport function toWeb(\n responseBody: ReadableStream<Uint8Array>,\n): WebReadableStream<Uint8Array> {\n const reader = responseBody.getReader();\n return new WebReadableStream({\n async pull(controller) {\n const { value, done } = await reader.read();\n if (value) {\n controller.enqueue(value);\n }\n if (done) {\n controller.close();\n }\n },\n });\n}\n"],"names":["Readable","PassThrough","WebReadableStream"],"mappings":";;;;;AAmBO,SAAS,kBACd,KAAA,EACkB;AAClB,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,IAAA,CAAK,KAAK,CAAA;AAC7B,IAAA,MAAA,CAAO,WAAA,EAAY;AACnB,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,QAAA,EAA8B;AAC/D,EAAA,OAAO,QAAA,CAAS,IAAA,GACZA,eAAA,CAAS,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,IAAI,CAAC,CAAA,GAClC,IAAIC,kBAAA,EAAY,CAAE,GAAA,EAAI;AAC5B;AAKO,SAAS,MACd,YAAA,EAC+B;AAC/B,EAAA,MAAM,MAAA,GAAS,aAAa,SAAA,EAAU;AACtC,EAAA,OAAO,IAAIC,kBAAA,CAAkB;AAAA,IAC3B,MAAM,KAAK,UAAA,EAAY;AACrB,MAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAK,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,UAAA,CAAW,QAAQ,KAAK,CAAA;AAAA,MAC1B;AACA,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,UAAA,CAAW,KAAA,EAAM;AAAA,MACnB;AAAA,IACF;AAAA,GACD,CAAA;AACH;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urlReaderServiceFactory.cjs.js","sources":["../../../src/entrypoints/urlReader/urlReaderServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 } from './lib';\nimport { UrlReaders } from './lib/UrlReaders';\nimport {\n coreServices,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\n\n/**\n * @public\n * A non-singleton reference to URL Reader factory services.\n *\n * @example\n * Creating a service factory implementation for a Custom URL Reader.\n * ```ts\n * createServiceFactory({\n * service: urlReaderFactoriesServiceRef,\n * deps: {},\n * async factory() {\n * return CustomUrlReader.factory;\n * },\n * });\n * ```\n */\nexport const urlReaderFactoriesServiceRef = createServiceRef<ReaderFactory>({\n id: 'core.urlReader.factories',\n scope: 'plugin',\n multiton: true,\n});\n\n/**\n * Reading content from external systems.\n *\n * See {@link @backstage/code-plugin-api#UrlReaderService}\n * and {@link https://backstage.io/docs/backend-system/core-services/url-reader | the service docs}\n * for more information.\n *\n * @public\n */\nexport const urlReaderServiceFactory = createServiceFactory({\n service: coreServices.urlReader,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n factories: urlReaderFactoriesServiceRef,\n },\n async factory({ config, logger, factories }) {\n return UrlReaders.default({\n config,\n logger,\n factories,\n });\n },\n});\n"],"names":["createServiceRef","createServiceFactory","coreServices","UrlReaders"],"mappings":";;;;;AAwCO,MAAM,+BAA+BA,
|
|
1
|
+
{"version":3,"file":"urlReaderServiceFactory.cjs.js","sources":["../../../src/entrypoints/urlReader/urlReaderServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 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 } from './lib';\nimport { UrlReaders } from './lib/UrlReaders';\nimport {\n coreServices,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\n\n/**\n * @public\n * A non-singleton reference to URL Reader factory services.\n *\n * @example\n * Creating a service factory implementation for a Custom URL Reader.\n * ```ts\n * createServiceFactory({\n * service: urlReaderFactoriesServiceRef,\n * deps: {},\n * async factory() {\n * return CustomUrlReader.factory;\n * },\n * });\n * ```\n */\nexport const urlReaderFactoriesServiceRef = createServiceRef<ReaderFactory>({\n id: 'core.urlReader.factories',\n scope: 'plugin',\n multiton: true,\n});\n\n/**\n * Reading content from external systems.\n *\n * See {@link @backstage/code-plugin-api#UrlReaderService}\n * and {@link https://backstage.io/docs/backend-system/core-services/url-reader | the service docs}\n * for more information.\n *\n * @public\n */\nexport const urlReaderServiceFactory = createServiceFactory({\n service: coreServices.urlReader,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n factories: urlReaderFactoriesServiceRef,\n },\n async factory({ config, logger, factories }) {\n return UrlReaders.default({\n config,\n logger,\n factories,\n });\n },\n});\n"],"names":["createServiceRef","createServiceFactory","coreServices","UrlReaders"],"mappings":";;;;;AAwCO,MAAM,+BAA+BA,iCAAA,CAAgC;AAAA,EAC1E,EAAA,EAAI,0BAAA;AAAA,EACJ,KAAA,EAAO,QAAA;AAAA,EACP,QAAA,EAAU;AACZ,CAAC;AAWM,MAAM,0BAA0BC,qCAAA,CAAqB;AAAA,EAC1D,SAASC,6BAAA,CAAa,SAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,QAAQA,6BAAA,CAAa,UAAA;AAAA,IACrB,QAAQA,6BAAA,CAAa,MAAA;AAAA,IACrB,SAAA,EAAW;AAAA,GACb;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAQ,WAAU,EAAG;AAC3C,IAAA,OAAOC,sBAAW,OAAA,CAAQ;AAAA,MACxB,MAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultUserInfoService.cjs.js","sources":["../../../src/entrypoints/userInfo/DefaultUserInfoService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UserInfoService,\n BackstageUserInfo,\n DiscoveryService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { decodeJwt } from 'jose';\nimport { toInternalBackstageCredentials } from '../auth/helpers';\n\nexport type Options = {\n discovery: DiscoveryService;\n};\n\nexport class DefaultUserInfoService implements UserInfoService {\n private readonly discovery: DiscoveryService;\n\n constructor(options: Options) {\n this.discovery = options.discovery;\n }\n\n async getUserInfo(\n credentials: BackstageCredentials,\n ): Promise<BackstageUserInfo> {\n const internalCredentials = toInternalBackstageCredentials(credentials);\n if (internalCredentials.principal.type !== 'user') {\n throw new Error('Only user credentials are supported');\n }\n if (!internalCredentials.token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n const { sub: userEntityRef, ent: tokenEnt } = decodeJwt(\n internalCredentials.token,\n );\n\n if (typeof userEntityRef !== 'string') {\n throw new Error('User entity ref must be a string');\n }\n\n let ownershipEntityRefs = tokenEnt;\n\n if (!ownershipEntityRefs) {\n const userInfoResp = await fetch(\n `${await this.discovery.getBaseUrl('auth')}/v1/userinfo`,\n {\n headers: {\n Authorization: `Bearer ${internalCredentials.token}`,\n },\n },\n );\n\n if (!userInfoResp.ok) {\n throw await ResponseError.fromResponse(userInfoResp);\n }\n\n const {\n claims: { ent },\n } = await userInfoResp.json();\n ownershipEntityRefs = ent;\n }\n\n if (!ownershipEntityRefs) {\n throw new Error('Ownership entity refs can not be determined');\n } else if (\n !Array.isArray(ownershipEntityRefs) ||\n ownershipEntityRefs.some(ref => typeof ref !== 'string')\n ) {\n throw new Error('Ownership entity refs must be an array of strings');\n }\n\n return { userEntityRef, ownershipEntityRefs };\n }\n}\n"],"names":["toInternalBackstageCredentials","decodeJwt","ResponseError"],"mappings":";;;;;;AA8BO,MAAM,
|
|
1
|
+
{"version":3,"file":"DefaultUserInfoService.cjs.js","sources":["../../../src/entrypoints/userInfo/DefaultUserInfoService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UserInfoService,\n BackstageUserInfo,\n DiscoveryService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { decodeJwt } from 'jose';\nimport { toInternalBackstageCredentials } from '../auth/helpers';\n\nexport type Options = {\n discovery: DiscoveryService;\n};\n\nexport class DefaultUserInfoService implements UserInfoService {\n private readonly discovery: DiscoveryService;\n\n constructor(options: Options) {\n this.discovery = options.discovery;\n }\n\n async getUserInfo(\n credentials: BackstageCredentials,\n ): Promise<BackstageUserInfo> {\n const internalCredentials = toInternalBackstageCredentials(credentials);\n if (internalCredentials.principal.type !== 'user') {\n throw new Error('Only user credentials are supported');\n }\n if (!internalCredentials.token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n const { sub: userEntityRef, ent: tokenEnt } = decodeJwt(\n internalCredentials.token,\n );\n\n if (typeof userEntityRef !== 'string') {\n throw new Error('User entity ref must be a string');\n }\n\n let ownershipEntityRefs = tokenEnt;\n\n if (!ownershipEntityRefs) {\n const userInfoResp = await fetch(\n `${await this.discovery.getBaseUrl('auth')}/v1/userinfo`,\n {\n headers: {\n Authorization: `Bearer ${internalCredentials.token}`,\n },\n },\n );\n\n if (!userInfoResp.ok) {\n throw await ResponseError.fromResponse(userInfoResp);\n }\n\n const {\n claims: { ent },\n } = await userInfoResp.json();\n ownershipEntityRefs = ent;\n }\n\n if (!ownershipEntityRefs) {\n throw new Error('Ownership entity refs can not be determined');\n } else if (\n !Array.isArray(ownershipEntityRefs) ||\n ownershipEntityRefs.some(ref => typeof ref !== 'string')\n ) {\n throw new Error('Ownership entity refs must be an array of strings');\n }\n\n return { userEntityRef, ownershipEntityRefs };\n }\n}\n"],"names":["toInternalBackstageCredentials","decodeJwt","ResponseError"],"mappings":";;;;;;AA8BO,MAAM,sBAAA,CAAkD;AAAA,EAC5C,SAAA;AAAA,EAEjB,YAAY,OAAA,EAAkB;AAC5B,IAAA,IAAA,CAAK,YAAY,OAAA,CAAQ,SAAA;AAAA,EAC3B;AAAA,EAEA,MAAM,YACJ,WAAA,EAC4B;AAC5B,IAAA,MAAM,mBAAA,GAAsBA,uCAA+B,WAAW,CAAA;AACtE,IAAA,IAAI,mBAAA,CAAoB,SAAA,CAAU,IAAA,KAAS,MAAA,EAAQ;AACjD,MAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,IACvD;AACA,IAAA,IAAI,CAAC,oBAAoB,KAAA,EAAO;AAC9B,MAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,IAClE;AACA,IAAA,MAAM,EAAE,GAAA,EAAK,aAAA,EAAe,GAAA,EAAK,UAAS,GAAIC,cAAA;AAAA,MAC5C,mBAAA,CAAoB;AAAA,KACtB;AAEA,IAAA,IAAI,OAAO,kBAAkB,QAAA,EAAU;AACrC,MAAA,MAAM,IAAI,MAAM,kCAAkC,CAAA;AAAA,IACpD;AAEA,IAAA,IAAI,mBAAA,GAAsB,QAAA;AAE1B,IAAA,IAAI,CAAC,mBAAA,EAAqB;AACxB,MAAA,MAAM,eAAe,MAAM,KAAA;AAAA,QACzB,GAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA,CAAW,MAAM,CAAC,CAAA,YAAA,CAAA;AAAA,QAC1C;AAAA,UACE,OAAA,EAAS;AAAA,YACP,aAAA,EAAe,CAAA,OAAA,EAAU,mBAAA,CAAoB,KAAK,CAAA;AAAA;AACpD;AACF,OACF;AAEA,MAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AACpB,QAAA,MAAM,MAAMC,oBAAA,CAAc,YAAA,CAAa,YAAY,CAAA;AAAA,MACrD;AAEA,MAAA,MAAM;AAAA,QACJ,MAAA,EAAQ,EAAE,GAAA;AAAI,OAChB,GAAI,MAAM,YAAA,CAAa,IAAA,EAAK;AAC5B,MAAA,mBAAA,GAAsB,GAAA;AAAA,IACxB;AAEA,IAAA,IAAI,CAAC,mBAAA,EAAqB;AACxB,MAAA,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAAA,IAC/D,CAAA,MAAA,IACE,CAAC,KAAA,CAAM,OAAA,CAAQ,mBAAmB,CAAA,IAClC,mBAAA,CAAoB,IAAA,CAAK,CAAA,GAAA,KAAO,OAAO,GAAA,KAAQ,QAAQ,CAAA,EACvD;AACA,MAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,IACrE;AAEA,IAAA,OAAO,EAAE,eAAe,mBAAA,EAAoB;AAAA,EAC9C;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userInfoServiceFactory.cjs.js","sources":["../../../src/entrypoints/userInfo/userInfoServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultUserInfoService } from './DefaultUserInfoService';\n\n/**\n * Authenticated user information retrieval.\n *\n * See {@link @backstage/code-plugin-api#UserInfoService}\n * and {@link https://backstage.io/docs/backend-system/core-services/user-info | the service docs}\n * for more information.\n *\n * @public\n */\nexport const userInfoServiceFactory = createServiceFactory({\n service: coreServices.userInfo,\n deps: {\n discovery: coreServices.discovery,\n },\n async factory({ discovery }) {\n return new DefaultUserInfoService({ discovery });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultUserInfoService"],"mappings":";;;;;AA+BO,MAAM,yBAAyBA,
|
|
1
|
+
{"version":3,"file":"userInfoServiceFactory.cjs.js","sources":["../../../src/entrypoints/userInfo/userInfoServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultUserInfoService } from './DefaultUserInfoService';\n\n/**\n * Authenticated user information retrieval.\n *\n * See {@link @backstage/code-plugin-api#UserInfoService}\n * and {@link https://backstage.io/docs/backend-system/core-services/user-info | the service docs}\n * for more information.\n *\n * @public\n */\nexport const userInfoServiceFactory = createServiceFactory({\n service: coreServices.userInfo,\n deps: {\n discovery: coreServices.discovery,\n },\n async factory({ discovery }) {\n return new DefaultUserInfoService({ discovery });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultUserInfoService"],"mappings":";;;;;AA+BO,MAAM,yBAAyBA,qCAAA,CAAqB;AAAA,EACzD,SAASC,6BAAA,CAAa,QAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,WAAWA,6BAAA,CAAa;AAAA,GAC1B;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,SAAA,EAAU,EAAG;AAC3B,IAAA,OAAO,IAAIC,6CAAA,CAAuB,EAAE,SAAA,EAAW,CAAA;AAAA,EACjD;AACF,CAAC;;;;"}
|
package/dist/httpAuth.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
import { AuthService, DiscoveryService,
|
|
2
|
+
import { HttpAuthService, AuthService, DiscoveryService, BackstagePrincipalTypes, BackstageCredentials } from '@backstage/backend-plugin-api';
|
|
3
3
|
import { Request, Response } from 'express';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitStoreFactory.cjs.js","sources":["../../src/lib/RateLimitStoreFactory.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 */\nimport { Config } from '@backstage/config';\nimport type { Store } from 'express-rate-limit';\nimport { RedisStore } from 'rate-limit-redis';\n\n/**\n * Creates a store for `express-rate-limit` based on the configuration.\n *\n * @internal\n */\nexport class RateLimitStoreFactory {\n static create(options: {\n config: Config;\n prefix?: string;\n }): Store | undefined {\n const { config, prefix } = options;\n const store = config.getOptionalConfig('backend.rateLimit.store');\n if (!store) {\n return undefined;\n }\n const type = store.getString('type');\n switch (type) {\n case 'redis':\n return this.redis({ store, prefix });\n case 'memory':\n default:\n return undefined;\n }\n }\n\n private static redis(options: { store: Config; prefix?: string }): Store {\n const { store, prefix } = options;\n const connectionString = store.getString('connection');\n const KeyvRedis = require('@keyv/redis').default;\n const keyv = new KeyvRedis(connectionString);\n return new RedisStore({\n prefix,\n sendCommand: async (...args: string[]) => {\n const client = await keyv.getClient();\n return client.sendCommand(args);\n },\n });\n }\n}\n"],"names":["RedisStore"],"mappings":";;;;AAwBO,MAAM,
|
|
1
|
+
{"version":3,"file":"RateLimitStoreFactory.cjs.js","sources":["../../src/lib/RateLimitStoreFactory.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 */\nimport { Config } from '@backstage/config';\nimport type { Store } from 'express-rate-limit';\nimport { RedisStore } from 'rate-limit-redis';\n\n/**\n * Creates a store for `express-rate-limit` based on the configuration.\n *\n * @internal\n */\nexport class RateLimitStoreFactory {\n static create(options: {\n config: Config;\n prefix?: string;\n }): Store | undefined {\n const { config, prefix } = options;\n const store = config.getOptionalConfig('backend.rateLimit.store');\n if (!store) {\n return undefined;\n }\n const type = store.getString('type');\n switch (type) {\n case 'redis':\n return this.redis({ store, prefix });\n case 'memory':\n default:\n return undefined;\n }\n }\n\n private static redis(options: { store: Config; prefix?: string }): Store {\n const { store, prefix } = options;\n const connectionString = store.getString('connection');\n const KeyvRedis = require('@keyv/redis').default;\n const keyv = new KeyvRedis(connectionString);\n return new RedisStore({\n prefix,\n sendCommand: async (...args: string[]) => {\n const client = await keyv.getClient();\n return client.sendCommand(args);\n },\n });\n }\n}\n"],"names":["RedisStore"],"mappings":";;;;AAwBO,MAAM,qBAAA,CAAsB;AAAA,EACjC,OAAO,OAAO,OAAA,EAGQ;AACpB,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,OAAA;AAC3B,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,iBAAA,CAAkB,yBAAyB,CAAA;AAChE,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,SAAA,CAAU,MAAM,CAAA;AACnC,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,OAAA;AACH,QAAA,OAAO,IAAA,CAAK,KAAA,CAAM,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,MACrC,KAAK,QAAA;AAAA,MACL;AACE,QAAA,OAAO,MAAA;AAAA;AACX,EACF;AAAA,EAEA,OAAe,MAAM,OAAA,EAAoD;AACvE,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAO,GAAI,OAAA;AAC1B,IAAA,MAAM,gBAAA,GAAmB,KAAA,CAAM,SAAA,CAAU,YAAY,CAAA;AACrD,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,aAAa,CAAA,CAAE,OAAA;AACzC,IAAA,MAAM,IAAA,GAAO,IAAI,SAAA,CAAU,gBAAgB,CAAA;AAC3C,IAAA,OAAO,IAAIA,yBAAA,CAAW;AAAA,MACpB,MAAA;AAAA,MACA,WAAA,EAAa,UAAU,IAAA,KAAmB;AACxC,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,OAAO,MAAA,CAAO,YAAY,IAAI,CAAA;AAAA,MAChC;AAAA,KACD,CAAA;AAAA,EACH;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"escapeRegExp.cjs.js","sources":["../../src/lib/escapeRegExp.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\n/**\n * Escapes a given string to be used inside a RegExp.\n *\n * Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\n */\nexport const escapeRegExp = (text: string) => {\n return text.replace(/[.*+?^${}(\\)|[\\]\\\\]/g, '\\\\$&');\n};\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"escapeRegExp.cjs.js","sources":["../../src/lib/escapeRegExp.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\n/**\n * Escapes a given string to be used inside a RegExp.\n *\n * Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\n */\nexport const escapeRegExp = (text: string) => {\n return text.replace(/[.*+?^${}(\\)|[\\]\\\\]/g, '\\\\$&');\n};\n"],"names":[],"mappings":";;AAqBO,MAAM,YAAA,GAAe,CAAC,IAAA,KAAiB;AAC5C,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,MAAM,CAAA;AACpD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimitMiddleware.cjs.js","sources":["../../src/lib/rateLimitMiddleware.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 { RequestHandler } from 'express';\nimport { rateLimit, Store } from 'express-rate-limit';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport const rateLimitMiddleware = (options: {\n store?: Store;\n config?: Config;\n}): RequestHandler => {\n const { store, config } = options;\n let windowMs: number = 60000;\n if (config && config.has('window')) {\n const windowDuration = readDurationFromConfig(config, {\n key: 'window',\n });\n windowMs = durationToMilliseconds(windowDuration);\n }\n const limit = config?.getOptionalNumber('incomingRequestLimit');\n const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [\n '127.0.0.1',\n '0:0:0:0:0:0:0:1',\n '::1',\n ];\n const skipSuccessfulRequests = config?.getOptionalBoolean(\n 'skipSuccessfulRequests',\n );\n const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests');\n const passOnStoreError = config?.getOptionalBoolean('passOnStoreError');\n\n return rateLimit({\n windowMs,\n limit,\n skipSuccessfulRequests,\n message: {\n error: {\n name: 'Error',\n message: `Too many requests, please try again later`,\n },\n response: {\n statusCode: 429,\n },\n },\n statusCode: 429,\n skipFailedRequests,\n passOnStoreError: passOnStoreError,\n keyGenerator(req, _res): string {\n if (!req.ip) {\n return req.socket.remoteAddress!;\n }\n return req.ip;\n },\n skip: (req, _res) => {\n return (\n Boolean(req.ip && ipAllowList.includes(req.ip)) ||\n Boolean(\n req.socket.remoteAddress &&\n ipAllowList.includes(req.socket.remoteAddress),\n )\n );\n },\n validate: {\n trustProxy: false,\n },\n store,\n });\n};\n"],"names":["config","readDurationFromConfig","durationToMilliseconds","rateLimit"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"rateLimitMiddleware.cjs.js","sources":["../../src/lib/rateLimitMiddleware.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 { RequestHandler } from 'express';\nimport { rateLimit, Store } from 'express-rate-limit';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { durationToMilliseconds } from '@backstage/types';\n\nexport const rateLimitMiddleware = (options: {\n store?: Store;\n config?: Config;\n}): RequestHandler => {\n const { store, config } = options;\n let windowMs: number = 60000;\n if (config && config.has('window')) {\n const windowDuration = readDurationFromConfig(config, {\n key: 'window',\n });\n windowMs = durationToMilliseconds(windowDuration);\n }\n const limit = config?.getOptionalNumber('incomingRequestLimit');\n const ipAllowList = config?.getOptionalStringArray('ipAllowList') ?? [\n '127.0.0.1',\n '0:0:0:0:0:0:0:1',\n '::1',\n ];\n const skipSuccessfulRequests = config?.getOptionalBoolean(\n 'skipSuccessfulRequests',\n );\n const skipFailedRequests = config?.getOptionalBoolean('skipFailedRequests');\n const passOnStoreError = config?.getOptionalBoolean('passOnStoreError');\n\n return rateLimit({\n windowMs,\n limit,\n skipSuccessfulRequests,\n message: {\n error: {\n name: 'Error',\n message: `Too many requests, please try again later`,\n },\n response: {\n statusCode: 429,\n },\n },\n statusCode: 429,\n skipFailedRequests,\n passOnStoreError: passOnStoreError,\n keyGenerator(req, _res): string {\n if (!req.ip) {\n return req.socket.remoteAddress!;\n }\n return req.ip;\n },\n skip: (req, _res) => {\n return (\n Boolean(req.ip && ipAllowList.includes(req.ip)) ||\n Boolean(\n req.socket.remoteAddress &&\n ipAllowList.includes(req.socket.remoteAddress),\n )\n );\n },\n validate: {\n trustProxy: false,\n },\n store,\n });\n};\n"],"names":["config","readDurationFromConfig","durationToMilliseconds","rateLimit"],"mappings":";;;;;;AAoBO,MAAM,mBAAA,GAAsB,CAAC,OAAA,KAGd;AACpB,EAAA,MAAM,EAAE,KAAA,UAAOA,QAAA,EAAO,GAAI,OAAA;AAC1B,EAAA,IAAI,QAAA,GAAmB,GAAA;AACvB,EAAA,IAAIA,QAAA,IAAUA,QAAA,CAAO,GAAA,CAAI,QAAQ,CAAA,EAAG;AAClC,IAAA,MAAM,cAAA,GAAiBC,8BAAuBD,QAAA,EAAQ;AAAA,MACpD,GAAA,EAAK;AAAA,KACN,CAAA;AACD,IAAA,QAAA,GAAWE,6BAAuB,cAAc,CAAA;AAAA,EAClD;AACA,EAAA,MAAM,KAAA,GAAQF,QAAA,EAAQ,iBAAA,CAAkB,sBAAsB,CAAA;AAC9D,EAAA,MAAM,WAAA,GAAcA,QAAA,EAAQ,sBAAA,CAAuB,aAAa,CAAA,IAAK;AAAA,IACnE,WAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,yBAAyBA,QAAA,EAAQ,kBAAA;AAAA,IACrC;AAAA,GACF;AACA,EAAA,MAAM,kBAAA,GAAqBA,QAAA,EAAQ,kBAAA,CAAmB,oBAAoB,CAAA;AAC1E,EAAA,MAAM,gBAAA,GAAmBA,QAAA,EAAQ,kBAAA,CAAmB,kBAAkB,CAAA;AAEtE,EAAA,OAAOG,0BAAA,CAAU;AAAA,IACf,QAAA;AAAA,IACA,KAAA;AAAA,IACA,sBAAA;AAAA,IACA,OAAA,EAAS;AAAA,MACP,KAAA,EAAO;AAAA,QACL,IAAA,EAAM,OAAA;AAAA,QACN,OAAA,EAAS,CAAA,yCAAA;AAAA,OACX;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAA,EAAY;AAAA;AACd,KACF;AAAA,IACA,UAAA,EAAY,GAAA;AAAA,IACZ,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAA,CAAa,KAAK,IAAA,EAAc;AAC9B,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,OAAO,IAAI,MAAA,CAAO,aAAA;AAAA,MACpB;AACA,MAAA,OAAO,GAAA,CAAI,EAAA;AAAA,IACb,CAAA;AAAA,IACA,IAAA,EAAM,CAAC,GAAA,EAAK,IAAA,KAAS;AACnB,MAAA,OACE,OAAA,CAAQ,IAAI,EAAA,IAAM,WAAA,CAAY,SAAS,GAAA,CAAI,EAAE,CAAC,CAAA,IAC9C,OAAA;AAAA,QACE,IAAI,MAAA,CAAO,aAAA,IACT,YAAY,QAAA,CAAS,GAAA,CAAI,OAAO,aAAa;AAAA,OACjD;AAAA,IAEJ,CAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACR,UAAA,EAAY;AAAA,KACd;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|