@microsoft/agents-hosting-storage-cosmos 0.1.49

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/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @microsoft/agents-hosting-storage-cosmos
2
+
3
+ ## Overview
4
+
5
+ This package allows to configure Azure CosmosDB Storage as the backend for Agents conversation State
6
+
7
+ ## Usage
8
+
9
+ ```ts
10
+ const cosmosDbStorageOptions = {
11
+ databaseId: process.env.COSMOS_DATABASE_ID || 'agentsDB',
12
+ containerId: process.env.COSMOS_CONTAINER_ID || 'agentsState',
13
+ cosmosClientOptions: {
14
+ endpoint: process.env.COSMOS_ENDPOINT!,
15
+ key: process.env.COSMOS_KEY!,
16
+ }
17
+ } as CosmosDbPartitionedStorageOptions
18
+ const cosmosStorage = new CosmosDbPartitionedStorage(cosmosDbStorageOptions)
19
+ const conversationState = new ConversationState(cosmosStorage)
20
+ const userState = new UserState(cosmosStorage)
21
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ __exportStar(require("./src"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Provides methods for escaping keys for Cosmos DB.
3
+ */
4
+ export declare namespace CosmosDbKeyEscape {
5
+ /**
6
+ * Escapes a key for use in Cosmos DB.
7
+ * @param key The key to escape.
8
+ * @param keySuffix The suffix to append to the key.
9
+ * @param compatibilityMode Indicates whether compatibility mode is enabled.
10
+ * @returns The escaped key.
11
+ */
12
+ function escapeKey(key: string, keySuffix?: string, compatibilityMode?: boolean): string;
13
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CosmosDbKeyEscape = void 0;
4
+ // Copyright (c) Microsoft Corporation. All rights reserved.
5
+ // Licensed under the MIT License.
6
+ const crypto_1 = require("crypto");
7
+ /**
8
+ * Provides methods for escaping keys for Cosmos DB.
9
+ */
10
+ var CosmosDbKeyEscape;
11
+ (function (CosmosDbKeyEscape) {
12
+ const maxKeyLength = 255;
13
+ const illegalKeys = ['\\', '?', '/', '#', '\t', '\n', '\r', '*'];
14
+ const illegalKeyCharacterReplacementMap = illegalKeys.reduce((map, c) => {
15
+ map.set(c, `*${c.charCodeAt(0).toString(16)}`);
16
+ return map;
17
+ }, new Map());
18
+ /**
19
+ * Escapes a key for use in Cosmos DB.
20
+ * @param key The key to escape.
21
+ * @param keySuffix The suffix to append to the key.
22
+ * @param compatibilityMode Indicates whether compatibility mode is enabled.
23
+ * @returns The escaped key.
24
+ */
25
+ function escapeKey(key, keySuffix, compatibilityMode) {
26
+ if (!key) {
27
+ throw new Error("The 'key' parameter is required.");
28
+ }
29
+ const keySplitted = key.split('');
30
+ const firstIllegalCharIndex = keySplitted.findIndex((c) => illegalKeys.some((i) => i === c));
31
+ if (firstIllegalCharIndex === -1) {
32
+ return truncateKey(`${key}${keySuffix || ''}`, compatibilityMode);
33
+ }
34
+ const sanitizedKey = keySplitted.reduce((result, c) => result + (illegalKeyCharacterReplacementMap.has(c) ? illegalKeyCharacterReplacementMap.get(c) : c), '');
35
+ return truncateKey(`${sanitizedKey}${keySuffix || ''}`, compatibilityMode);
36
+ }
37
+ CosmosDbKeyEscape.escapeKey = escapeKey;
38
+ function truncateKey(key, truncateKeysForCompatibility) {
39
+ if (truncateKeysForCompatibility === false) {
40
+ return key;
41
+ }
42
+ if (key.length > maxKeyLength) {
43
+ key = hashKey(key);
44
+ }
45
+ return key;
46
+ }
47
+ function hashKey(key) {
48
+ const hash = (0, crypto_1.createHash)('sha256');
49
+ hash.update(key);
50
+ return hash.digest('hex');
51
+ }
52
+ })(CosmosDbKeyEscape || (exports.CosmosDbKeyEscape = CosmosDbKeyEscape = {}));
53
+ //# sourceMappingURL=cosmosDbKeyEscape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosmosDbKeyEscape.js","sourceRoot":"","sources":["../../src/cosmosDbKeyEscape.ts"],"names":[],"mappings":";;;AAAA,4DAA4D;AAC5D,kCAAkC;AAClC,mCAAmC;AAEnC;;GAEG;AACH,IAAiB,iBAAiB,CAyDjC;AAzDD,WAAiB,iBAAiB;IAChC,MAAM,YAAY,GAAW,GAAG,CAAA;IAChC,MAAM,WAAW,GAAsB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;IACnF,MAAM,iCAAiC,GAAwB,WAAW,CAAC,MAAM,CAC/E,CAAC,GAAwB,EAAE,CAAS,EAAE,EAAE;QACtC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAC9C,OAAO,GAAG,CAAA;IACZ,CAAC,EACD,IAAI,GAAG,EAAE,CACV,CAAA;IAED;;;;;;OAMG;IACH,SAAgB,SAAS,CAAE,GAAW,EAAE,SAAkB,EAAE,iBAA2B;QACrF,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;QACrD,CAAC;QAED,MAAM,WAAW,GAAa,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC3C,MAAM,qBAAqB,GAAW,WAAW,CAAC,SAAS,CAAC,CAAC,CAAS,EAAW,EAAE,CACjF,WAAW,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CACzC,CAAA;QAED,IAAI,qBAAqB,KAAK,CAAC,CAAC,EAAE,CAAC;YACjC,OAAO,WAAW,CAAC,GAAG,GAAG,GAAG,SAAS,IAAI,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAA;QACnE,CAAC;QAED,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CACrC,CAAC,MAAc,EAAE,CAAS,EAAE,EAAE,CAC5B,MAAM,GAAG,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EACrG,EAAE,CACH,CAAA;QAED,OAAO,WAAW,CAAC,GAAG,YAAY,GAAG,SAAS,IAAI,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAA;IAC5E,CAAC;IArBe,2BAAS,YAqBxB,CAAA;IAED,SAAS,WAAW,CAAE,GAAW,EAAE,4BAAsC;QACvE,IAAI,4BAA4B,KAAK,KAAK,EAAE,CAAC;YAC3C,OAAO,GAAG,CAAA;QACZ,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YAC9B,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,SAAS,OAAO,CAAE,GAAW;QAC3B,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAA;QACjC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;AACH,CAAC,EAzDgB,iBAAiB,iCAAjB,iBAAiB,QAyDjC"}
@@ -0,0 +1,46 @@
1
+ import { CosmosDbPartitionedStorageOptions } from './cosmosDbPartitionedStorageOptions';
2
+ import { Storage, StoreItems } from '@microsoft/agents-hosting';
3
+ export declare class DoOnce<T> {
4
+ private task;
5
+ waitFor(key: string, fn: () => Promise<T>): Promise<T>;
6
+ }
7
+ /**
8
+ * Implements storage using Cosmos DB partitioned storage.
9
+ */
10
+ export declare class CosmosDbPartitionedStorage implements Storage {
11
+ private readonly cosmosDbStorageOptions;
12
+ private container;
13
+ private client;
14
+ private compatibilityModePartitionKey;
15
+ [key: string]: any;
16
+ length: number;
17
+ /**
18
+ * Initializes a new instance of the CosmosDbPartitionedStorage class.
19
+ * @param cosmosDbStorageOptions The options for configuring Cosmos DB partitioned storage.
20
+ */
21
+ constructor(cosmosDbStorageOptions: CosmosDbPartitionedStorageOptions);
22
+ /**
23
+ * Reads items from storage.
24
+ * @param keys The keys of the items to read.
25
+ * @returns A promise that resolves to the read items.
26
+ */
27
+ read(keys: string[]): Promise<StoreItems>;
28
+ /**
29
+ * Writes items to storage.
30
+ * @param changes The items to write.
31
+ */
32
+ write(changes: StoreItems): Promise<void>;
33
+ /**
34
+ * Deletes items from storage.
35
+ * @param keys The keys of the items to delete.
36
+ */
37
+ delete(keys: string[]): Promise<void>;
38
+ /**
39
+ * Initializes the Cosmos DB container.
40
+ */
41
+ initialize(): Promise<void>;
42
+ private getOrCreateContainer;
43
+ private getPartitionKey;
44
+ private checkForNestingError;
45
+ private throwInformativeError;
46
+ }
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.CosmosDbPartitionedStorage = exports.DoOnce = void 0;
6
+ const cosmos_1 = require("@azure/cosmos");
7
+ const cosmosDbKeyEscape_1 = require("./cosmosDbKeyEscape");
8
+ const documentStoreItem_1 = require("./documentStoreItem");
9
+ class DoOnce {
10
+ constructor() {
11
+ this.task = {};
12
+ }
13
+ waitFor(key, fn) {
14
+ if (!this.task[key]) {
15
+ this.task[key] = fn();
16
+ }
17
+ return this.task[key];
18
+ }
19
+ }
20
+ exports.DoOnce = DoOnce;
21
+ const _doOnce = new DoOnce();
22
+ const maxDepthAllowed = 127;
23
+ /**
24
+ * Implements storage using Cosmos DB partitioned storage.
25
+ */
26
+ class CosmosDbPartitionedStorage {
27
+ /**
28
+ * Initializes a new instance of the CosmosDbPartitionedStorage class.
29
+ * @param cosmosDbStorageOptions The options for configuring Cosmos DB partitioned storage.
30
+ */
31
+ constructor(cosmosDbStorageOptions) {
32
+ var _a;
33
+ this.cosmosDbStorageOptions = cosmosDbStorageOptions;
34
+ this.compatibilityModePartitionKey = false;
35
+ this.length = 0;
36
+ if (!cosmosDbStorageOptions) {
37
+ throw new ReferenceError('CosmosDbPartitionedStorageOptions is required.');
38
+ }
39
+ const { cosmosClientOptions } = cosmosDbStorageOptions;
40
+ if (!(cosmosClientOptions === null || cosmosClientOptions === void 0 ? void 0 : cosmosClientOptions.endpoint)) {
41
+ throw new ReferenceError('endpoint in cosmosClientOptions is required.');
42
+ }
43
+ if (!(cosmosClientOptions === null || cosmosClientOptions === void 0 ? void 0 : cosmosClientOptions.key) && !(cosmosClientOptions === null || cosmosClientOptions === void 0 ? void 0 : cosmosClientOptions.tokenProvider)) {
44
+ throw new ReferenceError('key or tokenProvider in cosmosClientOptions is required.');
45
+ }
46
+ if (!cosmosDbStorageOptions.databaseId) {
47
+ throw new ReferenceError('databaseId is for CosmosDB required.');
48
+ }
49
+ if (!cosmosDbStorageOptions.containerId) {
50
+ throw new ReferenceError('containerId for CosmosDB is required.');
51
+ }
52
+ (_a = cosmosDbStorageOptions.compatibilityMode) !== null && _a !== void 0 ? _a : (cosmosDbStorageOptions.compatibilityMode = true);
53
+ if (cosmosDbStorageOptions.keySuffix) {
54
+ if (cosmosDbStorageOptions.compatibilityMode) {
55
+ throw new ReferenceError('compatibilityMode cannot be true while using a keySuffix.');
56
+ }
57
+ const suffixEscaped = cosmosDbKeyEscape_1.CosmosDbKeyEscape.escapeKey(cosmosDbStorageOptions.keySuffix);
58
+ if (cosmosDbStorageOptions.keySuffix !== suffixEscaped) {
59
+ throw new ReferenceError(`Cannot use invalid Row Key characters: ${cosmosDbStorageOptions.keySuffix} in keySuffix`);
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * Reads items from storage.
65
+ * @param keys The keys of the items to read.
66
+ * @returns A promise that resolves to the read items.
67
+ */
68
+ async read(keys) {
69
+ if (!keys) {
70
+ throw new ReferenceError('Keys are required when reading.');
71
+ }
72
+ else if (keys.length === 0) {
73
+ return {};
74
+ }
75
+ await this.initialize();
76
+ const storeItems = {};
77
+ await Promise.all(keys.map(async (k) => {
78
+ try {
79
+ const escapedKey = cosmosDbKeyEscape_1.CosmosDbKeyEscape.escapeKey(k, this.cosmosDbStorageOptions.keySuffix, this.cosmosDbStorageOptions.compatibilityMode);
80
+ const readItemResponse = await this.container
81
+ .item(escapedKey, this.getPartitionKey(escapedKey))
82
+ .read();
83
+ const documentStoreItem = readItemResponse.resource;
84
+ if (documentStoreItem) {
85
+ storeItems[documentStoreItem.realId] = documentStoreItem.document;
86
+ storeItems[documentStoreItem.realId].eTag = documentStoreItem._etag;
87
+ }
88
+ }
89
+ catch (err) {
90
+ if (err.code === 404) {
91
+ this.throwInformativeError('Not Found', err);
92
+ }
93
+ else if (err.code === 400) {
94
+ this.throwInformativeError(`Error reading from container. You might be attempting to read from a non-partitioned
95
+ container or a container that does not use '/id' as the partitionKeyPath`, err);
96
+ }
97
+ else {
98
+ this.throwInformativeError('Error reading from container', err);
99
+ }
100
+ }
101
+ }));
102
+ return storeItems;
103
+ }
104
+ /**
105
+ * Writes items to storage.
106
+ * @param changes The items to write.
107
+ */
108
+ async write(changes) {
109
+ if (!changes) {
110
+ throw new ReferenceError('Changes are required when writing.');
111
+ }
112
+ else if (changes.length === 0) {
113
+ return;
114
+ }
115
+ await this.initialize();
116
+ await Promise.all(Object.entries(changes).map(async ([key, { eTag, ...change }]) => {
117
+ const document = new documentStoreItem_1.DocumentStoreItem({
118
+ id: cosmosDbKeyEscape_1.CosmosDbKeyEscape.escapeKey(key, this.cosmosDbStorageOptions.keySuffix, this.cosmosDbStorageOptions.compatibilityMode),
119
+ realId: key,
120
+ document: change,
121
+ });
122
+ const accessCondition = eTag !== '*' && eTag != null && eTag.length > 0
123
+ ? { accessCondition: { type: 'IfMatch', condition: eTag } }
124
+ : undefined;
125
+ try {
126
+ await this.container.items.upsert(document, accessCondition);
127
+ }
128
+ catch (err) {
129
+ this.checkForNestingError(change, err);
130
+ this.throwInformativeError('Error upserting document', err);
131
+ }
132
+ }));
133
+ }
134
+ /**
135
+ * Deletes items from storage.
136
+ * @param keys The keys of the items to delete.
137
+ */
138
+ async delete(keys) {
139
+ await this.initialize();
140
+ await Promise.all(keys.map(async (k) => {
141
+ const escapedKey = cosmosDbKeyEscape_1.CosmosDbKeyEscape.escapeKey(k, this.cosmosDbStorageOptions.keySuffix, this.cosmosDbStorageOptions.compatibilityMode);
142
+ try {
143
+ await this.container.item(escapedKey, this.getPartitionKey(escapedKey)).delete();
144
+ }
145
+ catch (err) {
146
+ if (err.code === 404) {
147
+ this.throwInformativeError('Not Found', err);
148
+ }
149
+ else {
150
+ this.throwInformativeError('Unable to delete document', err);
151
+ }
152
+ }
153
+ }));
154
+ }
155
+ /**
156
+ * Initializes the Cosmos DB container.
157
+ */
158
+ async initialize() {
159
+ if (!this.container) {
160
+ if (!this.client) {
161
+ this.client = new cosmos_1.CosmosClient(this.cosmosDbStorageOptions.cosmosClientOptions);
162
+ }
163
+ const dbAndContainerKey = `${this.cosmosDbStorageOptions.databaseId}-${this.cosmosDbStorageOptions.containerId}`;
164
+ this.container = await _doOnce.waitFor(dbAndContainerKey, async () => await this.getOrCreateContainer());
165
+ }
166
+ }
167
+ async getOrCreateContainer() {
168
+ let createIfNotExists = !this.cosmosDbStorageOptions.compatibilityMode;
169
+ let container;
170
+ try {
171
+ const { database } = await this.client.databases.createIfNotExists({
172
+ id: this.cosmosDbStorageOptions.databaseId
173
+ });
174
+ if (this.cosmosDbStorageOptions.compatibilityMode) {
175
+ try {
176
+ container = database.container(this.cosmosDbStorageOptions.containerId);
177
+ // @ts-ignore
178
+ const partitionKeyResponse = await container.readPartitionKeyDefinition();
179
+ if (partitionKeyResponse.resource && partitionKeyResponse.resource.paths) {
180
+ const paths = partitionKeyResponse.resource.paths;
181
+ if (paths.includes('/_partitionKey')) {
182
+ this.compatibilityModePartitionKey = true;
183
+ }
184
+ else if (paths.indexOf(documentStoreItem_1.DocumentStoreItem.partitionKeyPath) === -1) {
185
+ throw new Error(`Custom Partition Key Paths are not supported. ${this.cosmosDbStorageOptions.containerId} has a custom Partition Key Path of ${paths[0]}.`);
186
+ }
187
+ }
188
+ else {
189
+ this.compatibilityModePartitionKey = true;
190
+ }
191
+ return container;
192
+ }
193
+ catch {
194
+ createIfNotExists = true;
195
+ }
196
+ }
197
+ if (createIfNotExists) {
198
+ const result = await database.containers.createIfNotExists({
199
+ id: this.cosmosDbStorageOptions.containerId,
200
+ partitionKey: {
201
+ paths: [documentStoreItem_1.DocumentStoreItem.partitionKeyPath],
202
+ },
203
+ throughput: this.cosmosDbStorageOptions.containerThroughput,
204
+ });
205
+ return result.container;
206
+ }
207
+ if (!container) {
208
+ throw new Error(`Container ${this.cosmosDbStorageOptions.containerId} not found.`);
209
+ }
210
+ return container;
211
+ }
212
+ catch (err) {
213
+ this.throwInformativeError(`Failed to initialize Cosmos DB database/container: ${this.cosmosDbStorageOptions.databaseId}/${this.cosmosDbStorageOptions.containerId}`, err);
214
+ throw err;
215
+ }
216
+ }
217
+ getPartitionKey(key) {
218
+ return this.compatibilityModePartitionKey ? undefined : key;
219
+ }
220
+ checkForNestingError(json, err) {
221
+ const checkDepth = (obj, depth, isInDialogState) => {
222
+ if (depth > maxDepthAllowed) {
223
+ let message = `Maximum nesting depth of ${maxDepthAllowed} exceeded.`;
224
+ if (isInDialogState) {
225
+ message +=
226
+ ' This is most likely caused by recursive component dialogs. ' +
227
+ 'Try reworking your dialog code to make sure it does not keep dialogs on the stack ' +
228
+ "that it's not using. For example, consider using replaceDialog instead of beginDialog.";
229
+ }
230
+ else {
231
+ message += ' Please check your data for signs of unintended recursion.';
232
+ }
233
+ this.throwInformativeError(message, err);
234
+ }
235
+ else if (obj && typeof obj === 'object') {
236
+ for (const [key, value] of Object.entries(obj)) {
237
+ checkDepth(value, depth + 1, key === 'dialogStack' || isInDialogState);
238
+ }
239
+ }
240
+ };
241
+ checkDepth(json, 0, false);
242
+ }
243
+ throwInformativeError(prependedMessage, err) {
244
+ if (typeof err === 'string') {
245
+ err = new Error(err);
246
+ }
247
+ err.message = `[${prependedMessage}] ${err.message}`;
248
+ throw err;
249
+ }
250
+ }
251
+ exports.CosmosDbPartitionedStorage = CosmosDbPartitionedStorage;
252
+ //# sourceMappingURL=cosmosDbPartitionedStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosmosDbPartitionedStorage.js","sourceRoot":"","sources":["../../src/cosmosDbPartitionedStorage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { CosmosClientOptions } from '@azure/cosmos';
2
+ /**
3
+ * Options for configuring Cosmos DB partitioned storage.
4
+ */
5
+ export interface CosmosDbPartitionedStorageOptions {
6
+ /**
7
+ * The ID of the database.
8
+ */
9
+ databaseId: string;
10
+ /**
11
+ * The ID of the container.
12
+ */
13
+ containerId: string;
14
+ /**
15
+ * The throughput of the container.
16
+ */
17
+ containerThroughput?: number;
18
+ /**
19
+ * The suffix to append to keys.
20
+ */
21
+ keySuffix?: string;
22
+ /**
23
+ * Indicates whether compatibility mode is enabled.
24
+ */
25
+ compatibilityMode?: boolean;
26
+ /**
27
+ * The options for the Cosmos client.
28
+ */
29
+ cosmosClientOptions?: CosmosClientOptions;
30
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ //# sourceMappingURL=cosmosDbPartitionedStorageOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cosmosDbPartitionedStorageOptions.js","sourceRoot":"","sources":["../../src/cosmosDbPartitionedStorageOptions.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Represents an item stored in the document store.
3
+ */
4
+ export declare class DocumentStoreItem {
5
+ /**
6
+ * Gets the partition key path.
7
+ */
8
+ static get partitionKeyPath(): string;
9
+ /**
10
+ * The ID of the document.
11
+ */
12
+ id: string;
13
+ /**
14
+ * The real ID of the document.
15
+ */
16
+ realId: string;
17
+ /**
18
+ * The document object.
19
+ */
20
+ document: object;
21
+ /**
22
+ * The ETag of the document.
23
+ */
24
+ eTag: string;
25
+ /**
26
+ * Gets the partition key.
27
+ */
28
+ get partitionKey(): string;
29
+ /**
30
+ * Initializes a new instance of the DocumentStoreItem class.
31
+ * @param storeItem The store item to initialize.
32
+ */
33
+ constructor(storeItem: {
34
+ id: string;
35
+ realId: string;
36
+ document: object;
37
+ eTag?: string;
38
+ });
39
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.DocumentStoreItem = void 0;
6
+ /**
7
+ * Represents an item stored in the document store.
8
+ */
9
+ class DocumentStoreItem {
10
+ /**
11
+ * Gets the partition key path.
12
+ */
13
+ static get partitionKeyPath() {
14
+ return '/id';
15
+ }
16
+ /**
17
+ * Gets the partition key.
18
+ */
19
+ get partitionKey() {
20
+ return this.id;
21
+ }
22
+ /**
23
+ * Initializes a new instance of the DocumentStoreItem class.
24
+ * @param storeItem The store item to initialize.
25
+ */
26
+ constructor(storeItem) {
27
+ this.id = storeItem.id;
28
+ this.realId = storeItem.realId || '';
29
+ this.document = storeItem.document || {};
30
+ this.eTag = storeItem.eTag || '';
31
+ }
32
+ }
33
+ exports.DocumentStoreItem = DocumentStoreItem;
34
+ //# sourceMappingURL=documentStoreItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentStoreItem.js","sourceRoot":"","sources":["../../src/documentStoreItem.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;AAElC;;GAEG;AACH,MAAa,iBAAiB;IAC5B;;OAEG;IACH,MAAM,KAAK,gBAAgB;QACzB,OAAO,KAAK,CAAA;IACd,CAAC;IAmBD;;OAEG;IACH,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IAED;;;OAGG;IACH,YAAa,SAA0E;QACrF,IAAI,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAA;QACtB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,EAAE,CAAA;QACpC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAA;QACxC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,EAAE,CAAA;IAClC,CAAC;CACF;AA1CD,8CA0CC"}
@@ -0,0 +1,2 @@
1
+ export * from './cosmosDbPartitionedStorage';
2
+ export * from './cosmosDbPartitionedStorageOptions';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ __exportStar(require("./cosmosDbPartitionedStorage"), exports);
20
+ __exportStar(require("./cosmosDbPartitionedStorageOptions"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,kCAAkC;;;;;;;;;;;;;;;;AAElC,+DAA4C;AAC5C,sEAAmD"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package.json",
3
+ "name": "@microsoft/agents-hosting-storage-cosmos",
4
+ "version": "0.1.49",
5
+ "homepage": "https://github.com/microsoft/Agents-for-js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/microsoft/Agents-for-js.git"
9
+ },
10
+ "author": {
11
+ "name": "Microsoft",
12
+ "email": "agentssdk@microsoft.com",
13
+ "url": "https://aka.ms/Agents"
14
+ },
15
+ "description": "Microsoft 365 Agents SDK State Cosmos Storage support.",
16
+ "main": "dist/index.js",
17
+ "types": "dist/src/index.d.ts",
18
+ "dependencies": {
19
+ "@azure/cosmos": "^4.3.0",
20
+ "@microsoft/agents-hosting": "0.1.49"
21
+ },
22
+ "license": "MIT",
23
+ "files": [
24
+ "README.md",
25
+ "dist/src",
26
+ "src"
27
+ ],
28
+ "exports": {
29
+ ".": {
30
+ "import": "./dist/src/index.js",
31
+ "require": "./dist/src/index.js"
32
+ },
33
+ "./package.json": "./package.json"
34
+ },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ }
38
+ }
@@ -0,0 +1,65 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+ import { createHash } from 'crypto'
4
+
5
+ /**
6
+ * Provides methods for escaping keys for Cosmos DB.
7
+ */
8
+ export namespace CosmosDbKeyEscape {
9
+ const maxKeyLength: number = 255
10
+ const illegalKeys: readonly string[] = ['\\', '?', '/', '#', '\t', '\n', '\r', '*']
11
+ const illegalKeyCharacterReplacementMap: Map<string, string> = illegalKeys.reduce<Map<string, string>>(
12
+ (map: Map<string, string>, c: string) => {
13
+ map.set(c, `*${c.charCodeAt(0).toString(16)}`)
14
+ return map
15
+ },
16
+ new Map()
17
+ )
18
+
19
+ /**
20
+ * Escapes a key for use in Cosmos DB.
21
+ * @param key The key to escape.
22
+ * @param keySuffix The suffix to append to the key.
23
+ * @param compatibilityMode Indicates whether compatibility mode is enabled.
24
+ * @returns The escaped key.
25
+ */
26
+ export function escapeKey (key: string, keySuffix?: string, compatibilityMode?: boolean): string {
27
+ if (!key) {
28
+ throw new Error("The 'key' parameter is required.")
29
+ }
30
+
31
+ const keySplitted: string[] = key.split('')
32
+ const firstIllegalCharIndex: number = keySplitted.findIndex((c: string): boolean =>
33
+ illegalKeys.some((i: string) => i === c)
34
+ )
35
+
36
+ if (firstIllegalCharIndex === -1) {
37
+ return truncateKey(`${key}${keySuffix || ''}`, compatibilityMode)
38
+ }
39
+
40
+ const sanitizedKey = keySplitted.reduce(
41
+ (result: string, c: string) =>
42
+ result + (illegalKeyCharacterReplacementMap.has(c) ? illegalKeyCharacterReplacementMap.get(c)! : c),
43
+ ''
44
+ )
45
+
46
+ return truncateKey(`${sanitizedKey}${keySuffix || ''}`, compatibilityMode)
47
+ }
48
+
49
+ function truncateKey (key: string, truncateKeysForCompatibility?: boolean): string {
50
+ if (truncateKeysForCompatibility === false) {
51
+ return key
52
+ }
53
+
54
+ if (key.length > maxKeyLength) {
55
+ key = hashKey(key)
56
+ }
57
+ return key
58
+ }
59
+
60
+ function hashKey (key: string): string {
61
+ const hash = createHash('sha256')
62
+ hash.update(key)
63
+ return hash.digest('hex')
64
+ }
65
+ }
@@ -0,0 +1,302 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { Container, CosmosClient } from '@azure/cosmos'
5
+ import { CosmosDbKeyEscape } from './cosmosDbKeyEscape'
6
+ import { DocumentStoreItem } from './documentStoreItem'
7
+ import { CosmosDbPartitionedStorageOptions } from './cosmosDbPartitionedStorageOptions'
8
+ import { Storage, StoreItems } from '@microsoft/agents-hosting'
9
+ export class DoOnce<T> {
10
+ private task: {
11
+ [key: string]: Promise<T>;
12
+ } = {}
13
+
14
+ waitFor (key: string, fn: () => Promise<T>): Promise<T> {
15
+ if (!this.task[key]) {
16
+ this.task[key] = fn()
17
+ }
18
+
19
+ return this.task[key]
20
+ }
21
+ }
22
+
23
+ const _doOnce: DoOnce<Container> = new DoOnce<Container>()
24
+
25
+ const maxDepthAllowed = 127
26
+
27
+ /**
28
+ * Implements storage using Cosmos DB partitioned storage.
29
+ */
30
+ export class CosmosDbPartitionedStorage implements Storage {
31
+ private container!: Container
32
+ private client!: CosmosClient
33
+ private compatibilityModePartitionKey = false;
34
+ [key: string]: any;
35
+ length: number = 0
36
+
37
+ /**
38
+ * Initializes a new instance of the CosmosDbPartitionedStorage class.
39
+ * @param cosmosDbStorageOptions The options for configuring Cosmos DB partitioned storage.
40
+ */
41
+ constructor (private readonly cosmosDbStorageOptions: CosmosDbPartitionedStorageOptions) {
42
+ if (!cosmosDbStorageOptions) {
43
+ throw new ReferenceError('CosmosDbPartitionedStorageOptions is required.')
44
+ }
45
+ const { cosmosClientOptions } = cosmosDbStorageOptions
46
+ if (!cosmosClientOptions?.endpoint) {
47
+ throw new ReferenceError('endpoint in cosmosClientOptions is required.')
48
+ }
49
+ if (!cosmosClientOptions?.key && !cosmosClientOptions?.tokenProvider) {
50
+ throw new ReferenceError('key or tokenProvider in cosmosClientOptions is required.')
51
+ }
52
+ if (!cosmosDbStorageOptions.databaseId) {
53
+ throw new ReferenceError('databaseId is for CosmosDB required.')
54
+ }
55
+ if (!cosmosDbStorageOptions.containerId) {
56
+ throw new ReferenceError('containerId for CosmosDB is required.')
57
+ }
58
+ cosmosDbStorageOptions.compatibilityMode ??= true
59
+ if (cosmosDbStorageOptions.keySuffix) {
60
+ if (cosmosDbStorageOptions.compatibilityMode) {
61
+ throw new ReferenceError('compatibilityMode cannot be true while using a keySuffix.')
62
+ }
63
+ const suffixEscaped = CosmosDbKeyEscape.escapeKey(cosmosDbStorageOptions.keySuffix)
64
+ if (cosmosDbStorageOptions.keySuffix !== suffixEscaped) {
65
+ throw new ReferenceError(
66
+ `Cannot use invalid Row Key characters: ${cosmosDbStorageOptions.keySuffix} in keySuffix`
67
+ )
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Reads items from storage.
74
+ * @param keys The keys of the items to read.
75
+ * @returns A promise that resolves to the read items.
76
+ */
77
+ async read (keys: string[]): Promise<StoreItems> {
78
+ if (!keys) {
79
+ throw new ReferenceError('Keys are required when reading.')
80
+ } else if (keys.length === 0) {
81
+ return {}
82
+ }
83
+
84
+ await this.initialize()
85
+
86
+ const storeItems: StoreItems = {}
87
+
88
+ await Promise.all(
89
+ keys.map(async (k: string): Promise<void> => {
90
+ try {
91
+ const escapedKey = CosmosDbKeyEscape.escapeKey(
92
+ k,
93
+ this.cosmosDbStorageOptions.keySuffix,
94
+ this.cosmosDbStorageOptions.compatibilityMode
95
+ )
96
+
97
+ const readItemResponse = await this.container
98
+ .item(escapedKey, this.getPartitionKey(escapedKey))
99
+ .read<DocumentStoreItem>()
100
+ const documentStoreItem = readItemResponse.resource
101
+ if (documentStoreItem) {
102
+ storeItems[documentStoreItem.realId] = documentStoreItem.document
103
+ storeItems[documentStoreItem.realId].eTag = documentStoreItem._etag
104
+ }
105
+ } catch (err: any) {
106
+ if (err.code === 404) {
107
+ this.throwInformativeError('Not Found',
108
+ err)
109
+ } else if (err.code === 400) {
110
+ this.throwInformativeError(
111
+ `Error reading from container. You might be attempting to read from a non-partitioned
112
+ container or a container that does not use '/id' as the partitionKeyPath`,
113
+ err
114
+ )
115
+ } else {
116
+ this.throwInformativeError('Error reading from container', err)
117
+ }
118
+ }
119
+ })
120
+ )
121
+
122
+ return storeItems
123
+ }
124
+
125
+ /**
126
+ * Writes items to storage.
127
+ * @param changes The items to write.
128
+ */
129
+ async write (changes: StoreItems): Promise<void> {
130
+ if (!changes) {
131
+ throw new ReferenceError('Changes are required when writing.')
132
+ } else if (changes.length === 0) {
133
+ return
134
+ }
135
+
136
+ await this.initialize()
137
+
138
+ await Promise.all(
139
+ Object.entries(changes).map(async ([key, { eTag, ...change }]): Promise<void> => {
140
+ const document = new DocumentStoreItem({
141
+ id: CosmosDbKeyEscape.escapeKey(
142
+ key,
143
+ this.cosmosDbStorageOptions.keySuffix,
144
+ this.cosmosDbStorageOptions.compatibilityMode
145
+ ),
146
+ realId: key,
147
+ document: change,
148
+ })
149
+
150
+ const accessCondition =
151
+ eTag !== '*' && eTag != null && eTag.length > 0
152
+ ? { accessCondition: { type: 'IfMatch', condition: eTag } }
153
+ : undefined
154
+
155
+ try {
156
+ await this.container.items.upsert(document, accessCondition)
157
+ } catch (err: any) {
158
+ this.checkForNestingError(change, err)
159
+ this.throwInformativeError('Error upserting document', err)
160
+ }
161
+ })
162
+ )
163
+ }
164
+
165
+ /**
166
+ * Deletes items from storage.
167
+ * @param keys The keys of the items to delete.
168
+ */
169
+ async delete (keys: string[]): Promise<void> {
170
+ await this.initialize()
171
+
172
+ await Promise.all(
173
+ keys.map(async (k: string): Promise<void> => {
174
+ const escapedKey = CosmosDbKeyEscape.escapeKey(
175
+ k,
176
+ this.cosmosDbStorageOptions.keySuffix,
177
+ this.cosmosDbStorageOptions.compatibilityMode
178
+ )
179
+ try {
180
+ await this.container.item(escapedKey, this.getPartitionKey(escapedKey)).delete()
181
+ } catch (err: any) {
182
+ if (err.code === 404) {
183
+ this.throwInformativeError('Not Found', err)
184
+ } else {
185
+ this.throwInformativeError('Unable to delete document', err)
186
+ }
187
+ }
188
+ })
189
+ )
190
+ }
191
+
192
+ /**
193
+ * Initializes the Cosmos DB container.
194
+ */
195
+ async initialize (): Promise<void> {
196
+ if (!this.container) {
197
+ if (!this.client) {
198
+ this.client = new CosmosClient(this.cosmosDbStorageOptions.cosmosClientOptions!)
199
+ }
200
+ const dbAndContainerKey = `${this.cosmosDbStorageOptions.databaseId}-${this.cosmosDbStorageOptions.containerId}`
201
+ this.container = await _doOnce.waitFor(
202
+ dbAndContainerKey,
203
+ async (): Promise<Container> => await this.getOrCreateContainer()
204
+ )
205
+ }
206
+ }
207
+
208
+ private async getOrCreateContainer (): Promise<Container> {
209
+ let createIfNotExists = !this.cosmosDbStorageOptions.compatibilityMode
210
+ let container: Container | undefined
211
+
212
+ try {
213
+ const { database } = await this.client.databases.createIfNotExists({
214
+ id: this.cosmosDbStorageOptions.databaseId
215
+ })
216
+
217
+ if (this.cosmosDbStorageOptions.compatibilityMode) {
218
+ try {
219
+ container = database.container(this.cosmosDbStorageOptions.containerId)
220
+ // @ts-ignore
221
+ const partitionKeyResponse = await container.readPartitionKeyDefinition()
222
+ if (partitionKeyResponse.resource && partitionKeyResponse.resource.paths) {
223
+ const paths = partitionKeyResponse.resource.paths
224
+ if (paths.includes('/_partitionKey')) {
225
+ this.compatibilityModePartitionKey = true
226
+ } else if (paths.indexOf(DocumentStoreItem.partitionKeyPath) === -1) {
227
+ throw new Error(
228
+ `Custom Partition Key Paths are not supported. ${this.cosmosDbStorageOptions.containerId} has a custom Partition Key Path of ${paths[0]}.`
229
+ )
230
+ }
231
+ } else {
232
+ this.compatibilityModePartitionKey = true
233
+ }
234
+ return container
235
+ } catch {
236
+ createIfNotExists = true
237
+ }
238
+ }
239
+
240
+ if (createIfNotExists) {
241
+ const result = await database.containers.createIfNotExists({
242
+ id: this.cosmosDbStorageOptions.containerId,
243
+ partitionKey: {
244
+ paths: [DocumentStoreItem.partitionKeyPath],
245
+ },
246
+ throughput: this.cosmosDbStorageOptions.containerThroughput,
247
+ })
248
+ return result.container
249
+ }
250
+
251
+ if (!container) {
252
+ throw new Error(`Container ${this.cosmosDbStorageOptions.containerId} not found.`)
253
+ }
254
+ return container
255
+ } catch (err: any) {
256
+ this.throwInformativeError(
257
+ `Failed to initialize Cosmos DB database/container: ${this.cosmosDbStorageOptions.databaseId}/${this.cosmosDbStorageOptions.containerId}`,
258
+ err
259
+ )
260
+ throw err
261
+ }
262
+ }
263
+
264
+ private getPartitionKey (key: string) {
265
+ return this.compatibilityModePartitionKey ? undefined : key
266
+ }
267
+
268
+ private checkForNestingError (json: object, err: Error | Record<'message', string> | string): void {
269
+ const checkDepth = (obj: unknown, depth: number, isInDialogState: boolean): void => {
270
+ if (depth > maxDepthAllowed) {
271
+ let message = `Maximum nesting depth of ${maxDepthAllowed} exceeded.`
272
+
273
+ if (isInDialogState) {
274
+ message +=
275
+ ' This is most likely caused by recursive component dialogs. ' +
276
+ 'Try reworking your dialog code to make sure it does not keep dialogs on the stack ' +
277
+ "that it's not using. For example, consider using replaceDialog instead of beginDialog."
278
+ } else {
279
+ message += ' Please check your data for signs of unintended recursion.'
280
+ }
281
+
282
+ this.throwInformativeError(message, err)
283
+ } else if (obj && typeof obj === 'object') {
284
+ for (const [key, value] of Object.entries(obj)) {
285
+ checkDepth(value, depth + 1, key === 'dialogStack' || isInDialogState)
286
+ }
287
+ }
288
+ }
289
+
290
+ checkDepth(json, 0, false)
291
+ }
292
+
293
+ private throwInformativeError (prependedMessage: string, err: Error | Record<'message', string> | string): void {
294
+ if (typeof err === 'string') {
295
+ err = new Error(err)
296
+ }
297
+
298
+ err.message = `[${prependedMessage}] ${err.message}`
299
+
300
+ throw err
301
+ }
302
+ }
@@ -0,0 +1,36 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ import { CosmosClientOptions } from '@azure/cosmos'
5
+
6
+ /**
7
+ * Options for configuring Cosmos DB partitioned storage.
8
+ */
9
+ export interface CosmosDbPartitionedStorageOptions {
10
+ /**
11
+ * The ID of the database.
12
+ */
13
+ databaseId: string;
14
+ /**
15
+ * The ID of the container.
16
+ */
17
+ containerId: string;
18
+ /**
19
+ * The throughput of the container.
20
+ */
21
+ containerThroughput?: number;
22
+ /**
23
+ * The suffix to append to keys.
24
+ */
25
+ keySuffix?: string;
26
+ /**
27
+ * Indicates whether compatibility mode is enabled.
28
+ */
29
+ compatibilityMode?: boolean;
30
+
31
+ /**
32
+ * The options for the Cosmos client.
33
+ */
34
+ cosmosClientOptions?: CosmosClientOptions;
35
+ // tokenCredential?: TokenCredential;
36
+ }
@@ -0,0 +1,49 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ /**
5
+ * Represents an item stored in the document store.
6
+ */
7
+ export class DocumentStoreItem {
8
+ /**
9
+ * Gets the partition key path.
10
+ */
11
+ static get partitionKeyPath (): string {
12
+ return '/id'
13
+ }
14
+
15
+ /**
16
+ * The ID of the document.
17
+ */
18
+ id: string
19
+ /**
20
+ * The real ID of the document.
21
+ */
22
+ realId: string
23
+ /**
24
+ * The document object.
25
+ */
26
+ document: object
27
+ /**
28
+ * The ETag of the document.
29
+ */
30
+ eTag: string
31
+
32
+ /**
33
+ * Gets the partition key.
34
+ */
35
+ get partitionKey (): string {
36
+ return this.id
37
+ }
38
+
39
+ /**
40
+ * Initializes a new instance of the DocumentStoreItem class.
41
+ * @param storeItem The store item to initialize.
42
+ */
43
+ constructor (storeItem: { id: string; realId: string; document: object; eTag?: string }) {
44
+ this.id = storeItem.id
45
+ this.realId = storeItem.realId || ''
46
+ this.document = storeItem.document || {}
47
+ this.eTag = storeItem.eTag || ''
48
+ }
49
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+
4
+ export * from './cosmosDbPartitionedStorage'
5
+ export * from './cosmosDbPartitionedStorageOptions'