diff --git a/packages/nodes-base/credentials/AzureCosmosDbSharedKeyApi.credentials.ts b/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts similarity index 79% rename from packages/nodes-base/credentials/AzureCosmosDbSharedKeyApi.credentials.ts rename to packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts index e601ad235e..686ff14f98 100644 --- a/packages/nodes-base/credentials/AzureCosmosDbSharedKeyApi.credentials.ts +++ b/packages/nodes-base/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.ts @@ -6,14 +6,17 @@ import { type INodeProperties, } from 'n8n-workflow'; -import { getAuthorizationTokenUsingMasterKey } from '../nodes/Microsoft/AzureCosmosDB/GenericFunctions'; +import { + getAuthorizationTokenUsingMasterKey, + HeaderConstants, +} from '../nodes/Microsoft/CosmosDB/GenericFunctions'; -export class AzureCosmosDbSharedKeyApi implements ICredentialType { - name = 'azureCosmosDbSharedKeyApi'; +export class MicrosoftCosmosDbSharedKeyApi implements ICredentialType { + name = 'microsoftCosmosDbSharedKeyApi'; displayName = 'Azure Cosmos DB API'; - documentationUrl = 'azureCosmosDb'; + documentationUrl = 'microsoftCosmosDb'; properties: INodeProperties[] = [ { @@ -75,8 +78,9 @@ export class AzureCosmosDbSharedKeyApi implements ICredentialType { } let resourceType = ''; - const resourceLink = requestOptions.url; + const resourceLink = '/dbs/first_database_1' + requestOptions.url; + console.log('Link', resourceLink); if (resourceLink.includes('/colls')) { resourceType = 'colls'; } else if (resourceLink.includes('/docs')) { @@ -86,6 +90,7 @@ export class AzureCosmosDbSharedKeyApi implements ICredentialType { } else { throw new ApplicationError('Unable to determine resourceType'); } + console.log('Type', resourceType); if (requestOptions.method) { const authToken = getAuthorizationTokenUsingMasterKey( @@ -96,10 +101,10 @@ export class AzureCosmosDbSharedKeyApi implements ICredentialType { credentials.key as string, ); - requestOptions.headers.Authorization = authToken; + requestOptions.headers[HeaderConstants.AUTHORIZATION] = authToken; } - console.log('Final requestOptions headers:', requestOptions.headers); + console.log('Final requestOptions:', requestOptions); return requestOptions; } diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/CosmosDB.svg b/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDB.svg similarity index 100% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/CosmosDB.svg rename to packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDB.svg diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/AzureCosmosDb.node.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts similarity index 94% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/AzureCosmosDb.node.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts index 72e6a0bd4c..566ea4b05d 100644 --- a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/AzureCosmosDb.node.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/CosmosDb.node.ts @@ -7,8 +7,8 @@ import { searchCollections } from './GenericFunctions'; export class AzureCosmosDb implements INodeType { description: INodeTypeDescription = { - displayName: 'Azure Cosmos DB', - name: 'azureCosmosDb', + displayName: 'Cosmos DB', + name: 'cosmosDb', icon: { light: 'file:CosmosDB.svg', dark: 'file:CosmosDB.svg', @@ -24,7 +24,7 @@ export class AzureCosmosDb implements INodeType { outputs: [NodeConnectionType.Main], credentials: [ { - name: 'azureCosmosDbSharedKeyApi', + name: 'microsoftCosmosDbSharedKeyApi', required: true, displayOptions: { show: { diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/GenericFunctions.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts similarity index 67% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/GenericFunctions.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts index 368f4947c3..1613e82729 100644 --- a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/GenericFunctions.ts @@ -11,34 +11,34 @@ import type { } from 'n8n-workflow'; import { ApplicationError } from 'n8n-workflow'; -// export const HeaderConstants = { -// // Required -// AUTHORIZATION: 'Authorization', -// CONTENT_TYPE: 'Content-Type', -// X_MS_DATE: 'x-ms-date', -// X_MS_VERSION: 'x-ms-version', +export const HeaderConstants = { + // Required + AUTHORIZATION: 'Authorization', + CONTENT_TYPE: 'Content-Type', + X_MS_DATE: 'x-ms-date', + X_MS_VERSION: 'x-ms-version', -// //Required - for session consistency only -// X_MS_SESSION_TOKEN: 'x-ms-session-token', + //Required - for session consistency only + X_MS_SESSION_TOKEN: 'x-ms-session-token', -// // Optional -// IF_MATCH: 'If-Match', -// IF_NONE_MATCH: 'If-None-Match', -// IF_MODIFIED_SINCE: 'If-Modified-Since', -// USER_AGENT: 'User-Agent', -// X_MS_ACTIVITY_ID: 'x-ms-activity-id', -// X_MS_CONSISTENCY_LEVEL: 'x-ms-consistency-level', -// X_MS_CONTINUATION: 'x-ms-continuation', -// X_MS_MAX_ITEM_COUNT: 'x-ms-max-item-count', -// X_MS_DOCUMENTDB_PARTITIONKEY: 'x-ms-documentdb-partitionkey', -// X_MS_DOCUMENTDB_ISQUERY: 'x-ms-documentdb-isquery', -// X_MS_DOCUMENTDB_QUERY_ENABLECROSSPARTITION: 'x-ms-documentdb-query-enablecrosspartition', -// A_IM: 'A-IM', -// X_MS_DOCUMENTDB_PARTITIONKEYRANGEID: 'x-ms-documentdb-partitionkeyrangeid', -// X_MS_COSMOS_ALLOW_TENTATIVE_WRITES: 'x-ms-cosmos-allow-tentative-writes', + // Optional + IF_MATCH: 'If-Match', + IF_NONE_MATCH: 'If-None-Match', + IF_MODIFIED_SINCE: 'If-Modified-Since', + USER_AGENT: 'User-Agent', + X_MS_ACTIVITY_ID: 'x-ms-activity-id', + X_MS_CONSISTENCY_LEVEL: 'x-ms-consistency-level', + X_MS_CONTINUATION: 'x-ms-continuation', + X_MS_MAX_ITEM_COUNT: 'x-ms-max-item-count', + X_MS_DOCUMENTDB_PARTITIONKEY: 'x-ms-documentdb-partitionkey', + X_MS_DOCUMENTDB_ISQUERY: 'x-ms-documentdb-isquery', + X_MS_DOCUMENTDB_QUERY_ENABLECROSSPARTITION: 'x-ms-documentdb-query-enablecrosspartition', + A_IM: 'A-IM', + X_MS_DOCUMENTDB_PARTITIONKEYRANGEID: 'x-ms-documentdb-partitionkeyrangeid', + X_MS_COSMOS_ALLOW_TENTATIVE_WRITES: 'x-ms-cosmos-allow-tentative-writes', -// PREFIX_FOR_STORAGE: 'x-ms-', -// }; + PREFIX_FOR_STORAGE: 'x-ms-', +}; export function getAuthorizationTokenUsingMasterKey( verb: string, @@ -52,15 +52,13 @@ export function getAuthorizationTokenUsingMasterKey( `${verb.toLowerCase()}\n` + `${resourceType.toLowerCase()}\n` + `${resourceLink}\n` + - `${date.toLowerCase()}\n` + + `${date}\n` + '\n'; const hmacSha256 = crypto.createHmac('sha256', key); const hashPayload = hmacSha256.update(payload, 'utf8').digest('base64'); - const authorizationString = `type=master&ver=1.0&sig=${hashPayload}`; - - return authorizationString; + return encodeURIComponent('type=master&ver=1.0&sig=' + hashPayload); } export async function handlePagination( @@ -118,11 +116,11 @@ export async function handlePagination( return aggregatedResult.map((result) => ({ json: result })); } -export async function azureCosmosDbRequest( +export async function microsoftCosmosDbRequest( this: ILoadOptionsFunctions, opts: IHttpRequestOptions, ): Promise { - const credentials = await this.getCredentials('azureCosmosDbSharedKeyApi'); + const credentials = await this.getCredentials('microsoftCosmosDbSharedKeyApi'); const databaseAccount = credentials?.account; if (!databaseAccount) { @@ -131,7 +129,7 @@ export async function azureCosmosDbRequest( const requestOptions: IHttpRequestOptions = { ...opts, - baseURL: `https://${databaseAccount}.documents.azure.com`, + baseURL: `${credentials.baseUrl}`, headers: { Accept: 'application/json', 'Content-Type': 'application/json', @@ -156,7 +154,7 @@ export async function azureCosmosDbRequest( return (await this.helpers.requestWithAuthentication.call( this, - 'azureCosmosDbSharedKeyApi', + 'microsoftCosmosDbSharedKeyApi', requestOptions, )) as IDataObject; } catch (error) { @@ -197,7 +195,7 @@ export async function searchCollections( url: '/colls', }; - const responseData: IDataObject = await azureCosmosDbRequest.call(this, opts); + const responseData: IDataObject = await microsoftCosmosDbRequest.call(this, opts); const responseBody = responseData as { DocumentCollections: IDataObject[]; @@ -220,37 +218,3 @@ export async function searchCollections( results, }; } - -// export async function searchDatabases( -// this: ILoadOptionsFunctions, -// filter?: string, -// ): Promise { - -// const opts: IHttpRequestOptions = { -// method: 'GET', -// url: '/dbs', -// }; - -// const responseData: IDataObject = await azureCosmosDbRequest.call(this, opts); -// console.log('Got this response', responseData) -// const responseBody = responseData as { -// Databases: IDataObject[]; -// }; -// const databases = responseBody.Databases; - -// if (!databases) { -// return { results: [] }; -// } - -// const results: INodeListSearchItems[] = databases -// .map((database) => ({ -// name: String(database.id), -// value: String(database.id), -// })) -// .filter((database) => !filter || database.name.includes(filter)) -// .sort((a, b) => a.name.localeCompare(b.name)); - -// return { -// results, -// }; -// } diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/descriptions/ContainerDescription.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/descriptions/ContainerDescription.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ContainerDescription.ts diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/descriptions/ItemDescription.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts similarity index 100% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/descriptions/ItemDescription.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/descriptions/ItemDescription.ts diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/HandlePagination.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts similarity index 100% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/HandlePagination.test.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/test/HandlePagination.test.ts diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/AzureCosmosDbRequest.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts similarity index 80% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/AzureCosmosDbRequest.test.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts index d9a51aa9a3..5042bf4a20 100644 --- a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/AzureCosmosDbRequest.test.ts +++ b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/MicrosoftCosmosDbRequest.test.ts @@ -1,6 +1,6 @@ -import { azureCosmosDbRequest } from '../GenericFunctions'; +import { microsoftCosmosDbRequest } from '../GenericFunctions'; -describe('GenericFunctions - azureCosmosDbRequest', () => { +describe('GenericFunctions - microsoftCosmosDbRequest', () => { let mockContext: any; let mockRequestWithAuthentication: jest.Mock; @@ -17,6 +17,12 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { test('should make a successful request with correct options', async () => { mockRequestWithAuthentication.mockResolvedValueOnce({ success: true }); (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ account: 'us-east-1' }); + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + database: 'first_database_1', + }); + (mockContext.getCredentials as jest.Mock).mockResolvedValueOnce({ + baseUrl: 'https://us-east-1.documents.azure.com/dbs', + }); const requestOptions = { method: 'GET' as const, @@ -26,13 +32,13 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - const result = await azureCosmosDbRequest.call(mockContext, requestOptions); + const result = await microsoftCosmosDbRequest.call(mockContext, requestOptions); expect(mockRequestWithAuthentication).toHaveBeenCalledWith( - 'azureCosmosDbSharedKeyApi', + 'microsoftCosmosDbSharedKeyApi', expect.objectContaining({ method: 'GET', - baseURL: 'https://us-east-1.documents.azure.com', + baseURL: 'https://us-east-1.documents.azure.com/dbs/first_database_1', url: '/example-endpoint', headers: expect.objectContaining({ 'Content-Type': 'application/json', @@ -55,7 +61,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'Database account not found in credentials!', ); @@ -81,7 +87,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'The Cosmos DB credentials are not valid!', ); @@ -107,7 +113,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'The Cosmos DB credentials are not valid!', ); @@ -133,7 +139,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'The requested resource was not found!', ); @@ -155,7 +161,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'Cosmos DB error response [500]: Internal Server Error', ); @@ -176,7 +182,7 @@ describe('GenericFunctions - azureCosmosDbRequest', () => { }, }; - await expect(azureCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( + await expect(microsoftCosmosDbRequest.call(mockContext, requestOptions)).rejects.toThrow( 'Cosmos DB error response [undefined]: Unexpected failure', ); diff --git a/packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/SearchCollections.test.ts b/packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts similarity index 100% rename from packages/nodes-base/nodes/Microsoft/AzureCosmosDB/test/SearchCollections.test.ts rename to packages/nodes-base/nodes/Microsoft/CosmosDB/test/SearchCollections.test.ts diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 6978635c64..9e9e965229 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -39,7 +39,6 @@ "dist/credentials/AutomizyApi.credentials.js", "dist/credentials/AutopilotApi.credentials.js", "dist/credentials/Aws.credentials.js", - "dist/credentials/AzureCosmosDbSharedKeyApi.credentials.js", "dist/credentials/BambooHrApi.credentials.js", "dist/credentials/BannerbearApi.credentials.js", "dist/credentials/BaserowApi.credentials.js", @@ -218,6 +217,7 @@ "dist/credentials/MetabaseApi.credentials.js", "dist/credentials/MessageBirdApi.credentials.js", "dist/credentials/MetabaseApi.credentials.js", + "dist/credentials/MicrosoftCosmosDbSharedKeyApi.credentials.js", "dist/credentials/MicrosoftDynamicsOAuth2Api.credentials.js", "dist/credentials/MicrosoftEntraOAuth2Api.credentials.js", "dist/credentials/MicrosoftExcelOAuth2Api.credentials.js", @@ -626,7 +626,7 @@ "dist/nodes/Merge/Merge.node.js", "dist/nodes/MessageBird/MessageBird.node.js", "dist/nodes/Metabase/Metabase.node.js", - "dist/nodes/Microsoft/AzureCosmosDB/AzureCosmosDb.node.js", + "dist/nodes/Microsoft/CosmosDB/CosmosDb.node.js", "dist/nodes/Microsoft/Dynamics/MicrosoftDynamicsCrm.node.js", "dist/nodes/Microsoft/Entra/MicrosoftEntra.node.js", "dist/nodes/Microsoft/Excel/MicrosoftExcel.node.js",