port: [#6813][#6798] Not able to create instance of BlobsTranscriptStore using TokenCredential instead of connectionString and containerName (#4720)

* add token credential authentication

* added constructor validations

* update botbuilder-azure-blobs.api
This commit is contained in:
Jhonatan Sandoval Velasco 2024-07-31 07:55:20 -05:00 коммит произвёл GitHub
Родитель 364fae8b78
Коммит 543f70ced2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 61 добавлений и 15 удалений

Просмотреть файл

@ -30,12 +30,12 @@ export interface BlobsStorageOptions {
// @public
export class BlobsTranscriptStore implements TranscriptStore {
constructor(connectionString: string, containerName: string, options?: BlobsTranscriptStoreOptions);
constructor(connectionString: string, containerName: string, options?: BlobsTranscriptStoreOptions, blobServiceUri?: string, tokenCredential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential);
deleteTranscript(channelId: string, conversationId: string): Promise<void>;
getTranscriptActivities(channelId: string, conversationId: string, continuationToken?: string, startDate?: Date): Promise<PagedResult<Activity>>;
listTranscripts(channelId: string, continuationToken?: string): Promise<PagedResult<TranscriptInfo>>;
logActivity(activity: Activity, options?: BlobsTranscriptStoreOptions): Promise<void>;
}
}
// @public
export interface BlobsTranscriptStoreOptions {
@ -43,7 +43,6 @@ export interface BlobsTranscriptStoreOptions {
storagePipelineOptions?: StoragePipelineOptions;
}
// (No @packageDocumentation comment for this package)
```

Просмотреть файл

@ -9,10 +9,13 @@ import { maybeCast } from 'botbuilder-stdlib';
import { sanitizeBlobKey } from './sanitizeBlobKey';
import {
AnonymousCredential,
ContainerClient,
ContainerListBlobHierarchySegmentResponse,
StoragePipelineOptions,
StorageSharedKeyCredential,
} from '@azure/storage-blob';
import { isTokenCredential, TokenCredential } from '@azure/core-http';
// Formats a timestamp in a way that is consistent with the C# SDK
function formatTicks(timestamp: Date): string {
@ -45,6 +48,12 @@ function getBlobKey(activity: Activity, options?: BlobsTranscriptStoreOptions):
);
}
function isCredentialType(value: any): value is TokenCredential {
return (
isTokenCredential(value) || value instanceof StorageSharedKeyCredential || value instanceof AnonymousCredential
);
}
// Max number of results returned in a single Azure API call
const MAX_PAGE_SIZE = 20;
@ -85,21 +94,54 @@ export class BlobsTranscriptStore implements TranscriptStore {
* @param {string} connectionString Azure Blob Storage connection string
* @param {string} containerName Azure Blob Storage container name
* @param {BlobsTranscriptStoreOptions} options Other options for BlobsTranscriptStore
* @param {string} blobServiceUri A Uri referencing the blob container that includes the name of the account and the name of the container
* @param {StorageSharedKeyCredential | AnonymousCredential | TokenCredential} tokenCredential The token credential to authenticate to the Azure storage
*/
constructor(connectionString: string, containerName: string, options?: BlobsTranscriptStoreOptions) {
z.object({ connectionString: z.string(), containerName: z.string() }).parse({
connectionString,
containerName,
});
constructor(
connectionString: string,
containerName: string,
options?: BlobsTranscriptStoreOptions,
blobServiceUri = '',
tokenCredential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential
) {
if (blobServiceUri != '' && tokenCredential != null) {
z.object({ blobServiceUri: z.string() }).parse({
blobServiceUri,
});
this._containerClient = new ContainerClient(connectionString, containerName, options?.storagePipelineOptions);
if (typeof tokenCredential != 'object' || !isCredentialType(tokenCredential)) {
throw new ReferenceError('Invalid credential type.');
}
this._containerClient = new ContainerClient(
blobServiceUri,
tokenCredential,
options?.storagePipelineOptions
);
// At most one promise at a time to be friendly to local emulator users
if (blobServiceUri.trim() === 'UseDevelopmentStorage=true;') {
this._concurrency = 1;
}
} else {
z.object({ connectionString: z.string(), containerName: z.string() }).parse({
connectionString,
containerName,
});
this._containerClient = new ContainerClient(
connectionString,
containerName,
options?.storagePipelineOptions
);
// At most one promise at a time to be friendly to local emulator users
if (connectionString.trim() === 'UseDevelopmentStorage=true;') {
this._concurrency = 1;
}
}
this._isDecodeTranscriptKey = options?.decodeTranscriptKey;
// At most one promise at a time to be friendly to local emulator users
if (connectionString.trim() === 'UseDevelopmentStorage=true;') {
this._concurrency = 1;
}
}
// Protects against JSON.stringify cycles

Просмотреть файл

@ -11,7 +11,7 @@ const containerName = process.env.AZURE_BLOB_STORAGE_CONTAINER;
const maybeClient = () =>
connectionString && containerName ? new BlobsTranscriptStore(connectionString, containerName) : null;
describe('BlobsStorage', function () {
describe('BlobsTranscriptStore', function () {
const client = maybeClient();
const maybeIt = client ? it : it.skip;
@ -69,6 +69,11 @@ describe('BlobsStorage', function () {
it('throws for bad args', function () {
assert.throws(() => new BlobsTranscriptStore(), 'throws for missing connectionString');
assert.throws(() => new BlobsTranscriptStore('connectionString'), 'throws for missing containerName');
assert.throws(() => new BlobsTranscriptStore(null, null, null, [], {}), 'throws for missing url');
assert.throws(
() => new BlobsTranscriptStore(null, null, null, 'url', {}),
ReferenceError('Invalid credential type.')
);
});
it('succeeds for good args', function () {