@backstage/backend-defaults 0.12.1 → 0.13.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @backstage/backend-defaults
2
2
 
3
+ ## 0.13.0-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/config-loader@1.10.4-next.0
9
+ - @backstage/config@1.3.4-next.0
10
+ - @backstage/integration@1.18.1-next.1
11
+ - @backstage/integration-aws-node@0.1.18-next.0
12
+ - @backstage/backend-app-api@1.2.8-next.0
13
+ - @backstage/backend-plugin-api@1.4.4-next.0
14
+ - @backstage/plugin-auth-node@0.6.8-next.0
15
+ - @backstage/plugin-permission-node@0.10.5-next.0
16
+ - @backstage/plugin-events-node@0.4.16-next.0
17
+ - @backstage/cli-node@0.2.14
18
+
19
+ ## 0.13.0-next.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 2d3e2b2: implement support for direct url for AzureBlobStorageUrlReader search function
24
+ - 8b91238: Adds support for configuring server-level HTTP options through the
25
+ `app-config.yaml` file under the `backend.server` key. Supported options
26
+ include `headersTimeout`, `keepAliveTimeout`, `requestTimeout`, `timeout`,
27
+ `maxHeadersCount`, and `maxRequestsPerSocket`.
28
+
29
+ These are passed directly to the underlying Node.js HTTP server.
30
+ If omitted, Node.js defaults are used.
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies
35
+ - @backstage/integration@1.18.1-next.0
36
+ - @backstage/backend-app-api@1.2.7
37
+ - @backstage/plugin-auth-node@0.6.7
38
+ - @backstage/plugin-permission-node@0.10.4
39
+ - @backstage/backend-dev-utils@0.1.5
40
+ - @backstage/backend-plugin-api@1.4.3
41
+ - @backstage/cli-node@0.2.14
42
+ - @backstage/config@1.3.3
43
+ - @backstage/config-loader@1.10.3
44
+ - @backstage/errors@1.2.7
45
+ - @backstage/integration-aws-node@0.1.17
46
+ - @backstage/types@1.2.2
47
+ - @backstage/plugin-events-node@0.4.15
48
+
3
49
  ## 0.12.1
4
50
 
5
51
  ### Patch Changes
package/config.d.ts CHANGED
@@ -95,6 +95,31 @@ export interface Config {
95
95
  };
96
96
  };
97
97
 
98
+ /**
99
+ * Server-level HTTP options configuration for the backend.
100
+ * These options are passed directly to the underlying Node.js HTTP server.
101
+ *
102
+ * Timeout values support multiple formats:
103
+ * - A number in milliseconds
104
+ * - A string in the format of '1d', '2 seconds' etc. as supported by the `ms` library
105
+ * - A standard ISO formatted duration string, e.g. 'P2DT6H' or 'PT1M'
106
+ * - An object with individual units (in plural) as keys, e.g. `{ days: 2, hours: 6 }`
107
+ */
108
+ server?: {
109
+ /** Sets the timeout value for receiving the complete HTTP headers from the client. */
110
+ headersTimeout?: number | string | HumanDuration;
111
+ /** Sets the timeout value for receiving the entire request (headers and body) from the client. */
112
+ requestTimeout?: number | string | HumanDuration;
113
+ /** Sets the timeout value for inactivity on a socket during keep-alive. */
114
+ keepAliveTimeout?: number | string | HumanDuration;
115
+ /** Sets the timeout value for sockets. */
116
+ timeout?: number | string | HumanDuration;
117
+ /** Limits maximum incoming headers count. */
118
+ maxHeadersCount?: number;
119
+ /** Sets the maximum number of requests socket can handle before closing keep alive connection. */
120
+ maxRequestsPerSocket?: number;
121
+ };
122
+
98
123
  /**
99
124
  * Options used by the default auditor service.
100
125
  */
@@ -58,6 +58,54 @@ const rootHttpRouterServiceFactoryWithOptions = (options) => backendPluginApi.cr
58
58
  if (trustProxy !== void 0) {
59
59
  app.set("trust proxy", trustProxy);
60
60
  }
61
+ const backendConfig = config$2.getOptionalConfig("backend");
62
+ const serverConfig = backendConfig?.getOptionalConfig("server");
63
+ if (serverConfig) {
64
+ const readDurationValue = (key) => {
65
+ if (!serverConfig.has(key)) {
66
+ return void 0;
67
+ }
68
+ const value = serverConfig.getOptional(key);
69
+ if (typeof value === "number") {
70
+ return value;
71
+ }
72
+ try {
73
+ const duration = config$1.readDurationFromConfig(serverConfig, { key });
74
+ return types.durationToMilliseconds(duration);
75
+ } catch (error) {
76
+ logger.warn(
77
+ `Failed to parse backend.server.${key} as duration: ${error}. Expected a number (milliseconds), duration string (e.g., '30s'), ISO duration (e.g., 'PT30S'), or duration object (e.g., {seconds: 30}). Falling back to number parsing.`
78
+ );
79
+ return void 0;
80
+ }
81
+ };
82
+ const headersTimeout = readDurationValue("headersTimeout");
83
+ if (headersTimeout !== void 0) {
84
+ server.headersTimeout = headersTimeout;
85
+ }
86
+ const requestTimeout = readDurationValue("requestTimeout");
87
+ if (requestTimeout !== void 0) {
88
+ server.requestTimeout = requestTimeout;
89
+ }
90
+ const keepAliveTimeout = readDurationValue("keepAliveTimeout");
91
+ if (keepAliveTimeout !== void 0) {
92
+ server.keepAliveTimeout = keepAliveTimeout;
93
+ }
94
+ const timeout = readDurationValue("timeout");
95
+ if (timeout !== void 0) {
96
+ server.timeout = timeout;
97
+ }
98
+ const maxHeadersCount = serverConfig.getOptionalNumber("maxHeadersCount");
99
+ if (maxHeadersCount !== void 0) {
100
+ server.maxHeadersCount = maxHeadersCount;
101
+ }
102
+ const maxRequestsPerSocket = serverConfig.getOptionalNumber(
103
+ "maxRequestsPerSocket"
104
+ );
105
+ if (maxRequestsPerSocket !== void 0) {
106
+ server.maxRequestsPerSocket = maxRequestsPerSocket;
107
+ }
108
+ }
61
109
  app.use(middleware.helmet());
62
110
  app.use(middleware.cors());
63
111
  app.use(middleware.compression());
@@ -1 +1 @@
1
- {"version":3,"file":"rootHttpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.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 {\n coreServices,\n createServiceFactory,\n LifecycleService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport express, { Express, RequestHandler } from 'express';\nimport type { Server } from 'node:http';\nimport {\n createHttpServer,\n MiddlewareFactory,\n readHttpServerOptions,\n} from './http';\nimport { DefaultRootHttpRouter } from './DefaultRootHttpRouter';\nimport { createHealthRouter } from './createHealthRouter';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { readDurationFromConfig } from '@backstage/config';\n\n/**\n * @public\n */\nexport interface RootHttpRouterConfigureContext {\n app: Express;\n server: Server;\n middleware: MiddlewareFactory;\n routes: RequestHandler;\n config: RootConfigService;\n logger: LoggerService;\n lifecycle: LifecycleService;\n healthRouter: RequestHandler;\n applyDefaults: () => void;\n}\n\n/**\n * HTTP route registration for root services.\n *\n * See {@link @backstage/code-plugin-api#RootHttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport type RootHttpRouterFactoryOptions = {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n\n configure?(context: RootHttpRouterConfigureContext): void;\n};\n\nfunction defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {\n applyDefaults();\n}\n\nconst rootHttpRouterServiceFactoryWithOptions = (\n options?: RootHttpRouterFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n rootLogger: coreServices.rootLogger,\n lifecycle: coreServices.rootLifecycle,\n health: coreServices.rootHealth,\n },\n async factory({ config, rootLogger, lifecycle, health }) {\n const { indexPath, configure = defaultConfigure } = options ?? {};\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n const app = express();\n\n const trustProxy = config.getOptional('backend.trustProxy');\n\n const router = DefaultRootHttpRouter.create({ indexPath });\n const middleware = MiddlewareFactory.create({ config, logger });\n const routes = router.handler();\n\n const healthRouter = createHealthRouter({ config, health });\n\n const server = await createHttpServer(\n app,\n readHttpServerOptions(config.getOptionalConfig('backend')),\n { logger },\n );\n\n configure({\n app,\n server,\n routes,\n middleware,\n config,\n logger,\n lifecycle,\n healthRouter,\n applyDefaults() {\n if (process.env.NODE_ENV === 'development') {\n app.set('json spaces', 2);\n }\n if (trustProxy !== undefined) {\n app.set('trust proxy', trustProxy);\n }\n app.use(middleware.helmet());\n app.use(middleware.cors());\n app.use(middleware.compression());\n app.use(middleware.logging());\n app.use(middleware.rateLimit());\n app.use(healthRouter);\n app.use(routes);\n app.use(middleware.notFound());\n app.use(middleware.error());\n },\n });\n\n if (config.has('backend.lifecycle.serverShutdownDelay')) {\n const serverShutdownDelay = readDurationFromConfig(config, {\n key: 'backend.lifecycle.serverShutdownDelay',\n });\n lifecycle.addBeforeShutdownHook(async () => {\n const timeoutMs = durationToMilliseconds(serverShutdownDelay);\n return await new Promise(resolve => {\n setTimeout(resolve, timeoutMs);\n });\n });\n }\n\n lifecycle.addShutdownHook(() => server.stop());\n\n await server.start();\n\n return router;\n },\n });\n\n/** @public */\nexport const rootHttpRouterServiceFactory = Object.assign(\n rootHttpRouterServiceFactoryWithOptions,\n rootHttpRouterServiceFactoryWithOptions(),\n);\n"],"names":["createServiceFactory","coreServices","config","express","DefaultRootHttpRouter","MiddlewareFactory","createHealthRouter","createHttpServer","readHttpServerOptions","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
1
+ {"version":3,"file":"rootHttpRouterServiceFactory.cjs.js","sources":["../../../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.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 {\n coreServices,\n createServiceFactory,\n LifecycleService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport express, { Express, RequestHandler } from 'express';\nimport type { Server } from 'node:http';\nimport {\n createHttpServer,\n MiddlewareFactory,\n readHttpServerOptions,\n} from './http';\nimport { DefaultRootHttpRouter } from './DefaultRootHttpRouter';\nimport { createHealthRouter } from './createHealthRouter';\nimport { durationToMilliseconds } from '@backstage/types';\nimport { readDurationFromConfig } from '@backstage/config';\n\n/**\n * @public\n */\nexport interface RootHttpRouterConfigureContext {\n app: Express;\n server: Server;\n middleware: MiddlewareFactory;\n routes: RequestHandler;\n config: RootConfigService;\n logger: LoggerService;\n lifecycle: LifecycleService;\n healthRouter: RequestHandler;\n applyDefaults: () => void;\n}\n\n/**\n * HTTP route registration for root services.\n *\n * See {@link @backstage/code-plugin-api#RootHttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport type RootHttpRouterFactoryOptions = {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n\n configure?(context: RootHttpRouterConfigureContext): void;\n};\n\nfunction defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {\n applyDefaults();\n}\n\nconst rootHttpRouterServiceFactoryWithOptions = (\n options?: RootHttpRouterFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n rootLogger: coreServices.rootLogger,\n lifecycle: coreServices.rootLifecycle,\n health: coreServices.rootHealth,\n },\n async factory({ config, rootLogger, lifecycle, health }) {\n const { indexPath, configure = defaultConfigure } = options ?? {};\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n const app = express();\n\n const trustProxy = config.getOptional('backend.trustProxy');\n\n const router = DefaultRootHttpRouter.create({ indexPath });\n const middleware = MiddlewareFactory.create({ config, logger });\n const routes = router.handler();\n\n const healthRouter = createHealthRouter({ config, health });\n\n const server = await createHttpServer(\n app,\n readHttpServerOptions(config.getOptionalConfig('backend')),\n { logger },\n );\n\n configure({\n app,\n server,\n routes,\n middleware,\n config,\n logger,\n lifecycle,\n healthRouter,\n applyDefaults() {\n if (process.env.NODE_ENV === 'development') {\n app.set('json spaces', 2);\n }\n if (trustProxy !== undefined) {\n app.set('trust proxy', trustProxy);\n }\n\n // Apply server-level HTTP options from config\n const backendConfig = config.getOptionalConfig('backend');\n const serverConfig = backendConfig?.getOptionalConfig('server');\n\n if (serverConfig) {\n // Helper function to read duration values (supporting number, string, or HumanDuration)\n const readDurationValue = (key: string): number | undefined => {\n if (!serverConfig.has(key)) {\n return undefined;\n }\n\n const value = serverConfig.getOptional(key);\n if (typeof value === 'number') {\n return value;\n }\n\n // If it's not a number, try to read it as a duration\n try {\n const duration = readDurationFromConfig(serverConfig, { key });\n return durationToMilliseconds(duration);\n } catch (error) {\n // Log warning for parsing failures\n logger.warn(\n `Failed to parse backend.server.${key} as duration: ${error}. ` +\n `Expected a number (milliseconds), duration string (e.g., '30s'), ` +\n `ISO duration (e.g., 'PT30S'), or duration object (e.g., {seconds: 30}). ` +\n `Falling back to number parsing.`,\n );\n return undefined;\n }\n };\n\n // Apply timeout settings\n const headersTimeout = readDurationValue('headersTimeout');\n if (headersTimeout !== undefined) {\n server.headersTimeout = headersTimeout;\n }\n\n const requestTimeout = readDurationValue('requestTimeout');\n if (requestTimeout !== undefined) {\n server.requestTimeout = requestTimeout;\n }\n\n const keepAliveTimeout = readDurationValue('keepAliveTimeout');\n if (keepAliveTimeout !== undefined) {\n server.keepAliveTimeout = keepAliveTimeout;\n }\n\n const timeout = readDurationValue('timeout');\n if (timeout !== undefined) {\n server.timeout = timeout;\n }\n\n // Apply numeric settings\n const maxHeadersCount =\n serverConfig.getOptionalNumber('maxHeadersCount');\n if (maxHeadersCount !== undefined) {\n server.maxHeadersCount = maxHeadersCount;\n }\n\n const maxRequestsPerSocket = serverConfig.getOptionalNumber(\n 'maxRequestsPerSocket',\n );\n if (maxRequestsPerSocket !== undefined) {\n server.maxRequestsPerSocket = maxRequestsPerSocket;\n }\n }\n\n app.use(middleware.helmet());\n app.use(middleware.cors());\n app.use(middleware.compression());\n app.use(middleware.logging());\n app.use(middleware.rateLimit());\n app.use(healthRouter);\n app.use(routes);\n app.use(middleware.notFound());\n app.use(middleware.error());\n },\n });\n\n if (config.has('backend.lifecycle.serverShutdownDelay')) {\n const serverShutdownDelay = readDurationFromConfig(config, {\n key: 'backend.lifecycle.serverShutdownDelay',\n });\n lifecycle.addBeforeShutdownHook(async () => {\n const timeoutMs = durationToMilliseconds(serverShutdownDelay);\n return await new Promise(resolve => {\n setTimeout(resolve, timeoutMs);\n });\n });\n }\n\n lifecycle.addShutdownHook(() => server.stop());\n\n await server.start();\n\n return router;\n },\n });\n\n/** @public */\nexport const rootHttpRouterServiceFactory = Object.assign(\n rootHttpRouterServiceFactoryWithOptions,\n rootHttpRouterServiceFactoryWithOptions(),\n);\n"],"names":["createServiceFactory","coreServices","config","express","DefaultRootHttpRouter","MiddlewareFactory","createHealthRouter","createHttpServer","readHttpServerOptions","readDurationFromConfig","durationToMilliseconds"],"mappings":"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"}
@@ -139,8 +139,29 @@ class AzureBlobStorageUrlReader {
139
139
  );
140
140
  }
141
141
  }
142
- async search() {
143
- throw new Error("AzureBlobStorageUrlReader does not implement search");
142
+ async search(url, options) {
143
+ const { path } = parseUrl(url);
144
+ if (path.match(/[*?]/)) {
145
+ throw new Error(
146
+ "Glob search pattern not implemented for AzureBlobStorageUrlReader"
147
+ );
148
+ }
149
+ try {
150
+ const data = await this.readUrl(url, options);
151
+ return {
152
+ files: [
153
+ {
154
+ url,
155
+ content: data.buffer,
156
+ lastModifiedAt: data.lastModifiedAt
157
+ }
158
+ ],
159
+ etag: data.etag ?? ""
160
+ };
161
+ } catch (error) {
162
+ errors.assertError(error);
163
+ throw error;
164
+ }
144
165
  }
145
166
  toString() {
146
167
  const accountName = this.integration.config.accountName;
@@ -1 +1 @@
1
- {"version":3,"file":"AzureBlobStorageUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.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 BlobDownloadOptions,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { Readable } from 'stream';\nimport { relative } from 'path/posix';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n AzureBlobStorageIntergation,\n AzureCredentialsManager,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\n\nexport function parseUrl(url: string): { path: string; container: string } {\n const parsedUrl = new URL(url);\n const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);\n\n if (pathSegments.length < 1) {\n throw new Error(`Invalid Azure Blob Storage URL format: ${url}`);\n }\n\n // First segment is the container name, rest is the blob path\n const container = pathSegments[0];\n const path = pathSegments.slice(1).join('/');\n\n return { path, container };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure storage accounts urls.\n *\n * @public\n */\nexport class AzureBlobStorageUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n\n const credsManager =\n DefaultAzureCredentialsManager.fromIntegrations(integrations);\n\n return integrations.azureBlobStorage.list().map(integrationConfig => {\n const reader = new AzureBlobStorageUrlReader(\n credsManager,\n integrationConfig,\n {\n treeResponseFactory,\n },\n );\n\n const predicate = (url: URL) =>\n url.host.endsWith(\n `${integrationConfig.config.accountName}.${integrationConfig.config.host}`,\n );\n return { reader, predicate };\n });\n };\n\n // private readonly blobServiceClient: BlobServiceClient;\n\n constructor(\n private readonly credsManager: AzureCredentialsManager,\n private readonly integration: AzureBlobStorageIntergation,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n private async createContainerClient(\n containerName: string,\n ): Promise<ContainerClient> {\n const accountName = this.integration.config.accountName; // Use the account name from the integration config\n const accountKey = this.integration.config.accountKey; // Get the account key if it exists\n\n if (accountKey && accountName) {\n const creds = new StorageSharedKeyCredential(accountName, accountKey);\n const blobServiceClient = new BlobServiceClient(\n `https://${accountName}.${this.integration.config.host}`,\n creds,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n // Use the credentials manager to get the correct credentials\n const credential = await this.credsManager.getCredentials(\n accountName as string,\n );\n\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n const blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n return blobServiceClient.getContainerClient(containerName);\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 const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobClient = containerClient.getBlobClient(path);\n\n const getBlobOptions: BlobDownloadOptions = {\n abortSignal: options?.signal,\n conditions: {\n ...(etag && { ifNoneMatch: etag }),\n ...(lastModifiedAfter && { ifModifiedSince: lastModifiedAfter }),\n },\n };\n\n const downloadBlockBlobResponse = await blobClient.download(\n 0,\n undefined,\n getBlobOptions,\n );\n\n return ReadUrlResponseFactory.fromReadable(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n {\n etag: downloadBlockBlobResponse.etag,\n lastModifiedAt: downloadBlockBlobResponse.lastModified,\n },\n );\n } catch (e) {\n if (e.statusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError(\n 'Could not retrieve file from Azure Blob Storage',\n e,\n );\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n\n const blobs = containerClient.listBlobsFlat({ prefix: path });\n\n const responses = [];\n\n for await (const blob of blobs) {\n const blobClient = containerClient.getBlobClient(blob.name);\n const downloadBlockBlobResponse = await blobClient.download(\n undefined,\n undefined,\n { abortSignal: options?.signal },\n );\n\n responses.push({\n data: Readable.from(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n ),\n path: relative(path, blob.name),\n lastModifiedAt: blob.properties.lastModified,\n });\n }\n\n return this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError(\n 'Could not retrieve file tree from Azure Blob Storage',\n e,\n );\n }\n }\n\n async search(): Promise<UrlReaderServiceSearchResponse> {\n throw new Error('AzureBlobStorageUrlReader does not implement search');\n }\n\n toString() {\n const accountName = this.integration.config.accountName;\n const accountKey = this.integration.config.accountKey;\n return `azureBlobStorage{accountName=${accountName},authed=${Boolean(\n accountKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureCredentialsManager","StorageSharedKeyCredential","blobServiceClient","BlobServiceClient","ReadUrlResponseFactory","NotModifiedError","ForwardedError","Readable","relative"],"mappings":"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"}
1
+ {"version":3,"file":"AzureBlobStorageUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.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 BlobDownloadOptions,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n assertError,\n ForwardedError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { Readable } from 'stream';\nimport { relative } from 'path/posix';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n AzureBlobStorageIntergation,\n AzureCredentialsManager,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\n\nexport function parseUrl(url: string): { path: string; container: string } {\n const parsedUrl = new URL(url);\n const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);\n\n if (pathSegments.length < 1) {\n throw new Error(`Invalid Azure Blob Storage URL format: ${url}`);\n }\n\n // First segment is the container name, rest is the blob path\n const container = pathSegments[0];\n const path = pathSegments.slice(1).join('/');\n\n return { path, container };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure storage accounts urls.\n *\n * @public\n */\nexport class AzureBlobStorageUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n\n const credsManager =\n DefaultAzureCredentialsManager.fromIntegrations(integrations);\n\n return integrations.azureBlobStorage.list().map(integrationConfig => {\n const reader = new AzureBlobStorageUrlReader(\n credsManager,\n integrationConfig,\n {\n treeResponseFactory,\n },\n );\n\n const predicate = (url: URL) =>\n url.host.endsWith(\n `${integrationConfig.config.accountName}.${integrationConfig.config.host}`,\n );\n return { reader, predicate };\n });\n };\n\n // private readonly blobServiceClient: BlobServiceClient;\n\n constructor(\n private readonly credsManager: AzureCredentialsManager,\n private readonly integration: AzureBlobStorageIntergation,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n private async createContainerClient(\n containerName: string,\n ): Promise<ContainerClient> {\n const accountName = this.integration.config.accountName; // Use the account name from the integration config\n const accountKey = this.integration.config.accountKey; // Get the account key if it exists\n\n if (accountKey && accountName) {\n const creds = new StorageSharedKeyCredential(accountName, accountKey);\n const blobServiceClient = new BlobServiceClient(\n `https://${accountName}.${this.integration.config.host}`,\n creds,\n );\n return blobServiceClient.getContainerClient(containerName);\n }\n // Use the credentials manager to get the correct credentials\n const credential = await this.credsManager.getCredentials(\n accountName as string,\n );\n\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n const blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n return blobServiceClient.getContainerClient(containerName);\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 const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobClient = containerClient.getBlobClient(path);\n\n const getBlobOptions: BlobDownloadOptions = {\n abortSignal: options?.signal,\n conditions: {\n ...(etag && { ifNoneMatch: etag }),\n ...(lastModifiedAfter && { ifModifiedSince: lastModifiedAfter }),\n },\n };\n\n const downloadBlockBlobResponse = await blobClient.download(\n 0,\n undefined,\n getBlobOptions,\n );\n\n return ReadUrlResponseFactory.fromReadable(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n {\n etag: downloadBlockBlobResponse.etag,\n lastModifiedAt: downloadBlockBlobResponse.lastModified,\n },\n );\n } catch (e) {\n if (e.statusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError(\n 'Could not retrieve file from Azure Blob Storage',\n e,\n );\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, container } = parseUrl(url);\n\n const containerClient = await this.createContainerClient(container);\n const blobs = containerClient.listBlobsFlat({ prefix: path });\n\n const responses = [];\n\n for await (const blob of blobs) {\n const blobClient = containerClient.getBlobClient(blob.name);\n\n const downloadBlockBlobResponse = await blobClient.download(\n undefined,\n undefined,\n { abortSignal: options?.signal },\n );\n\n responses.push({\n data: Readable.from(\n downloadBlockBlobResponse.readableStreamBody as Readable,\n ),\n path: relative(path, blob.name),\n lastModifiedAt: blob.properties.lastModified,\n });\n }\n\n return this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError(\n 'Could not retrieve file tree from Azure Blob Storage',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url);\n\n if (path.match(/[*?]/)) {\n throw new Error(\n 'Glob search pattern not implemented for AzureBlobStorageUrlReader',\n );\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 throw error;\n }\n }\n\n toString() {\n const accountName = this.integration.config.accountName;\n const accountKey = this.integration.config.accountKey;\n return `azureBlobStorage{accountName=${accountName},authed=${Boolean(\n accountKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureCredentialsManager","StorageSharedKeyCredential","blobServiceClient","BlobServiceClient","ReadUrlResponseFactory","NotModifiedError","ForwardedError","Readable","relative","assertError"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.12.1";
5
+ var version = "0.13.0-next.1";
6
6
  var packageinfo = {
7
7
  version: version};
8
8
 
@@ -363,7 +363,7 @@ declare class AzureBlobStorageUrlReader implements UrlReaderService {
363
363
  read(url: string): Promise<Buffer>;
364
364
  readUrl(url: string, options?: UrlReaderServiceReadUrlOptions): Promise<UrlReaderServiceReadUrlResponse>;
365
365
  readTree(url: string, options?: UrlReaderServiceReadTreeOptions): Promise<UrlReaderServiceReadTreeResponse>;
366
- search(): Promise<UrlReaderServiceSearchResponse>;
366
+ search(url: string, options?: UrlReaderServiceSearchOptions): Promise<UrlReaderServiceSearchResponse>;
367
367
  toString(): string;
368
368
  }
369
369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults",
3
- "version": "0.12.1",
3
+ "version": "0.13.0-next.1",
4
4
  "description": "Backend defaults used by Backstage backend apps",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -216,19 +216,19 @@
216
216
  "@aws-sdk/credential-providers": "^3.350.0",
217
217
  "@aws-sdk/types": "^3.347.0",
218
218
  "@azure/storage-blob": "^12.5.0",
219
- "@backstage/backend-app-api": "^1.2.7",
220
- "@backstage/backend-dev-utils": "^0.1.5",
221
- "@backstage/backend-plugin-api": "^1.4.3",
222
- "@backstage/cli-node": "^0.2.14",
223
- "@backstage/config": "^1.3.3",
224
- "@backstage/config-loader": "^1.10.3",
225
- "@backstage/errors": "^1.2.7",
226
- "@backstage/integration": "^1.18.0",
227
- "@backstage/integration-aws-node": "^0.1.17",
228
- "@backstage/plugin-auth-node": "^0.6.7",
229
- "@backstage/plugin-events-node": "^0.4.15",
230
- "@backstage/plugin-permission-node": "^0.10.4",
231
- "@backstage/types": "^1.2.2",
219
+ "@backstage/backend-app-api": "1.2.8-next.0",
220
+ "@backstage/backend-dev-utils": "0.1.5",
221
+ "@backstage/backend-plugin-api": "1.4.4-next.0",
222
+ "@backstage/cli-node": "0.2.14",
223
+ "@backstage/config": "1.3.4-next.0",
224
+ "@backstage/config-loader": "1.10.4-next.0",
225
+ "@backstage/errors": "1.2.7",
226
+ "@backstage/integration": "1.18.1-next.1",
227
+ "@backstage/integration-aws-node": "0.1.18-next.0",
228
+ "@backstage/plugin-auth-node": "0.6.8-next.0",
229
+ "@backstage/plugin-events-node": "0.4.16-next.0",
230
+ "@backstage/plugin-permission-node": "0.10.5-next.0",
231
+ "@backstage/types": "1.2.2",
232
232
  "@google-cloud/storage": "^7.0.0",
233
233
  "@keyv/memcache": "^2.0.1",
234
234
  "@keyv/redis": "^4.0.1",
@@ -284,9 +284,9 @@
284
284
  },
285
285
  "devDependencies": {
286
286
  "@aws-sdk/util-stream-node": "^3.350.0",
287
- "@backstage/backend-plugin-api": "^1.4.3",
288
- "@backstage/backend-test-utils": "^1.9.0",
289
- "@backstage/cli": "^0.34.2",
287
+ "@backstage/backend-plugin-api": "1.4.4-next.0",
288
+ "@backstage/backend-test-utils": "1.9.1-next.1",
289
+ "@backstage/cli": "0.34.4-next.1",
290
290
  "@google-cloud/cloud-sql-connector": "^1.4.0",
291
291
  "@types/archiver": "^6.0.0",
292
292
  "@types/base64-stream": "^1.0.2",