UNPKG

@azure/cosmos

Version:
542 lines (541 loc) • 21.3 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var Database_exports = {}; __export(Database_exports, { Database: () => Database }); module.exports = __toCommonJS(Database_exports); var import_common = require("../../common/index.js"); var import_request = require("../../request/index.js"); var import_Container = require("../Container/index.js"); var import_User = require("../User/index.js"); var import_DatabaseResponse = require("./DatabaseResponse.js"); var import_Offer = require("../Offer/index.js"); var import_diagnostics = require("../../utils/diagnostics.js"); var import_CosmosDiagnostics = require("../../CosmosDiagnostics.js"); var import_encryption = require("../../encryption/index.js"); class Database { /** Returns a new {@link Database} instance. * * Note: the intention is to get this object from {@link CosmosClient} via `client.database(id)`, not to instantiate it yourself. * @hidden */ constructor(client, id, clientContext, encryptionManager, _rid) { this.client = client; this.id = id; this.clientContext = clientContext; this.encryptionManager = encryptionManager; this.containers = new import_Container.Containers(this, this.clientContext, this.encryptionManager); this.users = new import_User.Users(this, this.clientContext); this._rid = _rid; } /** * Used for creating new containers, or querying/reading all containers. * * Use `.database(id)` to read, replace, or delete a specific, existing {@link Database} by id. * * @example Create a new container * ```ts snippet:DatabaseCreateContainer * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * * const { body: containerDefinition, container } = await client * .database("<db id>") * .containers.create({ id: "<container id>" }); * ``` */ containers; /** * Used for creating new users, or querying/reading all users. * * Use `.user(id)` to read, replace, or delete a specific, existing {@link User} by id. */ users; /** * Returns a reference URL to the resource. Used for linking in Permissions. * @example * ```ts snippet:DatabaseGetUrl * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * * const { database } = await client.databases.createIfNotExists({ id: "Test Database" }); * * const url = database.url; * ``` */ get url() { return (0, import_common.createDatabaseUri)(this.id); } /** * @internal */ _rid; /** * Used to read, replace, or delete a specific, existing {@link Database} by id. * * Use `.containers` creating new containers, or querying/reading all containers. * * @example Delete a container * ```ts snippet:DatabaseDeleteContainer * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * * await client.database("<db id>").container("<container id>").delete(); * ``` */ container(id) { return new import_Container.Container(this, id, this.clientContext, this.encryptionManager); } /** * Used to read, replace, or delete a specific, existing {@link User} by id. * * Use `.users` for creating new users, or querying/reading all users. * @example Delete a user * ```ts snippet:DatabaseDeleteUser * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * await client.database("<db id>").user("<user id>").delete(); * ``` */ user(id) { return new import_User.User(this, id, this.clientContext); } /** Read the definition of the given Database. * @example * ```ts snippet:DatabaseRead * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * * const { resource: database } = await client.database("<db id>").read(); * ``` */ async read(options) { return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { return this.readInternal(diagnosticNode, options); }, this.clientContext); } /** * @hidden */ async readInternal(diagnosticNode, options) { const path = (0, import_common.getPathFromLink)(this.url); const id = (0, import_common.getIdFromLink)(this.url); const response = await this.clientContext.read({ path, resourceType: import_common.ResourceType.database, resourceId: id, options, diagnosticNode }); return new import_DatabaseResponse.DatabaseResponse( response.result, response.headers, response.code, this, (0, import_diagnostics.getEmptyCosmosDiagnostics)() ); } /** Delete the given Database. * @example * ```ts snippet:CosmosClientDatabaseDelete * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * await client.database("<id here>").delete(); * ``` */ async delete(options) { return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { const path = (0, import_common.getPathFromLink)(this.url); const id = (0, import_common.getIdFromLink)(this.url); const response = await this.clientContext.delete({ path, resourceType: import_common.ResourceType.database, resourceId: id, options, diagnosticNode }); return new import_DatabaseResponse.DatabaseResponse( response.result, response.headers, response.code, this, (0, import_diagnostics.getEmptyCosmosDiagnostics)() ); }, this.clientContext); } /** * Gets offer on database. If none exists, returns an OfferResponse with undefined. * @example Read the offer on the database * ```ts snippet:DatabaseReadOffer * import { CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const client = new CosmosClient({ endpoint, key }); * * const { resource: offer } = await client.database("<db id>").readOffer(); * ``` */ async readOffer(options = {}) { return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { const { resource: record } = await (0, import_diagnostics.withMetadataDiagnostics)( async (node) => { return this.readInternal(node); }, diagnosticNode, import_CosmosDiagnostics.MetadataLookUpType.DatabaseLookUp ); const path = "/offers"; const url = record._self; const response = await this.clientContext.queryFeed({ path, resourceId: "", resourceType: import_common.ResourceType.offer, query: `SELECT * from root where root.resource = "${url}"`, resultFn: (result) => result.Offers, options, diagnosticNode }); const offer = response.result[0] ? new import_Offer.Offer(this.client, response.result[0].id, this.clientContext) : void 0; return new import_Offer.OfferResponse( response.result[0], response.headers, response.code, (0, import_diagnostics.getEmptyCosmosDiagnostics)(), offer ); }, this.clientContext); } /** * Create Encryption key for database account * @example * ```ts snippet:DatabaseCreateClientEncryptionKey * import { ClientSecretCredential } from "@azure/identity"; * import { * AzureKeyVaultEncryptionKeyResolver, * CosmosClient, * EncryptionKeyWrapMetadata, * EncryptionKeyResolverName, * KeyEncryptionAlgorithm, * EncryptionAlgorithm, * } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const credentials = new ClientSecretCredential("<tenant-id>", "<client-id>", "<app-secret>"); * const keyResolver = new AzureKeyVaultEncryptionKeyResolver(credentials); * const client = new CosmosClient({ * endpoint, * key, * clientEncryptionOptions: { * keyEncryptionKeyResolver: keyResolver, * }, * }); * const { database } = await client.databases.createIfNotExists({ id: "<db id>" }); * const metadata: EncryptionKeyWrapMetadata = { * type: EncryptionKeyResolverName.AzureKeyVault, * name: "<key-name>", * value: "<key-vault-url>", * algorithm: KeyEncryptionAlgorithm.RSA_OAEP, * }; * * await database.createClientEncryptionKey( * "<cek-id>", * EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, * metadata, * ); * ``` */ async createClientEncryptionKey(clientEncryptionKeyId, encryptionAlgorithm, keyWrapMetadata) { if (clientEncryptionKeyId == null || !clientEncryptionKeyId.trim()) { throw new Error("encryption key id cannot be null or empty"); } if (encryptionAlgorithm !== import_encryption.EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256) { throw new Error(`Invalid encryption algorithm '${encryptionAlgorithm}' passed.`); } if (!keyWrapMetadata) { throw new Error("encryptionKeyWrapMetadata cannot be null."); } if (keyWrapMetadata.algorithm !== import_encryption.KeyEncryptionAlgorithm.RSA_OAEP) { throw new Error(`Invalid key wrap algorithm '${keyWrapMetadata.algorithm}' passed.`); } if (!this.clientContext.enableEncryption) { throw new Error( "Creating a client encryption key requires the use of an encryption-enabled client." ); } const keyEncryptionKey = this.encryptionManager.keyEncryptionKeyCache.getOrCreate( keyWrapMetadata.name, keyWrapMetadata.value, this.encryptionManager.encryptionKeyStoreProvider ); const protectedDataEncryptionKey = await this.encryptionManager.protectedDataEncryptionKeyCache.getOrCreate( clientEncryptionKeyId, keyEncryptionKey ); const wrappedDataEncryptionKey = protectedDataEncryptionKey.encryptedValue; const body = { id: clientEncryptionKeyId, encryptionAlgorithm, keyWrapMetadata, wrappedDataEncryptionKey: wrappedDataEncryptionKey.toString("base64") }; return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { const path = (0, import_common.getPathFromLink)(this.url, import_common.ResourceType.clientencryptionkey); const databaseId = (0, import_common.getIdFromLink)(this.url); const response = await this.clientContext.create({ body, path, resourceType: import_common.ResourceType.clientencryptionkey, resourceId: databaseId, diagnosticNode }); const ref = { id: response.result.id, encryptionAlgorithm: response.result.encryptionAlgorithm, etag: response.result._etag, wrappedDataEncryptionKey: new Uint8Array( Buffer.from(response.result.wrappedDataEncryptionKey, "base64") ), encryptionKeyWrapMetadata: response.result.keyWrapMetadata }; return new import_encryption.ClientEncryptionKeyResponse( response.result, response.headers, response.code, ref, (0, import_diagnostics.getEmptyCosmosDiagnostics)() ); }, this.clientContext); } /** * Read Encryption key for database account * @example * ```ts snippet:DatabaseReadClientEncryptionKey * import { ClientSecretCredential } from "@azure/identity"; * import { AzureKeyVaultEncryptionKeyResolver, CosmosClient } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const credentials = new ClientSecretCredential("<tenant-id>", "<client-id>", "<app-secret>"); * const keyResolver = new AzureKeyVaultEncryptionKeyResolver(credentials); * const client = new CosmosClient({ * endpoint, * key, * clientEncryptionOptions: { * keyEncryptionKeyResolver: keyResolver, * }, * }); * const { database } = await client.databases.createIfNotExists({ id: "<db id>" }); * * const { resource: clientEncryptionKey } = await database.readClientEncryptionKey("<cek-id>"); * ``` */ async readClientEncryptionKey(clientEncryptionKeyId) { if (clientEncryptionKeyId == null || !clientEncryptionKeyId.trim()) { throw new import_request.ErrorResponse("encryption key id cannot be null or empty"); } return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { if (!this._rid) { const databaseResponse = await this.readInternal(diagnosticNode); if (!databaseResponse || !databaseResponse.resource) { throw new import_request.ErrorResponse(`Error reading database with id ${clientEncryptionKeyId}`); } this._rid = databaseResponse.resource._rid; } const path = (0, import_common.getPathFromLink)(this.url, import_common.ResourceType.clientencryptionkey); const resourceid = (0, import_common.getIdFromLink)(this.url); const response = await this.clientContext.read({ path: path + `/${clientEncryptionKeyId}`, resourceType: import_common.ResourceType.clientencryptionkey, resourceId: resourceid + `/${import_common.ResourceType.clientencryptionkey}/${clientEncryptionKeyId}`, options: { databaseRid: this._rid }, diagnosticNode }); if (!response || !response.result) { throw new import_request.ErrorResponse( `Error reading client encryption key with id ${clientEncryptionKeyId}` ); } const ref = { id: response.result.id, encryptionAlgorithm: response.result.encryptionAlgorithm, etag: response.result._etag, wrappedDataEncryptionKey: new Uint8Array( Buffer.from(response.result.wrappedDataEncryptionKey, "base64") ), encryptionKeyWrapMetadata: response.result.keyWrapMetadata }; return new import_encryption.ClientEncryptionKeyResponse( response.result, response.headers, response.code, ref, (0, import_diagnostics.getEmptyCosmosDiagnostics)() ); }, this.clientContext); } /** * rewraps a client encryption key with new key encryption key * @param id - client encryption key id * @param newKeyWrapMetadata - new encryption key wrap metadata * @returns rewrapped client encryption key with new customer managed key * @example * ```ts snippet:DatabaseRewrapClientEncryptionKey * import { ClientSecretCredential } from "@azure/identity"; * import { * AzureKeyVaultEncryptionKeyResolver, * CosmosClient, * EncryptionKeyWrapMetadata, * EncryptionKeyResolverName, * KeyEncryptionAlgorithm, * } from "@azure/cosmos"; * * const endpoint = "https://your-account.documents.azure.com"; * const key = "<database account masterkey>"; * const credentials = new ClientSecretCredential("<tenant-id>", "<client-id>", "<app-secret>"); * const keyResolver = new AzureKeyVaultEncryptionKeyResolver(credentials); * const client = new CosmosClient({ * endpoint, * key, * clientEncryptionOptions: { * keyEncryptionKeyResolver: keyResolver, * }, * }); * const { database } = await client.databases.createIfNotExists({ id: "<db id>" }); * const newMetadata: EncryptionKeyWrapMetadata = { * type: EncryptionKeyResolverName.AzureKeyVault, * name: "<key-name>", * value: "<key-vault-url>", * algorithm: KeyEncryptionAlgorithm.RSA_OAEP, * }; * * await database.rewrapClientEncryptionKey("<new-cek-id>", newMetadata); * ``` */ async rewrapClientEncryptionKey(clientEncryptionKeyId, newKeyWrapMetadata) { if (clientEncryptionKeyId == null || !clientEncryptionKeyId.trim()) { throw new import_request.ErrorResponse("encryption key id cannot be null or empty"); } if (!newKeyWrapMetadata) { throw new import_request.ErrorResponse("encryptionKeyWrapMetadata cannot be null."); } if (newKeyWrapMetadata.algorithm !== import_encryption.KeyEncryptionAlgorithm.RSA_OAEP) { throw new import_request.ErrorResponse( `Invalid key wrap algorithm '${newKeyWrapMetadata.algorithm}' passed.` ); } if (!this.clientContext.enableEncryption) { throw new import_request.ErrorResponse( "Rewrapping a client encryption key requires the use of an encryption-enabled client." ); } const res = await this.readClientEncryptionKey(clientEncryptionKeyId); if (!res || !res.clientEncryptionKeyProperties) { throw new import_request.ErrorResponse( `Error reading client encryption key with id ${clientEncryptionKeyId}` ); } let clientEncryptionKeyProperties = res.clientEncryptionKeyProperties; let keyEncryptionKey = this.encryptionManager.keyEncryptionKeyCache.getOrCreate( clientEncryptionKeyProperties.encryptionKeyWrapMetadata.name, clientEncryptionKeyProperties.encryptionKeyWrapMetadata.value, this.encryptionManager.encryptionKeyStoreProvider ); const unwrappedKey = await keyEncryptionKey.unwrapEncryptionKey( Buffer.from(clientEncryptionKeyProperties.wrappedDataEncryptionKey) ); keyEncryptionKey = this.encryptionManager.keyEncryptionKeyCache.getOrCreate( newKeyWrapMetadata.name, newKeyWrapMetadata.value, this.encryptionManager.encryptionKeyStoreProvider ); const rewrappedKey = await keyEncryptionKey.wrapEncryptionKey(unwrappedKey); clientEncryptionKeyProperties = { id: clientEncryptionKeyId, encryptionAlgorithm: clientEncryptionKeyProperties.encryptionAlgorithm, etag: clientEncryptionKeyProperties.etag, wrappedDataEncryptionKey: rewrappedKey, encryptionKeyWrapMetadata: newKeyWrapMetadata }; const body = { id: clientEncryptionKeyId, encryptionAlgorithm: clientEncryptionKeyProperties.encryptionAlgorithm, keyWrapMetadata: newKeyWrapMetadata, wrappedDataEncryptionKey: rewrappedKey.toString("base64") }; return (0, import_diagnostics.withDiagnostics)(async (diagnosticNode) => { const path = (0, import_common.getPathFromLink)(this.url, import_common.ResourceType.clientencryptionkey); const resourceid = (0, import_common.getIdFromLink)(this.url); const options = { accessCondition: { type: "IfMatch", condition: clientEncryptionKeyProperties.etag } }; const response = await this.clientContext.replace({ body, path: path + `/${clientEncryptionKeyId}`, resourceType: import_common.ResourceType.clientencryptionkey, resourceId: resourceid + `/${import_common.ResourceType.clientencryptionkey}/${clientEncryptionKeyId}`, options, diagnosticNode }); if (!response || !response.result) { throw new import_request.ErrorResponse( `Error rewrapping client encryption key with id ${clientEncryptionKeyId}` ); } const ref = { id: response.result.id, encryptionAlgorithm: response.result.encryptionAlgorithm, etag: response.result._etag, wrappedDataEncryptionKey: new Uint8Array( Buffer.from(response.result.wrappedDataEncryptionKey, "base64") ), encryptionKeyWrapMetadata: response.result.keyWrapMetadata }; return new import_encryption.ClientEncryptionKeyResponse( response.result, response.headers, response.code, ref, (0, import_diagnostics.getEmptyCosmosDiagnostics)() ); }, this.clientContext); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Database });