@microsoft/agents-hosting-storage-blob 1.8.1 → 1.9.0-beta.18.g6b8111bba5
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 +15 -5
- package/dist/package.json +4 -4
- package/dist/src/blobsStorage.d.ts +3 -2
- package/dist/src/blobsStorage.js +23 -2
- package/dist/src/blobsStorage.js.map +1 -1
- package/package.json +4 -4
- package/src/blobsStorage.ts +30 -4
package/README.md
CHANGED
|
@@ -18,9 +18,19 @@ const userState = new UserState(blobStorage)
|
|
|
18
18
|
>note: you must assign RBAC permissions to your storage account
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
|
-
const echo = new AgentApplication<TurnState>({
|
|
22
|
-
storage: new BlobsStorage('', undefined, undefined,
|
|
23
|
-
'https://agentsstate.blob.core.windows.net/nodejs-conversations',
|
|
24
|
-
new MsalTokenCredential(loadAuthConfigFromEnv()))
|
|
25
|
-
})
|
|
21
|
+
const echo = new AgentApplication<TurnState>({
|
|
22
|
+
storage: new BlobsStorage('', undefined, undefined,
|
|
23
|
+
'https://agentsstate.blob.core.windows.net/nodejs-conversations',
|
|
24
|
+
new MsalTokenCredential(loadAuthConfigFromEnv()))
|
|
25
|
+
})
|
|
26
26
|
```
|
|
27
|
+
|
|
28
|
+
## TTL writes
|
|
29
|
+
|
|
30
|
+
`BlobsStorage` supports the shared storage TTL option:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
await blobStorage.write({ 'session/123': { value: 'temporary' } }, { ttl: 3600 })
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Expired blobs are omitted from reads and deleted on a best-effort basis when encountered. Physical auto-eviction still depends on Azure Blob lifecycle policies.
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@microsoft/agents-hosting-storage-blob",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.0-beta.18.g6b8111bba5",
|
|
5
5
|
"homepage": "https://github.com/microsoft/Agents-for-js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@azure/core-auth": "1.10.1",
|
|
20
20
|
"@azure/storage-blob": "12.31.0",
|
|
21
|
-
"@microsoft/agents-hosting": "1.
|
|
22
|
-
"@microsoft/agents-activity": "1.
|
|
23
|
-
"@microsoft/agents-telemetry": "1.
|
|
21
|
+
"@microsoft/agents-hosting": "1.9.0-beta.18.g6b8111bba5",
|
|
22
|
+
"@microsoft/agents-activity": "1.9.0-beta.18.g6b8111bba5",
|
|
23
|
+
"@microsoft/agents-telemetry": "1.9.0-beta.18.g6b8111bba5",
|
|
24
24
|
"zod": "3.25.75"
|
|
25
25
|
},
|
|
26
26
|
"license": "MIT",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TokenCredential } from '@azure/core-auth';
|
|
2
2
|
import { AnonymousCredential, StoragePipelineOptions, StorageSharedKeyCredential } from '@azure/storage-blob';
|
|
3
|
-
import { Storage, StoreItems } from '@microsoft/agents-hosting';
|
|
3
|
+
import { Storage, StorageWriteOptions, StoreItems } from '@microsoft/agents-hosting';
|
|
4
4
|
/**
|
|
5
5
|
* Options for configuring the BlobsStorage.
|
|
6
6
|
*/
|
|
@@ -45,7 +45,7 @@ export declare class BlobsStorage implements Storage {
|
|
|
45
45
|
* @returns A promise that resolves when the write operation is complete
|
|
46
46
|
* @throws Will throw if there's a validation error, eTag conflict, or other storage error
|
|
47
47
|
*/
|
|
48
|
-
write(changes: StoreItems): Promise<void>;
|
|
48
|
+
write(changes: StoreItems, options?: StorageWriteOptions): Promise<void>;
|
|
49
49
|
/**
|
|
50
50
|
* Deletes storage items from blob storage.
|
|
51
51
|
*
|
|
@@ -54,4 +54,5 @@ export declare class BlobsStorage implements Storage {
|
|
|
54
54
|
* @throws Will throw if keys parameter is invalid
|
|
55
55
|
*/
|
|
56
56
|
delete(keys: string[]): Promise<void>;
|
|
57
|
+
private isExpired;
|
|
57
58
|
}
|
package/dist/src/blobsStorage.js
CHANGED
|
@@ -41,6 +41,7 @@ const z = __importStar(require("zod"));
|
|
|
41
41
|
const consumers_1 = __importDefault(require("stream/consumers"));
|
|
42
42
|
const core_auth_1 = require("@azure/core-auth");
|
|
43
43
|
const storage_blob_1 = require("@azure/storage-blob");
|
|
44
|
+
const agents_hosting_1 = require("@microsoft/agents-hosting");
|
|
44
45
|
const agents_activity_1 = require("@microsoft/agents-activity");
|
|
45
46
|
const errorHelper_1 = require("./errorHelper");
|
|
46
47
|
const blobsTranscriptStore_1 = require("./blobsTranscriptStore");
|
|
@@ -48,6 +49,7 @@ const ignoreError_1 = require("./ignoreError");
|
|
|
48
49
|
const agents_telemetry_1 = require("@microsoft/agents-telemetry");
|
|
49
50
|
const observability_1 = require("./observability");
|
|
50
51
|
const logger = (0, agents_telemetry_1.debug)('agents:blob-storage');
|
|
52
|
+
const expirationMetadataKey = 'agentsstorageexpiresat';
|
|
51
53
|
/**
|
|
52
54
|
* A class that implements the Storage interface using Azure Blob Storage.
|
|
53
55
|
* Provides persistence for bot state data using Azure's Blob Storage service.
|
|
@@ -120,10 +122,20 @@ class BlobsStorage {
|
|
|
120
122
|
if (!blob) {
|
|
121
123
|
return result;
|
|
122
124
|
}
|
|
123
|
-
const { etag: eTag, readableStreamBody } = blob;
|
|
125
|
+
const { etag: eTag, metadata, readableStreamBody } = blob;
|
|
124
126
|
if (!readableStreamBody) {
|
|
125
127
|
return result;
|
|
126
128
|
}
|
|
129
|
+
if (this.isExpired(metadata === null || metadata === void 0 ? void 0 : metadata[expirationMetadataKey])) {
|
|
130
|
+
readableStreamBody.destroy();
|
|
131
|
+
logger.info('Blob expired, deleting from storage', {
|
|
132
|
+
key: (0, agents_telemetry_1.redactString)(key, true),
|
|
133
|
+
eTag: (0, agents_telemetry_1.redactString)(eTag, true),
|
|
134
|
+
expiresAt: metadata === null || metadata === void 0 ? void 0 : metadata[expirationMetadataKey],
|
|
135
|
+
});
|
|
136
|
+
await (0, ignoreError_1.ignoreError)(this._containerClient.deleteBlob((0, blobsTranscriptStore_1.sanitizeBlobKey)(key), { conditions: { ifMatch: eTag } }), (0, ignoreError_1.isStatusCodeError)(404, 412));
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
127
139
|
const parsed = (await consumers_1.default.json(readableStreamBody));
|
|
128
140
|
result.value = { ...parsed, eTag };
|
|
129
141
|
logger.debug(`Read blob: ${key}, eTag: ${eTag}`);
|
|
@@ -139,9 +151,10 @@ class BlobsStorage {
|
|
|
139
151
|
* @returns A promise that resolves when the write operation is complete
|
|
140
152
|
* @throws Will throw if there's a validation error, eTag conflict, or other storage error
|
|
141
153
|
*/
|
|
142
|
-
async write(changes) {
|
|
154
|
+
async write(changes, options) {
|
|
143
155
|
return (0, agents_telemetry_1.trace)(observability_1.BlobsStorageTraceDefinitions.write, async ({ record }) => {
|
|
144
156
|
z.record(z.unknown()).parse(changes);
|
|
157
|
+
const expiresAt = (0, agents_hosting_1.getStorageWriteExpiry)(options);
|
|
145
158
|
record({ keyCount: Object.keys(changes).length });
|
|
146
159
|
await this._initialize();
|
|
147
160
|
await Promise.all(Object.entries(changes).map(async ([key, { eTag = '', ...change }]) => {
|
|
@@ -152,6 +165,7 @@ class BlobsStorage {
|
|
|
152
165
|
return await blob.upload(serialized, serialized.length, {
|
|
153
166
|
conditions: typeof eTag === 'string' && eTag !== '*' ? { ifMatch: eTag } : {},
|
|
154
167
|
blobHTTPHeaders: { blobContentType: 'application/json' },
|
|
168
|
+
metadata: expiresAt === undefined ? {} : { [expirationMetadataKey]: expiresAt.toString() },
|
|
155
169
|
});
|
|
156
170
|
}
|
|
157
171
|
catch (err) {
|
|
@@ -181,6 +195,13 @@ class BlobsStorage {
|
|
|
181
195
|
await Promise.all(keys.map((key) => (0, ignoreError_1.ignoreError)(this._containerClient.deleteBlob((0, blobsTranscriptStore_1.sanitizeBlobKey)(key)), (0, ignoreError_1.isStatusCodeError)(404))));
|
|
182
196
|
});
|
|
183
197
|
}
|
|
198
|
+
isExpired(expiresAt) {
|
|
199
|
+
if (expiresAt === undefined) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const timestamp = Number(expiresAt);
|
|
203
|
+
return Number.isFinite(timestamp) && timestamp <= Date.now();
|
|
204
|
+
}
|
|
184
205
|
}
|
|
185
206
|
exports.BlobsStorage = BlobsStorage;
|
|
186
207
|
//# sourceMappingURL=blobsStorage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blobsStorage.js","sourceRoot":"","sources":["../../src/blobsStorage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,MAAY,CAAC,gCAAW;AACxB,iEAA8C;AAC9C,gDAAqE;AACrE,sDAK4B;
|
|
1
|
+
{"version":3,"file":"blobsStorage.js","sourceRoot":"","sources":["../../src/blobsStorage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,MAAY,CAAC,gCAAW;AACxB,iEAA8C;AAC9C,gDAAqE;AACrE,sDAK4B;AAC5B,8DAA2G;AAC3G,gEAA4D;AAC5D,+CAAsC;AACtC,iEAAwD;AACxD,+CAA8D;AAC9D,kEAAwE;AACxE,mDAA8D;AAE9D,MAAM,MAAM,GAAG,IAAA,wBAAK,EAAC,qBAAqB,CAAC,CAAA;AAC3C,MAAM,qBAAqB,GAAG,wBAAwB,CAAA;AAYtD;;;GAGG;AACH;IAKE;;;;;;;;OAQG;IACH,YACE,aAAqB,EACrB,gBAAyB,EACzB,OAA6B,EAC7B,GAAG,GAAG,EAAE,EACR,UAA+E;QAjBhE,iBAAY,GAAG,QAAQ,CAAA;QAmBtC,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACtB,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC;gBAClC,GAAG;aACJ,CAAC,CAAA;YAEF,IAAI,CAAC,gBAAgB,GAAG,IAAI,8BAAe,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,sBAAsB,CAAC,CAAA;YAE7F,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,6BAA6B,EAAE,CAAC;gBACjD,IAAI,CAAC,YAAY,GAAG,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,CAAC,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC;gBAC1E,gBAAgB;gBAChB,aAAa;aACd,CAAC,CAAA;YAEF,IAAI,CAAC,gBAAgB,GAAG,IAAI,8BAAe,CACzC,gBAAiB,EACjB,aAAa,EACb,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,sBAAsB,CAChC,CAAA;YAED,IAAI,gBAAiB,CAAC,IAAI,EAAE,KAAK,6BAA6B,EAAE,CAAC;gBAC/D,IAAI,CAAC,YAAY,GAAG,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE;YAC1C,SAAS,EAAE,aAAa;YACxB,UAAU,EAAE;gBACV,IAAI,EAAE,IAAA,6BAAiB,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB;gBACxG,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAiB,CAAC,CAAC,IAAI,EAAE,KAAK,6BAA6B,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY;aAC5H;YACD,QAAQ,EAAE,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,sBAAsB,MAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;SAC/E,CAAC,CAAA;IACJ,CAAC;IAEO,MAAM;QACZ,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAA;IACjC,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAA;QACrE,CAAC;QACD,OAAO,IAAI,CAAC,kBAAkB,CAAA;IAChC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,CAAE,IAAc;QACxB,OAAO,IAAA,wBAAK,EAAC,4CAA4B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;;YACnE,MAAM,CAAC,EAAE,QAAQ,QAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,mCAAI,CAAC,EAAE,CAAC,CAAA;YACvC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YAEvD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;YAExB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACvD,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;gBAExC,MAAM,IAAI,GAAG,MAAM,IAAA,yBAAW,EAC5B,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAA,sCAAe,EAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,EACpE,IAAA,+BAAiB,EAAC,GAAG,CAAC,CACvB,CAAA;gBAED,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,OAAO,MAAM,CAAA;gBACf,CAAC;gBAED,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAA;gBACzD,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACxB,OAAO,MAAM,CAAA;gBACf,CAAC;gBAED,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,qBAAqB,CAAC,CAAC,EAAE,CAAC;oBACtD,kBAAkB,CAAC,OAAO,EAAE,CAAA;oBAC5B,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE;wBACjD,GAAG,EAAE,IAAA,+BAAY,EAAC,GAAG,EAAE,IAAI,CAAC;wBAC5B,IAAI,EAAE,IAAA,+BAAY,EAAC,IAAI,EAAE,IAAI,CAAC;wBAC9B,SAAS,EAAE,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,qBAAqB,CAAC;qBAC7C,CAAC,CAAA;oBACF,MAAM,IAAA,yBAAW,EACf,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAA,sCAAe,EAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,EACzF,IAAA,+BAAiB,EAAC,GAAG,EAAE,GAAG,CAAC,CAC5B,CAAA;oBACD,OAAO,MAAM,CAAA;gBACf,CAAC;gBAED,MAAM,MAAM,GAAG,CAAC,MAAM,mBAAe,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAQ,CAAA;gBACtE,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,CAAA;gBAClC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,WAAW,IAAI,EAAE,CAAC,CAAA;gBAChD,OAAO,MAAM,CAAA;YACf,CAAC,CAAC,CAAC,CAAA;YAEH,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAA;QAC9F,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CAAE,OAAmB,EAAE,OAA6B;QAC7D,OAAO,IAAA,wBAAK,EAAC,4CAA4B,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACpE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACpC,MAAM,SAAS,GAAG,IAAA,sCAAqB,EAAC,OAAO,CAAC,CAAA;YAChD,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAA;YAEjD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;YAExB,MAAM,OAAO,CAAC,GAAG,CACf,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpE,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAA,sCAAe,EAAC,GAAG,CAAC,CAAC,CAAA;oBAC3E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;oBACzC,MAAM,CAAC,KAAK,CAAC,iBAAiB,GAAG,WAAW,IAAI,WAAW,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;oBAC/E,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE;wBACtD,UAAU,EAAE,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;wBAC7E,eAAe,EAAE,EAAE,eAAe,EAAE,kBAAkB,EAAE;wBACxD,QAAQ,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,qBAAqB,CAAC,EAAE,SAAS,CAAC,QAAQ,EAAE,EAAE;qBAC3F,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;wBAC3B,MAAM,iCAAe,CAAC,iBAAiB,CAAC,KAAK,EAAE,oBAAM,CAAC,YAAY,CAAC,CAAA;oBACrE,CAAC;yBAAM,CAAC;wBACN,MAAM,GAAG,CAAA;oBACX,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CACH,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAE,IAAc;QAC1B,OAAO,IAAA,wBAAK,EAAC,4CAA4B,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;;YACrE,MAAM,CAAC,EAAE,QAAQ,QAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,mCAAI,CAAC,EAAE,CAAC,CAAA;YACvC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YAEvD,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;YAExB,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,yBAAW,EAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAA,sCAAe,EAAC,GAAG,CAAC,CAAC,EAAE,IAAA,+BAAiB,EAAC,GAAG,CAAC,CAAC,CAAC,CAC/G,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAEO,SAAS,CAAE,SAAkB;QACnC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;QACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA;IAC9D,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@microsoft/agents-hosting-storage-blob",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.0-beta.18.g6b8111bba5",
|
|
5
5
|
"homepage": "https://github.com/microsoft/Agents-for-js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@azure/core-auth": "1.10.1",
|
|
20
20
|
"@azure/storage-blob": "12.31.0",
|
|
21
|
-
"@microsoft/agents-hosting": "1.
|
|
22
|
-
"@microsoft/agents-activity": "1.
|
|
23
|
-
"@microsoft/agents-telemetry": "1.
|
|
21
|
+
"@microsoft/agents-hosting": "1.9.0-beta.18.g6b8111bba5",
|
|
22
|
+
"@microsoft/agents-activity": "1.9.0-beta.18.g6b8111bba5",
|
|
23
|
+
"@microsoft/agents-telemetry": "1.9.0-beta.18.g6b8111bba5",
|
|
24
24
|
"zod": "3.25.75"
|
|
25
25
|
},
|
|
26
26
|
"license": "MIT",
|
package/src/blobsStorage.ts
CHANGED
|
@@ -7,15 +7,16 @@ import {
|
|
|
7
7
|
StoragePipelineOptions,
|
|
8
8
|
StorageSharedKeyCredential,
|
|
9
9
|
} from '@azure/storage-blob'
|
|
10
|
-
import { Storage, StoreItems } from '@microsoft/agents-hosting'
|
|
10
|
+
import { getStorageWriteExpiry, Storage, StorageWriteOptions, StoreItems } from '@microsoft/agents-hosting'
|
|
11
11
|
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
12
12
|
import { Errors } from './errorHelper'
|
|
13
13
|
import { sanitizeBlobKey } from './blobsTranscriptStore'
|
|
14
14
|
import { ignoreError, isStatusCodeError } from './ignoreError'
|
|
15
|
-
import { trace, debug } from '@microsoft/agents-telemetry'
|
|
15
|
+
import { trace, debug, redactString } from '@microsoft/agents-telemetry'
|
|
16
16
|
import { BlobsStorageTraceDefinitions } from './observability'
|
|
17
17
|
|
|
18
18
|
const logger = debug('agents:blob-storage')
|
|
19
|
+
const expirationMetadataKey = 'agentsstorageexpiresat'
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Options for configuring the BlobsStorage.
|
|
@@ -125,11 +126,25 @@ export class BlobsStorage implements Storage {
|
|
|
125
126
|
return result
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
const { etag: eTag, readableStreamBody } = blob
|
|
129
|
+
const { etag: eTag, metadata, readableStreamBody } = blob
|
|
129
130
|
if (!readableStreamBody) {
|
|
130
131
|
return result
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
if (this.isExpired(metadata?.[expirationMetadataKey])) {
|
|
135
|
+
readableStreamBody.destroy()
|
|
136
|
+
logger.info('Blob expired, deleting from storage', {
|
|
137
|
+
key: redactString(key, true),
|
|
138
|
+
eTag: redactString(eTag, true),
|
|
139
|
+
expiresAt: metadata?.[expirationMetadataKey],
|
|
140
|
+
})
|
|
141
|
+
await ignoreError(
|
|
142
|
+
this._containerClient.deleteBlob(sanitizeBlobKey(key), { conditions: { ifMatch: eTag } }),
|
|
143
|
+
isStatusCodeError(404, 412)
|
|
144
|
+
)
|
|
145
|
+
return result
|
|
146
|
+
}
|
|
147
|
+
|
|
133
148
|
const parsed = (await StreamConsumers.json(readableStreamBody)) as any
|
|
134
149
|
result.value = { ...parsed, eTag }
|
|
135
150
|
logger.debug(`Read blob: ${key}, eTag: ${eTag}`)
|
|
@@ -147,9 +162,10 @@ export class BlobsStorage implements Storage {
|
|
|
147
162
|
* @returns A promise that resolves when the write operation is complete
|
|
148
163
|
* @throws Will throw if there's a validation error, eTag conflict, or other storage error
|
|
149
164
|
*/
|
|
150
|
-
async write (changes: StoreItems): Promise<void> {
|
|
165
|
+
async write (changes: StoreItems, options?: StorageWriteOptions): Promise<void> {
|
|
151
166
|
return trace(BlobsStorageTraceDefinitions.write, async ({ record }) => {
|
|
152
167
|
z.record(z.unknown()).parse(changes)
|
|
168
|
+
const expiresAt = getStorageWriteExpiry(options)
|
|
153
169
|
record({ keyCount: Object.keys(changes).length })
|
|
154
170
|
|
|
155
171
|
await this._initialize()
|
|
@@ -163,6 +179,7 @@ export class BlobsStorage implements Storage {
|
|
|
163
179
|
return await blob.upload(serialized, serialized.length, {
|
|
164
180
|
conditions: typeof eTag === 'string' && eTag !== '*' ? { ifMatch: eTag } : {},
|
|
165
181
|
blobHTTPHeaders: { blobContentType: 'application/json' },
|
|
182
|
+
metadata: expiresAt === undefined ? {} : { [expirationMetadataKey]: expiresAt.toString() },
|
|
166
183
|
})
|
|
167
184
|
} catch (err: any) {
|
|
168
185
|
if (err.statusCode === 412) {
|
|
@@ -195,4 +212,13 @@ export class BlobsStorage implements Storage {
|
|
|
195
212
|
)
|
|
196
213
|
})
|
|
197
214
|
}
|
|
215
|
+
|
|
216
|
+
private isExpired (expiresAt?: string): boolean {
|
|
217
|
+
if (expiresAt === undefined) {
|
|
218
|
+
return false
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const timestamp = Number(expiresAt)
|
|
222
|
+
return Number.isFinite(timestamp) && timestamp <= Date.now()
|
|
223
|
+
}
|
|
198
224
|
}
|