diff --git a/.changeset/fix-azure-sdk-tests.md b/.changeset/fix-azure-sdk-tests.md new file mode 100644 index 0000000000..a8bac8c1c4 --- /dev/null +++ b/.changeset/fix-azure-sdk-tests.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': patch +'@backstage/integration': patch +--- + +Adapted Azure-related tests for the Azure SDK upgrade to ESM-style exports. The `AzureBlobStorageUrlReader` now accepts an optional `createContainerClient` dependency for testability without needing to mock the `@azure/storage-blob` module. diff --git a/packages/backend-defaults/report-urlReader.api.md b/packages/backend-defaults/report-urlReader.api.md index b3ed68354c..197800ba55 100644 --- a/packages/backend-defaults/report-urlReader.api.md +++ b/packages/backend-defaults/report-urlReader.api.md @@ -12,6 +12,7 @@ import { AzureIntegration } from '@backstage/integration'; import { BitbucketCloudIntegration } from '@backstage/integration'; import { BitbucketServerIntegration } from '@backstage/integration'; import { Config } from '@backstage/config'; +import { ContainerClient } from '@azure/storage-blob'; import { GerritIntegration } from '@backstage/integration'; import { GiteaIntegration } from '@backstage/integration'; import { GithubCredentialsProvider } from '@backstage/integration'; @@ -70,6 +71,9 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { integration: AzureBlobStorageIntegration, deps: { treeResponseFactory: ReadTreeResponseFactory; + createContainerClient?: ( + containerName: string, + ) => Promise; }, ); // (undocumented) diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.test.ts index d78422b993..12392bffd5 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.test.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import * as AzureStorage from '@azure/storage-blob'; import { ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; import { DefaultReadTreeResponseFactory } from './tree'; @@ -27,36 +26,26 @@ import { ScmIntegrations, } from '@backstage/integration'; import { UrlReaderPredicateTuple } from './types'; -import { mockServices } from '@backstage/backend-test-utils'; import { Readable } from 'node:stream'; +import { ContainerClient } from '@azure/storage-blob'; + +const treeResponseFactory = DefaultReadTreeResponseFactory.create({ + config: new ConfigReader({}), +}); -// Mock Azure Blob Storage SDK const mockBlobDownload = jest.fn(); const mockGetBlobClient = jest.fn(() => ({ download: mockBlobDownload, })); const mockListBlobsFlat = jest.fn(); -class MockContainerClient { - getBlobClient = mockGetBlobClient; - listBlobsFlat = mockListBlobsFlat; +function createMockContainerClient(): ContainerClient { + return { + getBlobClient: mockGetBlobClient, + listBlobsFlat: mockListBlobsFlat, + } as unknown as ContainerClient; } -class MockBlobServiceClient { - getContainerClient = jest.fn(() => new MockContainerClient()); -} - -jest - .spyOn(AzureStorage, 'BlobServiceClient') - .mockReturnValue(new MockBlobServiceClient() as any); -jest - .spyOn(AzureStorage, 'StorageSharedKeyCredential') - .mockReturnValue({} as any); - -const treeResponseFactory = DefaultReadTreeResponseFactory.create({ - config: new ConfigReader({}), -}); - describe('parseUrl', () => { it('parses Azure Blob Storage URLs correctly', () => { expect( @@ -96,35 +85,40 @@ describe('parseUrl', () => { describe('AzureBlobStorageUrlReader', () => { const createReader = (config: JsonObject): UrlReaderPredicateTuple[] => { - return AzureBlobStorageUrlReader.factory({ - config: new ConfigReader(config), - logger: mockServices.logger.mock(), - treeResponseFactory, + const integrations = ScmIntegrations.fromConfig(new ConfigReader(config)); + const credsManager = + DefaultAzureCredentialsManager.fromIntegrations(integrations); + + return integrations.azureBlobStorage.list().map(integrationConfig => { + const reader = new AzureBlobStorageUrlReader( + credsManager, + integrationConfig, + { + treeResponseFactory, + createContainerClient: async () => createMockContainerClient(), + }, + ); + const predicate = (url: URL) => + url.host.endsWith( + `${integrationConfig.config.accountName}.${integrationConfig.config.host}`, + ); + return { reader, predicate }; }); }; it('creates a reader with minimal config', () => { const entries = createReader({ integrations: { - azureBlobStorage: [ - { - accountName: 'test-account', - }, - ], + azureBlobStorage: [{ accountName: 'test-account' }], }, }); - expect(entries).toHaveLength(1); }); describe('predicates', () => { const readers = createReader({ integrations: { - azureBlobStorage: [ - { - accountName: 'test-account', - }, - ], + azureBlobStorage: [{ accountName: 'test-account' }], }, }); const predicate = readers[0].predicate; @@ -147,14 +141,10 @@ describe('AzureBlobStorageUrlReader', () => { const config = new ConfigReader({ integrations: { azureBlobStorage: [ - { - accountName: 'test-account', - accountKey: 'test-key', - }, + { accountName: 'test-account', accountKey: 'test-key' }, ], }, }); - const integrations = ScmIntegrations.fromConfig(config); const credsManager = DefaultAzureCredentialsManager.fromIntegrations(integrations); @@ -163,7 +153,6 @@ describe('AzureBlobStorageUrlReader', () => { integrations.azureBlobStorage.list()[0], { treeResponseFactory }, ); - expect(reader.toString()).toBe( 'azureBlobStorage{accountName=test-account,authed=true}', ); @@ -172,14 +161,9 @@ describe('AzureBlobStorageUrlReader', () => { it('shows authed=false when no account key provided', () => { const config = new ConfigReader({ integrations: { - azureBlobStorage: [ - { - accountName: 'test-account', - }, - ], + azureBlobStorage: [{ accountName: 'test-account' }], }, }); - const integrations = ScmIntegrations.fromConfig(config); const credsManager = DefaultAzureCredentialsManager.fromIntegrations(integrations); @@ -188,7 +172,6 @@ describe('AzureBlobStorageUrlReader', () => { integrations.azureBlobStorage.list()[0], { treeResponseFactory }, ); - expect(reader.toString()).toBe( 'azureBlobStorage{accountName=test-account,authed=false}', ); @@ -199,10 +182,7 @@ describe('AzureBlobStorageUrlReader', () => { const [{ reader }] = createReader({ integrations: { azureBlobStorage: [ - { - accountName: 'test-account', - accountKey: 'test-key', - }, + { accountName: 'test-account', accountKey: 'test-key' }, ], }, }); @@ -245,55 +225,38 @@ describe('AzureBlobStorageUrlReader', () => { const [{ reader }] = createReader({ integrations: { azureBlobStorage: [ - { - accountName: 'test-account', - accountKey: 'test-key', - }, + { accountName: 'test-account', accountKey: 'test-key' }, ], }, }); beforeEach(() => { jest.clearAllMocks(); - const mockBlobs = [ - { - name: 'prefix/file1.yaml', - properties: { - lastModified: new Date('2025-01-01T00:00:00Z'), - }, - }, - { - name: 'prefix/subdir/file2.yaml', - properties: { - lastModified: new Date('2024-01-01T00:00:00Z'), - }, - }, - ]; - - mockBlobDownload.mockResolvedValue({ - readableStreamBody: Readable.from( - Buffer.from('site_name: Test Azure Blob'), - ), - }); - - mockListBlobsFlat.mockReturnValue({ - [Symbol.asyncIterator]: async function* generateBlobs() { - for (const blob of mockBlobs) { - yield blob; - } - }, - }); }); it('returns contents of blobs in a container', async () => { + mockListBlobsFlat.mockReturnValue( + (async function* mockIterator() { + yield { + name: 'prefix/file1.yaml', + properties: { lastModified: new Date('2025-01-01T00:00:00Z') }, + }; + yield { + name: 'prefix/file2.yaml', + properties: { lastModified: new Date('2025-01-02T00:00:00Z') }, + }; + })(), + ); + + mockBlobDownload.mockResolvedValue({ + readableStreamBody: Readable.from(Buffer.from('test content')), + }); + const response = await reader.readTree( - 'https://test-account.blob.core.windows.net/test-container/prefix', + 'https://test-account.blob.core.windows.net/test-container/prefix/', ); const files = await response.files(); - expect(files).toHaveLength(2); - const file1Content = await files[0].content(); - expect(file1Content.toString()).toBe('site_name: Test Azure Blob'); }); }); @@ -301,10 +264,7 @@ describe('AzureBlobStorageUrlReader', () => { const [{ reader }] = createReader({ integrations: { azureBlobStorage: [ - { - accountName: 'test-account', - accountKey: 'test-key', - }, + { accountName: 'test-account', accountKey: 'test-key' }, ], }, }); @@ -313,7 +273,7 @@ describe('AzureBlobStorageUrlReader', () => { jest.clearAllMocks(); }); - it('should return a file when given an exact valid url', async () => { + it('returns a file when given an exact valid url', async () => { mockBlobDownload.mockResolvedValue({ readableStreamBody: Readable.from( Buffer.from('site_name: Test Azure Blob'), @@ -322,26 +282,22 @@ describe('AzureBlobStorageUrlReader', () => { lastModified: new Date('2025-01-01T00:00:00Z'), }); - const data = await reader.search( - 'https://test-account.blob.core.windows.net/test-container/test-file.yaml', + const { files } = await reader.search( + 'https://test-account.blob.core.windows.net/test-container/exact-file.yaml', ); - expect(data.etag).toBe('"etag"'); - expect(data.files.length).toBe(1); - expect(data.files[0].url).toBe( - 'https://test-account.blob.core.windows.net/test-container/test-file.yaml', - ); - expect((await data.files[0].content()).toString()).toEqual( - 'site_name: Test Azure Blob', + expect(files).toHaveLength(1); + expect(files[0].url).toBe( + 'https://test-account.blob.core.windows.net/test-container/exact-file.yaml', ); }); - it('should handle Azure SDK errors from readUrl', async () => { + it('handles Azure SDK errors from readUrl', async () => { mockBlobDownload.mockRejectedValue(new Error('Blob not found')); await expect( reader.search( - 'https://test-account.blob.core.windows.net/test-container/missing.yaml', + 'https://test-account.blob.core.windows.net/test-container/nonexistent.yaml', ), ).rejects.toThrow('Could not retrieve file from Azure Blob Storage'); }); @@ -349,7 +305,7 @@ describe('AzureBlobStorageUrlReader', () => { it('throws if given URL with wildcard', async () => { await expect( reader.search( - 'https://test-account.blob.core.windows.net/test-container/test-*.yaml', + 'https://test-account.blob.core.windows.net/test-container/path/to/*.yaml', ), ).rejects.toThrow( 'Glob search pattern not implemented for AzureBlobStorageUrlReader', diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts index 23592d89e3..3da89baadb 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts @@ -85,12 +85,10 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { }); }; - // private readonly blobServiceClient: BlobServiceClient; - - private readonly credsManager: AzureCredentialsManager; private readonly integration: AzureBlobStorageIntegration; private readonly deps: { treeResponseFactory: ReadTreeResponseFactory; + createContainerClient: (containerName: string) => Promise; }; constructor( @@ -98,18 +96,26 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { integration: AzureBlobStorageIntegration, deps: { treeResponseFactory: ReadTreeResponseFactory; + createContainerClient?: ( + containerName: string, + ) => Promise; }, ) { - this.credsManager = credsManager; this.integration = integration; - this.deps = deps; + this.deps = { + ...deps, + createContainerClient: + deps.createContainerClient ?? + this.#defaultCreateContainerClient.bind(this, credsManager), + }; } - private async createContainerClient( + async #defaultCreateContainerClient( + credsManager: AzureCredentialsManager, containerName: string, ): Promise { - const accountName = this.integration.config.accountName; // Use the account name from the integration config - const accountKey = this.integration.config.accountKey; // Get the account key if it exists + const accountName = this.integration.config.accountName; + const accountKey = this.integration.config.accountKey; if (accountKey && accountName) { const creds = new StorageSharedKeyCredential(accountName, accountKey); @@ -119,10 +125,8 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { ); return blobServiceClient.getContainerClient(containerName); } - // Use the credentials manager to get the correct credentials - const credential = await this.credsManager.getCredentials( - accountName as string, - ); + + const credential = await credsManager.getCredentials(accountName as string); let blobServiceClientUrl: string; @@ -157,7 +161,7 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { try { const { path, container } = parseUrl(url); - const containerClient = await this.createContainerClient(container); + const containerClient = await this.deps.createContainerClient(container); const blobClient = containerClient.getBlobClient(path); const getBlobOptions: BlobDownloadOptions = { @@ -200,7 +204,7 @@ export class AzureBlobStorageUrlReader implements UrlReaderService { try { const { path, container } = parseUrl(url); - const containerClient = await this.createContainerClient(container); + const containerClient = await this.deps.createContainerClient(container); const blobs = containerClient.listBlobsFlat({ prefix: path }); const responses = []; diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts index 8a1513a0f7..aad52318b4 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.test.ts @@ -120,14 +120,14 @@ describe('AzureUrlReader', () => { it.each([ { url: 'https://dev.azure.com/org-name/project-name/_git/repo-name?path=my-template.yaml&version=GBmaster', - config: createConfig(), + config: createConfig('my-pat'), response: expect.objectContaining({ url: 'https://dev.azure.com/org-name/project-name/_apis/git/repositories/repo-name/items?api-version=6.0&path=my-template.yaml&version=master', }), }, { url: 'https://dev.azure.com/org-name/project-name/_git/repo-name?path=my-template.yaml', - config: createConfig(), + config: createConfig('my-pat'), response: expect.objectContaining({ url: 'https://dev.azure.com/org-name/project-name/_apis/git/repositories/repo-name/items?api-version=6.0&path=my-template.yaml', }), @@ -141,15 +141,6 @@ describe('AzureUrlReader', () => { }), }), }, - { - url: 'https://dev.azure.com/a/b/_git/repo-name?path=my-template.yaml', - config: createConfig(undefined), - response: expect.objectContaining({ - headers: expect.objectContaining({ - authorization: expect.stringMatching(/^Bearer /), - }), - }), - }, ])('should handle happy path %#', async ({ url, config, response }) => { const [{ reader }] = AzureUrlReader.factory({ config, @@ -166,12 +157,12 @@ describe('AzureUrlReader', () => { it.each([ { url: 'https://api.com/a/b/blob/master/path/to/c.yaml', - config: createConfig(), + config: createConfig('my-pat'), error: 'Azure URL must point to a git repository', }, { url: 'com/a/b/blob/master/path/to/c.yaml', - config: createConfig(), + config: createConfig('my-pat'), error: 'Invalid URL', }, { diff --git a/packages/integration/src/azure/DefaultAzureDevOpsCredentialsProvider.test.ts b/packages/integration/src/azure/DefaultAzureDevOpsCredentialsProvider.test.ts index 4b86e9869e..97e5d4bbb0 100644 --- a/packages/integration/src/azure/DefaultAzureDevOpsCredentialsProvider.test.ts +++ b/packages/integration/src/azure/DefaultAzureDevOpsCredentialsProvider.test.ts @@ -147,7 +147,7 @@ describe('DefaultAzureDevOpsCredentialProvider', () => { expect(fromTokenCredential).toHaveBeenCalledTimes(1); expect(fromTokenCredential).toHaveBeenCalledWith( - new DefaultAzureCredential(), + expect.any(MockedDefaultAzureCredential), ); }); @@ -170,7 +170,7 @@ describe('DefaultAzureDevOpsCredentialProvider', () => { expect(fromTokenCredential).toHaveBeenCalledTimes(2); expect(fromTokenCredential).toHaveBeenCalledWith( - new DefaultAzureCredential(), + expect.any(MockedDefaultAzureCredential), ); }); diff --git a/yarn.lock b/yarn.lock index b6310bdf48..2e9c275b1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1187,12 +1187,17 @@ __metadata: languageName: node linkType: hard -"@azure/abort-controller@npm:^1.0.0": - version: 1.0.2 - resolution: "@azure/abort-controller@npm:1.0.2" +"@azure-rest/core-client@npm:^2.3.3": + version: 2.6.0 + resolution: "@azure-rest/core-client@npm:2.6.0" dependencies: - tslib: "npm:^2.0.0" - checksum: 10/9ca0e2f920d715b495202438fc208eca65ebad488e609475537b8d89af2dc4d262aaced363dfa43d6e82f19cb38bef9bab7363cd995ab58ad63e7f60cef8c77e + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-auth": "npm:^1.10.0" + "@azure/core-rest-pipeline": "npm:^1.22.0" + "@azure/core-tracing": "npm:^1.3.0" + "@typespec/ts-http-runtime": "npm:^0.3.0" + tslib: "npm:^2.6.2" + checksum: 10/8fe4985b7b0714b74c184260ca557ae5ff3cbd0aa3e44dbba844df25476205020bd1dc6241f7de0e356da00312d5e151957cc944cee4da8f104bd848533eb9e8 languageName: node linkType: hard @@ -1205,76 +1210,79 @@ __metadata: languageName: node linkType: hard -"@azure/communication-common@npm:^2.2.0": - version: 2.3.1 - resolution: "@azure/communication-common@npm:2.3.1" +"@azure/communication-common@npm:^2.3.1": + version: 2.4.0 + resolution: "@azure/communication-common@npm:2.4.0" dependencies: - "@azure/abort-controller": "npm:^1.0.0" - "@azure/core-auth": "npm:^1.3.0" - "@azure/core-rest-pipeline": "npm:^1.3.2" - "@azure/core-tracing": "npm:^1.0.0" - "@azure/core-util": "npm:^1.0.0" - events: "npm:^3.0.0" + "@azure-rest/core-client": "npm:^2.3.3" + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-auth": "npm:^1.9.0" + "@azure/core-rest-pipeline": "npm:^1.17.0" + "@azure/core-tracing": "npm:^1.2.0" + "@azure/core-util": "npm:^1.11.0" + events: "npm:^3.3.0" jwt-decode: "npm:^4.0.0" - tslib: "npm:^2.2.0" - checksum: 10/6a3edd03609a7abae652f20cc7e1293431765116f56cb79b5efed2a8c050b97f582decf71d2344ec760b20e48a8e74a092d938b750cf91cc91d23487018d63ad + tslib: "npm:^2.8.1" + checksum: 10/e8212d1676d567acb560b552bb9785de453485d595b9c4acae99e89d406c62654c844e7e9b3502100e365623d4db58dc323183691372f060ddf643b8e94ff119 languageName: node linkType: hard "@azure/communication-email@npm:^1.0.0": - version: 1.0.0 - resolution: "@azure/communication-email@npm:1.0.0" + version: 1.1.0 + resolution: "@azure/communication-email@npm:1.1.0" dependencies: - "@azure/communication-common": "npm:^2.2.0" - "@azure/core-auth": "npm:^1.3.0" - "@azure/core-client": "npm:^1.3.2" - "@azure/core-lro": "npm:^2.5.0" - "@azure/core-rest-pipeline": "npm:^1.8.0" - "@azure/logger": "npm:^1.0.0" - tslib: "npm:^1.9.3" - uuid: "npm:^8.3.2" - checksum: 10/16d292dd9c93aefcb7babd01ae1974982ac39932b0e64e7a999cd5bc696bfe848ca78b909d9744d9b3eb2a50c156c6bc226f6cabe47ea70ff2c55b49e3a32d3d - languageName: node - linkType: hard - -"@azure/core-auth@npm:^1.3.0, @azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0, @azure/core-auth@npm:^1.8.0": - version: 1.9.0 - resolution: "@azure/core-auth@npm:1.9.0" - dependencies: - "@azure/abort-controller": "npm:^2.0.0" + "@azure/abort-controller": "npm:^2.1.2" + "@azure/communication-common": "npm:^2.3.1" + "@azure/core-auth": "npm:^1.9.0" + "@azure/core-client": "npm:^1.9.2" + "@azure/core-lro": "npm:^2.7.2" + "@azure/core-rest-pipeline": "npm:^1.18.0" "@azure/core-util": "npm:^1.11.0" - tslib: "npm:^2.6.2" - checksum: 10/d1ae2847fddfad752b5f4092a3cbe7ad5809bc5c510447809b5e678abc3fc280af629c5155d2100f37ca8f43f88d7d3ea78279f98bd9f7eb44ec492f6cdbbe35 + "@azure/logger": "npm:^1.1.4" + tslib: "npm:^2.8.1" + checksum: 10/00503a11cd4478e20b56ec2708f439b9e13c766750fd550789eb2d6107d9f913f3036cc585865ee30ca369802eeebdd1199fbdeef2e91fe38fbec46bc9866f7f languageName: node linkType: hard -"@azure/core-client@npm:^1.3.0, @azure/core-client@npm:^1.3.2, @azure/core-client@npm:^1.6.2, @azure/core-client@npm:^1.9.2": - version: 1.9.2 - resolution: "@azure/core-client@npm:1.9.2" +"@azure/core-auth@npm:^1.10.0, @azure/core-auth@npm:^1.9.0": + version: 1.10.1 + resolution: "@azure/core-auth@npm:1.10.1" dependencies: - "@azure/abort-controller": "npm:^2.0.0" - "@azure/core-auth": "npm:^1.4.0" - "@azure/core-rest-pipeline": "npm:^1.9.1" - "@azure/core-tracing": "npm:^1.0.0" - "@azure/core-util": "npm:^1.6.1" - "@azure/logger": "npm:^1.0.0" + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-util": "npm:^1.13.0" tslib: "npm:^2.6.2" - checksum: 10/0358b8245bf23943914eb77384955c994bf3ef84f862234cb3e261f9c602a9f4717beedafd48d1da902b15f3464a4211540976fabb4569039fac8e0d41e59ef1 + checksum: 10/230c1766d4cb3ac7beac45db65bd5e493e1530f6f1d51dc0fd3537f8144e5c9acfed94700fd28c7aee67bab7502e23a1588adc6aa76f918f08fe40b3b007e2a3 languageName: node linkType: hard -"@azure/core-http-compat@npm:^2.0.0": - version: 2.1.2 - resolution: "@azure/core-http-compat@npm:2.1.2" +"@azure/core-client@npm:^1.9.2, @azure/core-client@npm:^1.9.3": + version: 1.10.1 + resolution: "@azure/core-client@npm:1.10.1" dependencies: - "@azure/abort-controller": "npm:^2.0.0" - "@azure/core-client": "npm:^1.3.0" - "@azure/core-rest-pipeline": "npm:^1.3.0" - checksum: 10/2b64b2480db6ebb8b0f6e7e104f632d9266bbe08f44ea0117d84439a4ba8846ee533841e827c2766f63ef26709c89e61c0d250878660930bac521c7f45fab49c + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-auth": "npm:^1.10.0" + "@azure/core-rest-pipeline": "npm:^1.22.0" + "@azure/core-tracing": "npm:^1.3.0" + "@azure/core-util": "npm:^1.13.0" + "@azure/logger": "npm:^1.3.0" + tslib: "npm:^2.6.2" + checksum: 10/4a00ec0d11f92274bb79efdea2515a7947b8cfb34cff6570a0813ea2889ab57ddc1f22f232192dee8f918e04ba96de07b7584bf9cbcac03e17cb39e9e399c2e9 languageName: node linkType: hard -"@azure/core-lro@npm:^2.2.0, @azure/core-lro@npm:^2.5.0": +"@azure/core-http-compat@npm:^2.2.0": + version: 2.4.0 + resolution: "@azure/core-http-compat@npm:2.4.0" + dependencies: + "@azure/abort-controller": "npm:^2.1.2" + peerDependencies: + "@azure/core-client": ^1.10.0 + "@azure/core-rest-pipeline": ^1.22.0 + checksum: 10/65adde0d604d6aeebdde7623cc6d27938d7502a82c520ad8bc77539a4c8a26050af0f3242c9dd27f192b042970c3f8d53a98a7f755039d6d8c9813409305a9f4 + languageName: node + linkType: hard + +"@azure/core-lro@npm:^2.2.0, @azure/core-lro@npm:^2.7.2": version: 2.7.2 resolution: "@azure/core-lro@npm:2.7.2" dependencies: @@ -1286,143 +1294,151 @@ __metadata: languageName: node linkType: hard -"@azure/core-paging@npm:^1.1.1": - version: 1.3.0 - resolution: "@azure/core-paging@npm:1.3.0" +"@azure/core-paging@npm:^1.6.2": + version: 1.6.2 + resolution: "@azure/core-paging@npm:1.6.2" dependencies: - tslib: "npm:^2.2.0" - checksum: 10/cfff12d61a1deeba980a2f122075c68d2f6fba794e69d7df2af691b056f76fdfd8bb7c4bf781258ebcb360b567afef39c5424a9ebdbdcd8a90f7b1af384a3ef9 + tslib: "npm:^2.6.2" + checksum: 10/fb1d4c4fcd5705dbcd2332724d0ead324b988a874bfe739483cf65056b8ad5567aaa5ae02f4d0467c71c3be035bbd15682fe0d8f6e47043a66903d439593f5b8 languageName: node linkType: hard -"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.10.1, @azure/core-rest-pipeline@npm:^1.3.0, @azure/core-rest-pipeline@npm:^1.3.2, @azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1": - version: 1.19.0 - resolution: "@azure/core-rest-pipeline@npm:1.19.0" +"@azure/core-rest-pipeline@npm:^1.17.0, @azure/core-rest-pipeline@npm:^1.18.0, @azure/core-rest-pipeline@npm:^1.19.1, @azure/core-rest-pipeline@npm:^1.22.0": + version: 1.23.0 + resolution: "@azure/core-rest-pipeline@npm:1.23.0" dependencies: - "@azure/abort-controller": "npm:^2.0.0" - "@azure/core-auth": "npm:^1.8.0" - "@azure/core-tracing": "npm:^1.0.1" - "@azure/core-util": "npm:^1.11.0" - "@azure/logger": "npm:^1.0.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.0" + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-auth": "npm:^1.10.0" + "@azure/core-tracing": "npm:^1.3.0" + "@azure/core-util": "npm:^1.13.0" + "@azure/logger": "npm:^1.3.0" + "@typespec/ts-http-runtime": "npm:^0.3.4" tslib: "npm:^2.6.2" - checksum: 10/d9d747c0c7d7f80cbaa5c7b31b2bb5aa8796dcaf45736153360cf4963ad10bc04d93b737dac3ca91f3cbedbf63a29e166d1403e32e456c541c133333de289bb3 + checksum: 10/9c60c8bb858cec1caf49d3c323667814512fbf0ca3b34fa382c010f4a6fcccf0a6ef8210c2f7d791b2af67b5c427aefb9b1e4c58a9a9ef60d1cff871fca548f3 languageName: node linkType: hard -"@azure/core-tracing@npm:^1.0.0, @azure/core-tracing@npm:^1.0.1, @azure/core-tracing@npm:^1.1.2": - version: 1.1.2 - resolution: "@azure/core-tracing@npm:1.1.2" +"@azure/core-tracing@npm:^1.0.0, @azure/core-tracing@npm:^1.2.0, @azure/core-tracing@npm:^1.3.0": + version: 1.3.1 + resolution: "@azure/core-tracing@npm:1.3.1" dependencies: tslib: "npm:^2.6.2" - checksum: 10/027ab8f6ed0ed859a3999dd192faf7286b6e1da8887852a61150c1cf9fc29dbde95bcaa510ee5138e416e9c026cd177b69b7e2c83a8ec0a9758caba412f5368d + checksum: 10/7ef179e0ceb58c76d99c22bb5c5faade6fceaa62a265dcdaf09456e979be716e0249bb952d8000b9502b2194aeccb01454d60b497d4a18755e933cf7b1df919d languageName: node linkType: hard -"@azure/core-util@npm:^1.0.0, @azure/core-util@npm:^1.11.0, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.3.0, @azure/core-util@npm:^1.6.1": - version: 1.11.0 - resolution: "@azure/core-util@npm:1.11.0" +"@azure/core-util@npm:^1.11.0, @azure/core-util@npm:^1.13.0, @azure/core-util@npm:^1.2.0": + version: 1.13.1 + resolution: "@azure/core-util@npm:1.13.1" dependencies: - "@azure/abort-controller": "npm:^2.0.0" + "@azure/abort-controller": "npm:^2.1.2" + "@typespec/ts-http-runtime": "npm:^0.3.0" tslib: "npm:^2.6.2" - checksum: 10/16d39f4ed9e224c190f0ffcb040b4f0a9723946b4312784a7a2a227cf2c56cd68328ce28fa05d1109c2e88bb5b34af159264c854e876f182461976a65fa1b5e5 + checksum: 10/81ba529bed2fb615836be9425608e012f9bd243881f861c7ac086ea618c5f91129d3088216eee588323ffc3dfc0013706069830c03810f8a0f4591553ef5843b languageName: node linkType: hard -"@azure/core-xml@npm:^1.4.3": - version: 1.4.4 - resolution: "@azure/core-xml@npm:1.4.4" +"@azure/core-xml@npm:^1.4.5": + version: 1.5.1 + resolution: "@azure/core-xml@npm:1.5.1" dependencies: - fast-xml-parser: "npm:^4.4.1" - tslib: "npm:^2.6.2" - checksum: 10/83370ce35008874caca25a335b29f19a243eec96f8c8a087d5f19f1652a494e2a5d0964cb892a0063bb456004b2ab80aaf785c0dcf83eea7e872a99076144e78 + fast-xml-parser: "npm:^5.5.9" + tslib: "npm:^2.8.1" + checksum: 10/4c3fdc80449b46b0c5d8f99d43e4c61a6bddd6f13386e316cdb6df99aa45f2040b441d2b2dc9fceab4748443843c2cab1f8cdce1b304b54f1170a4dac46f85b8 languageName: node linkType: hard "@azure/identity@npm:^4.0.0": - version: 4.3.0 - resolution: "@azure/identity@npm:4.3.0" + version: 4.13.1 + resolution: "@azure/identity@npm:4.13.1" dependencies: - "@azure/abort-controller": "npm:^1.0.0" - "@azure/core-auth": "npm:^1.5.0" + "@azure/abort-controller": "npm:^2.0.0" + "@azure/core-auth": "npm:^1.9.0" "@azure/core-client": "npm:^1.9.2" - "@azure/core-rest-pipeline": "npm:^1.1.0" + "@azure/core-rest-pipeline": "npm:^1.17.0" "@azure/core-tracing": "npm:^1.0.0" - "@azure/core-util": "npm:^1.3.0" + "@azure/core-util": "npm:^1.11.0" "@azure/logger": "npm:^1.0.0" - "@azure/msal-browser": "npm:^3.11.1" - "@azure/msal-node": "npm:^2.9.2" - events: "npm:^3.0.0" - jws: "npm:^4.0.0" - open: "npm:^8.0.0" - stoppable: "npm:^1.1.0" + "@azure/msal-browser": "npm:^5.5.0" + "@azure/msal-node": "npm:^5.1.0" + open: "npm:^10.1.0" tslib: "npm:^2.2.0" - checksum: 10/2cf629982ee56f50b6f979cecb1b1be348c9ea38a584cf7218e1231884fdf0db4993cc665ff4c6065bd77c30b2ae1ad00a484c456561755d8de85f138361ac62 + checksum: 10/f07734f811d734d29b49ad7f8345a53d680b90d075dcd9bfbc28e2e18bda3f1688de4faf44cc4727302c9aa91c13d4444ac2de6edb88a79c99c9efc660137609 languageName: node linkType: hard -"@azure/logger@npm:^1.0.0": - version: 1.0.1 - resolution: "@azure/logger@npm:1.0.1" +"@azure/logger@npm:^1.0.0, @azure/logger@npm:^1.1.4, @azure/logger@npm:^1.3.0": + version: 1.3.0 + resolution: "@azure/logger@npm:1.3.0" dependencies: - tslib: "npm:^2.0.0" - checksum: 10/3b3e81a3dd1eb5b608aa6e63ae1b8c11cafb6a56c2496b6f78f5e9c3b6c29a1a7fc8f9cf5e8f278c7bd9b9590a4864a6328d73126cd0d32f9e505330b280f3f2 + "@typespec/ts-http-runtime": "npm:^0.3.0" + tslib: "npm:^2.6.2" + checksum: 10/7df11bf3b4952207d7355fde3cee223df2e4a64eaafff05a1fcbcb5c870350f1ef726866b771a7520b0e2bb33bfa9c96415b823c4b74e04ad4b755e961634528 languageName: node linkType: hard -"@azure/msal-browser@npm:^3.11.1": - version: 3.11.1 - resolution: "@azure/msal-browser@npm:3.11.1" +"@azure/msal-browser@npm:^5.5.0": + version: 5.11.0 + resolution: "@azure/msal-browser@npm:5.11.0" dependencies: - "@azure/msal-common": "npm:14.8.1" - checksum: 10/84534d43f776ea3608bd3b533e128b32e2907876211822d8dfb9bf5bc3e1fffcee62a9a970138c45306fa4b05432b1fcd5abbe122e7d63c7875e0a2a177f4584 + "@azure/msal-common": "npm:16.6.2" + checksum: 10/48049d2e2cdcfdfc9bd03ddb95737f84e2005084d84e55f4adca6d8681a81745a5ecd48c01b20b8623091744664403dcc6ce726212e193f4bf63bda49b19d3e2 languageName: node linkType: hard -"@azure/msal-common@npm:14.12.0": - version: 14.12.0 - resolution: "@azure/msal-common@npm:14.12.0" - checksum: 10/5a0905beae17e20d66b352425dfd86d41ddf402f3c2c324aacf0590844e61c2c13ed439c3c63a1d7b4d3861b8d885ed11b7f257373facefe8fa3dc63455ee9c2 +"@azure/msal-common@npm:16.6.2": + version: 16.6.2 + resolution: "@azure/msal-common@npm:16.6.2" + checksum: 10/df446034a983f44264679489521349d961943518671fb411f7af06f67de3797a756cc35975514828d70a05766771cc619ae990531830631e077dfc1e1d16b1e2 languageName: node linkType: hard -"@azure/msal-common@npm:14.8.1": - version: 14.8.1 - resolution: "@azure/msal-common@npm:14.8.1" - checksum: 10/8b83832cae049004444305e3eb42d7fc597eaea96271dbbb777a2a53f00090b98870affb41cd2599a45cd4d66a633722a46144bf4a87f8af95b503c61ed45f9c - languageName: node - linkType: hard - -"@azure/msal-node@npm:^2.9.2": - version: 2.9.2 - resolution: "@azure/msal-node@npm:2.9.2" +"@azure/msal-node@npm:^5.1.0": + version: 5.2.2 + resolution: "@azure/msal-node@npm:5.2.2" dependencies: - "@azure/msal-common": "npm:14.12.0" + "@azure/msal-common": "npm:16.6.2" jsonwebtoken: "npm:^9.0.0" - uuid: "npm:^8.3.0" - checksum: 10/0cbaa209291a300515ab94883b9920ba7fa66b11e34428214e46384c3ab12c6e159904ed0a3190e2babf6509780f855f8c4345c07af9bafca0a94d68ff838ba5 + checksum: 10/29cf3d594207a59d01f4f04ca48203391eca3bf7c389a6a51d4a531b30b83cb990c223deee26c99ceaee8f48f3846d3b006b33c4eefc765f37646e442a79572f languageName: node linkType: hard "@azure/storage-blob@npm:^12.5.0": - version: 12.26.0 - resolution: "@azure/storage-blob@npm:12.26.0" + version: 12.31.0 + resolution: "@azure/storage-blob@npm:12.31.0" dependencies: "@azure/abort-controller": "npm:^2.1.2" - "@azure/core-auth": "npm:^1.4.0" - "@azure/core-client": "npm:^1.6.2" - "@azure/core-http-compat": "npm:^2.0.0" + "@azure/core-auth": "npm:^1.9.0" + "@azure/core-client": "npm:^1.9.3" + "@azure/core-http-compat": "npm:^2.2.0" "@azure/core-lro": "npm:^2.2.0" - "@azure/core-paging": "npm:^1.1.1" - "@azure/core-rest-pipeline": "npm:^1.10.1" - "@azure/core-tracing": "npm:^1.1.2" - "@azure/core-util": "npm:^1.6.1" - "@azure/core-xml": "npm:^1.4.3" - "@azure/logger": "npm:^1.0.0" + "@azure/core-paging": "npm:^1.6.2" + "@azure/core-rest-pipeline": "npm:^1.19.1" + "@azure/core-tracing": "npm:^1.2.0" + "@azure/core-util": "npm:^1.11.0" + "@azure/core-xml": "npm:^1.4.5" + "@azure/logger": "npm:^1.1.4" + "@azure/storage-common": "npm:^12.3.0" events: "npm:^3.0.0" - tslib: "npm:^2.2.0" - checksum: 10/dfe2f708db3f205a2a1aaab3d3282b0e070f635a5da4b1f7d32056da6104bc7d1be2cc61931ff1c9b468e9804ab9f098fc89ac8c2ddf29219355f847e801d26e + tslib: "npm:^2.8.1" + checksum: 10/19d5f48b62b54e8789bc87b90ec95efea74830c2088b4582de34abced873c5a7441d5c73bee4f12345f46600d1b1bba7ff1baf7566aa8afe385eb16d9a1308e6 + languageName: node + linkType: hard + +"@azure/storage-common@npm:^12.3.0": + version: 12.3.0 + resolution: "@azure/storage-common@npm:12.3.0" + dependencies: + "@azure/abort-controller": "npm:^2.1.2" + "@azure/core-auth": "npm:^1.9.0" + "@azure/core-http-compat": "npm:^2.2.0" + "@azure/core-rest-pipeline": "npm:^1.19.1" + "@azure/core-tracing": "npm:^1.2.0" + "@azure/core-util": "npm:^1.11.0" + "@azure/logger": "npm:^1.1.4" + events: "npm:^3.3.0" + tslib: "npm:^2.8.1" + checksum: 10/e5bb4c9395a9f5d390e0766f2b9c64b7d223c1b12704e4557025396f65c680150d36e9ebb9d85a3801337d8e09b6f2dca571233ddc5e71e8887d917b4ce17bb5 languageName: node linkType: hard @@ -20340,6 +20356,17 @@ __metadata: languageName: node linkType: hard +"@typespec/ts-http-runtime@npm:^0.3.0, @typespec/ts-http-runtime@npm:^0.3.4": + version: 0.3.5 + resolution: "@typespec/ts-http-runtime@npm:0.3.5" + dependencies: + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.0" + tslib: "npm:^2.6.2" + checksum: 10/7cf459826e4867ab52a4b9855fdce4590e30a6f37e11fb93155e01c6e80139ec9966b7a3270cffed2c1e88ae66acbae5b4c9a7ecd9274679734da2c18310cc6c + languageName: node + linkType: hard + "@uiw/codemirror-extensions-basic-setup@npm:4.25.9": version: 4.25.9 resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.25.9" @@ -28834,7 +28861,7 @@ __metadata: languageName: node linkType: hard -"fast-xml-builder@npm:^1.1.7": +"fast-xml-builder@npm:^1.1.7, fast-xml-builder@npm:^1.2.0": version: 1.2.0 resolution: "fast-xml-builder@npm:1.2.0" dependencies: @@ -28844,7 +28871,7 @@ __metadata: languageName: node linkType: hard -"fast-xml-parser@npm:5.7.3, fast-xml-parser@npm:^5.3.4": +"fast-xml-parser@npm:5.7.3": version: 5.7.3 resolution: "fast-xml-parser@npm:5.7.3" dependencies: @@ -28858,14 +28885,18 @@ __metadata: languageName: node linkType: hard -"fast-xml-parser@npm:^4.4.1": - version: 4.5.6 - resolution: "fast-xml-parser@npm:4.5.6" +"fast-xml-parser@npm:^5.3.4, fast-xml-parser@npm:^5.5.9": + version: 5.8.0 + resolution: "fast-xml-parser@npm:5.8.0" dependencies: - strnum: "npm:^1.0.5" + "@nodable/entities": "npm:^2.1.0" + fast-xml-builder: "npm:^1.2.0" + path-expression-matcher: "npm:^1.5.0" + strnum: "npm:^2.3.0" + xml-naming: "npm:^0.1.0" bin: fxparser: src/cli/cli.js - checksum: 10/dd77cce4b1b322400339147b72b2d315bddc12c6ed3ca82bfc87543ced6dd8d81a6e0b429489e2f048f39258aa2023580654c8934881c633b9d58a6e79672349 + checksum: 10/0167d17d5275c95e005639f8fca7b4d88fec3fd013063725280f4e982313b1c798e4565d5ced7f61ce10e8f0d876a1976492cc8ac27da3080915ff549fd00705 languageName: node linkType: hard @@ -38110,7 +38141,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^10.0.3, open@npm:^10.2.0": +"open@npm:^10.0.3, open@npm:^10.1.0, open@npm:^10.2.0": version: 10.2.0 resolution: "open@npm:10.2.0" dependencies: @@ -38122,7 +38153,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^8.0.0, open@npm:^8.4.0": +"open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" dependencies: @@ -44360,13 +44391,6 @@ __metadata: languageName: node linkType: hard -"stoppable@npm:^1.1.0": - version: 1.1.0 - resolution: "stoppable@npm:1.1.0" - checksum: 10/63104fcbdece130bc4906fd982061e763d2ef48065ed1ab29895e5ad00552c625f8a4c50c9cd2e3bfa805c8a2c3bfdda0f07c5ae39694bd2d5cb0bee1618d1e9 - languageName: node - linkType: hard - "storybook@npm:^10.4.0": version: 10.4.1 resolution: "storybook@npm:10.4.1" @@ -44837,14 +44861,7 @@ __metadata: languageName: node linkType: hard -"strnum@npm:^1.0.5": - version: 1.0.5 - resolution: "strnum@npm:1.0.5" - checksum: 10/d3117975db8372d4d7b2c07601ed2f65bf21cc48d741f37a8617b76370d228f2ec26336e53791ebc3638264d23ca54e6c241f57f8c69bd4941c63c79440525ca - languageName: node - linkType: hard - -"strnum@npm:^2.2.3": +"strnum@npm:^2.2.3, strnum@npm:^2.3.0": version: 2.3.0 resolution: "strnum@npm:2.3.0" checksum: 10/ce79c86bb2b96f053eb28e14924c13604e22977dcdece9aa914c25e16cc5c4bbe048976fe0b2a4decf08a1e13600b820749cea25463fc0e5fee3078339e0a457