@azure/storage-blob-changefeed 12.0.0-alpha.20250617.1 → 12.0.0-alpha.20250718.2
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/dist/browser/BlobChangeFeedClient.js +49 -40
- package/dist/browser/BlobChangeFeedClient.js.map +1 -1
- package/dist/browser/ChangeFeed.js +13 -2
- package/dist/browser/ChangeFeed.js.map +1 -1
- package/dist/browser/ChangeFeedFactory.js +3 -1
- package/dist/browser/ChangeFeedFactory.js.map +1 -1
- package/dist/browser/Chunk.js +5 -0
- package/dist/browser/Chunk.js.map +1 -1
- package/dist/browser/ChunkFactory.js +3 -0
- package/dist/browser/ChunkFactory.js.map +1 -1
- package/dist/browser/LazyLoadingBlobStream.js +19 -8
- package/dist/browser/LazyLoadingBlobStream.js.map +1 -1
- package/dist/browser/Segment.js +9 -0
- package/dist/browser/Segment.js.map +1 -1
- package/dist/browser/SegmentFactory.js +4 -3
- package/dist/browser/SegmentFactory.js.map +1 -1
- package/dist/browser/Shard.js +5 -0
- package/dist/browser/Shard.js.map +1 -1
- package/dist/browser/ShardFactory.js +10 -23
- package/dist/browser/ShardFactory.js.map +1 -1
- package/dist/browser/utils/utils.common.js +17 -44
- package/dist/browser/utils/utils.common.js.map +1 -1
- package/dist/commonjs/BlobChangeFeedClient.js +49 -40
- package/dist/commonjs/BlobChangeFeedClient.js.map +1 -1
- package/dist/commonjs/ChangeFeed.js +13 -2
- package/dist/commonjs/ChangeFeed.js.map +1 -1
- package/dist/commonjs/ChangeFeedFactory.js +3 -1
- package/dist/commonjs/ChangeFeedFactory.js.map +1 -1
- package/dist/commonjs/Chunk.js +5 -0
- package/dist/commonjs/Chunk.js.map +1 -1
- package/dist/commonjs/ChunkFactory.js +3 -0
- package/dist/commonjs/ChunkFactory.js.map +1 -1
- package/dist/commonjs/LazyLoadingBlobStream.js +19 -8
- package/dist/commonjs/LazyLoadingBlobStream.js.map +1 -1
- package/dist/commonjs/Segment.js +9 -0
- package/dist/commonjs/Segment.js.map +1 -1
- package/dist/commonjs/SegmentFactory.js +4 -3
- package/dist/commonjs/SegmentFactory.js.map +1 -1
- package/dist/commonjs/Shard.js +5 -0
- package/dist/commonjs/Shard.js.map +1 -1
- package/dist/commonjs/ShardFactory.js +10 -23
- package/dist/commonjs/ShardFactory.js.map +1 -1
- package/dist/commonjs/tsdoc-metadata.json +11 -11
- package/dist/commonjs/utils/utils.common.js +17 -44
- package/dist/commonjs/utils/utils.common.js.map +1 -1
- package/dist/esm/BlobChangeFeedClient.js +49 -40
- package/dist/esm/BlobChangeFeedClient.js.map +1 -1
- package/dist/esm/ChangeFeed.js +13 -2
- package/dist/esm/ChangeFeed.js.map +1 -1
- package/dist/esm/ChangeFeedFactory.js +3 -1
- package/dist/esm/ChangeFeedFactory.js.map +1 -1
- package/dist/esm/Chunk.js +5 -0
- package/dist/esm/Chunk.js.map +1 -1
- package/dist/esm/ChunkFactory.js +3 -0
- package/dist/esm/ChunkFactory.js.map +1 -1
- package/dist/esm/LazyLoadingBlobStream.js +19 -8
- package/dist/esm/LazyLoadingBlobStream.js.map +1 -1
- package/dist/esm/Segment.js +9 -0
- package/dist/esm/Segment.js.map +1 -1
- package/dist/esm/SegmentFactory.js +4 -3
- package/dist/esm/SegmentFactory.js.map +1 -1
- package/dist/esm/Shard.js +5 -0
- package/dist/esm/Shard.js.map +1 -1
- package/dist/esm/ShardFactory.js +10 -23
- package/dist/esm/ShardFactory.js.map +1 -1
- package/dist/esm/utils/utils.common.js +17 -44
- package/dist/esm/utils/utils.common.js.map +1 -1
- package/dist/react-native/BlobChangeFeedClient.js +49 -40
- package/dist/react-native/BlobChangeFeedClient.js.map +1 -1
- package/dist/react-native/ChangeFeed.js +13 -2
- package/dist/react-native/ChangeFeed.js.map +1 -1
- package/dist/react-native/ChangeFeedFactory.js +3 -1
- package/dist/react-native/ChangeFeedFactory.js.map +1 -1
- package/dist/react-native/Chunk.js +5 -0
- package/dist/react-native/Chunk.js.map +1 -1
- package/dist/react-native/ChunkFactory.js +3 -0
- package/dist/react-native/ChunkFactory.js.map +1 -1
- package/dist/react-native/LazyLoadingBlobStream.js +19 -8
- package/dist/react-native/LazyLoadingBlobStream.js.map +1 -1
- package/dist/react-native/Segment.js +9 -0
- package/dist/react-native/Segment.js.map +1 -1
- package/dist/react-native/SegmentFactory.js +4 -3
- package/dist/react-native/SegmentFactory.js.map +1 -1
- package/dist/react-native/Shard.js +5 -0
- package/dist/react-native/Shard.js.map +1 -1
- package/dist/react-native/ShardFactory.js +10 -23
- package/dist/react-native/ShardFactory.js.map +1 -1
- package/dist/react-native/utils/utils.common.js +17 -44
- package/dist/react-native/utils/utils.common.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
|
-
import { __asyncGenerator, __await } from "tslib";
|
|
4
3
|
import { BlobServiceClient, Pipeline } from "@azure/storage-blob";
|
|
5
4
|
import { ChangeFeedFactory } from "./ChangeFeedFactory.js";
|
|
6
5
|
import { CHANGE_FEED_MAX_PAGE_SIZE, SDK_VERSION } from "./utils/constants.js";
|
|
@@ -8,6 +7,14 @@ import { CHANGE_FEED_MAX_PAGE_SIZE, SDK_VERSION } from "./utils/constants.js";
|
|
|
8
7
|
* Contains paged response data for the {@link BlobChangeFeedClient.listChanges} operation.
|
|
9
8
|
*/
|
|
10
9
|
export class BlobChangeFeedEventPage {
|
|
10
|
+
/**
|
|
11
|
+
* Array of {@link BlobChangeFeedEvent}.
|
|
12
|
+
*/
|
|
13
|
+
events;
|
|
14
|
+
/**
|
|
15
|
+
* The token that keeps track of where to continue the iterator.
|
|
16
|
+
*/
|
|
17
|
+
continuationToken;
|
|
11
18
|
constructor() {
|
|
12
19
|
this.events = [];
|
|
13
20
|
this.continuationToken = "";
|
|
@@ -44,6 +51,12 @@ function appendUserAgentPrefix(options) {
|
|
|
44
51
|
* @see https://learn.microsoft.com/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal
|
|
45
52
|
*/
|
|
46
53
|
export class BlobChangeFeedClient {
|
|
54
|
+
/**
|
|
55
|
+
* blobServiceClient provided by `@azure/storage-blob` package.
|
|
56
|
+
*/
|
|
57
|
+
blobServiceClient;
|
|
58
|
+
changeFeedFactory;
|
|
59
|
+
changeFeedClientOptions;
|
|
47
60
|
/**
|
|
48
61
|
*
|
|
49
62
|
* Creates an instance of BlobChangeFeedClient from connection string.
|
|
@@ -79,52 +92,48 @@ export class BlobChangeFeedClient {
|
|
|
79
92
|
this.blobServiceClient = new BlobServiceClient(urlOrClient, credentialOrPipeline, appendUserAgentPrefix(options));
|
|
80
93
|
}
|
|
81
94
|
}
|
|
82
|
-
getChange() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
async *getChange(options = {}) {
|
|
96
|
+
const changeFeed = await this.changeFeedFactory.create(this.blobServiceClient, undefined, options);
|
|
97
|
+
while (changeFeed.hasNext()) {
|
|
98
|
+
const event = await changeFeed.getChange({
|
|
99
|
+
abortSignal: options.abortSignal,
|
|
100
|
+
tracingOptions: options.tracingOptions,
|
|
101
|
+
});
|
|
102
|
+
if (event) {
|
|
103
|
+
yield event;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// start in ChangeFeedListChangesOptions will be ignored when continuationToken is specified.
|
|
111
|
+
async *getPage(continuationToken, maxPageSize, options = {}) {
|
|
112
|
+
const changeFeed = await this.changeFeedFactory.create(this.blobServiceClient, continuationToken, options);
|
|
113
|
+
if (!maxPageSize || maxPageSize > CHANGE_FEED_MAX_PAGE_SIZE) {
|
|
114
|
+
maxPageSize = CHANGE_FEED_MAX_PAGE_SIZE;
|
|
115
|
+
}
|
|
116
|
+
while (changeFeed.hasNext()) {
|
|
117
|
+
const eventPage = new BlobChangeFeedEventPage();
|
|
118
|
+
while (changeFeed.hasNext() && eventPage.events.length < maxPageSize) {
|
|
119
|
+
const event = await changeFeed.getChange({
|
|
87
120
|
abortSignal: options.abortSignal,
|
|
88
121
|
tracingOptions: options.tracingOptions,
|
|
89
|
-
})
|
|
122
|
+
});
|
|
90
123
|
if (event) {
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
return yield __await(void 0);
|
|
124
|
+
eventPage.events.push(event);
|
|
95
125
|
}
|
|
96
126
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// start in ChangeFeedListChangesOptions will be ignored when continuationToken is specified.
|
|
100
|
-
getPage(continuationToken_1, maxPageSize_1) {
|
|
101
|
-
return __asyncGenerator(this, arguments, function* getPage_1(continuationToken, maxPageSize, options = {}) {
|
|
102
|
-
const changeFeed = yield __await(this.changeFeedFactory.create(this.blobServiceClient, continuationToken, options));
|
|
103
|
-
if (!maxPageSize || maxPageSize > CHANGE_FEED_MAX_PAGE_SIZE) {
|
|
104
|
-
maxPageSize = CHANGE_FEED_MAX_PAGE_SIZE;
|
|
127
|
+
if (changeFeed.hasNext()) {
|
|
128
|
+
eventPage.continuationToken = JSON.stringify(changeFeed.getCursor());
|
|
105
129
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
while (changeFeed.hasNext() && eventPage.events.length < maxPageSize) {
|
|
109
|
-
const event = yield __await(changeFeed.getChange({
|
|
110
|
-
abortSignal: options.abortSignal,
|
|
111
|
-
tracingOptions: options.tracingOptions,
|
|
112
|
-
}));
|
|
113
|
-
if (event) {
|
|
114
|
-
eventPage.events.push(event);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (changeFeed.hasNext()) {
|
|
118
|
-
eventPage.continuationToken = JSON.stringify(changeFeed.getCursor());
|
|
119
|
-
}
|
|
120
|
-
if (eventPage.events.length > 0) {
|
|
121
|
-
yield yield __await(eventPage);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
return yield __await(void 0);
|
|
125
|
-
}
|
|
130
|
+
if (eventPage.events.length > 0) {
|
|
131
|
+
yield eventPage;
|
|
126
132
|
}
|
|
127
|
-
|
|
133
|
+
else {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
128
137
|
}
|
|
129
138
|
/**
|
|
130
139
|
* Returns an async iterable iterator to list all the change feed events
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlobChangeFeedClient.js","sourceRoot":"","sources":["../../src/BlobChangeFeedClient.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type {\n StoragePipelineOptions,\n StorageSharedKeyCredential,\n AnonymousCredential,\n} from \"@azure/storage-blob\";\nimport { BlobServiceClient, Pipeline } from \"@azure/storage-blob\";\nimport type { PagedAsyncIterableIterator, PageSettings } from \"@azure/core-paging\";\nimport type { BlobChangeFeedEvent } from \"./models/BlobChangeFeedEvent.js\";\nimport { ChangeFeedFactory } from \"./ChangeFeedFactory.js\";\nimport type { ChangeFeed } from \"./ChangeFeed.js\";\nimport { CHANGE_FEED_MAX_PAGE_SIZE, SDK_VERSION } from \"./utils/constants.js\";\nimport type { BlobChangeFeedListChangesOptions } from \"./models/models.js\";\nimport type { TokenCredential } from \"@azure/core-auth\";\n\n/**\n * Contains paged response data for the {@link BlobChangeFeedClient.listChanges} operation.\n */\nexport class BlobChangeFeedEventPage {\n /**\n * Array of {@link BlobChangeFeedEvent}.\n */\n public events: BlobChangeFeedEvent[];\n\n /**\n * The token that keeps track of where to continue the iterator.\n */\n public continuationToken: string;\n\n constructor() {\n this.events = [];\n this.continuationToken = \"\";\n }\n}\n\n/**\n * Creates a new Pipeline object with Credential provided.\n *\n * @param credential - Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used.\n * @param pipelineOptions - Optional. Options.\n * @returns A new Pipeline object.\n */\nexport function newPipeline(\n credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential,\n pipelineOptions: StoragePipelineOptions = {},\n): Pipeline {\n return newPipeline(credential, appendUserAgentPrefix(pipelineOptions));\n}\n\nfunction appendUserAgentPrefix(options?: StoragePipelineOptions): StoragePipelineOptions {\n if (!options) {\n options = {};\n }\n if (options.userAgentOptions === undefined) {\n options.userAgentOptions = {};\n }\n\n if (options.userAgentOptions.userAgentPrefix === undefined) {\n options.userAgentOptions.userAgentPrefix = \"\";\n } else if (options.userAgentOptions.userAgentPrefix !== \"\") {\n options.userAgentOptions.userAgentPrefix += \" \";\n }\n options.userAgentOptions.userAgentPrefix += `changefeed-js/${SDK_VERSION}`;\n return options;\n}\n\n/**\n * Blob Change Feed client options.\n */\nexport interface BlobChangeFeedClientOptions {\n /**\n * The maximum length of an transfer in bytes.\n */\n maximumTransferSize?: number;\n}\n\n/**\n * BlobChangeFeedClient.\n * @see https://learn.microsoft.com/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal\n */\nexport class BlobChangeFeedClient {\n /**\n * blobServiceClient provided by `@azure/storage-blob` package.\n */\n private blobServiceClient: BlobServiceClient;\n private changeFeedFactory: ChangeFeedFactory;\n private changeFeedClientOptions: BlobChangeFeedClientOptions;\n\n /**\n *\n * Creates an instance of BlobChangeFeedClient from connection string.\n *\n * @param connectionString - Account connection string or a SAS connection string of an Azure storage account.\n * [ Note - Account connection string can only be used in NODE.JS runtime. ]\n * Account connection string example -\n * `DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=accountKey;EndpointSuffix=core.windows.net`\n * SAS connection string example -\n * `BlobEndpoint=https://myaccount.blob.core.windows.net/;QueueEndpoint=https://myaccount.queue.core.windows.net/;FileEndpoint=https://myaccount.file.core.windows.net/;TableEndpoint=https://myaccount.table.core.windows.net/;SharedAccessSignature=sasString`\n * @param options - Optional. Options to configure the HTTP pipeline.\n */\n public static fromConnectionString(\n connectionString: string,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n // Static method to construct an object, the option is for the object not for the method.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n ): BlobChangeFeedClient {\n const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString, options);\n return new BlobChangeFeedClient(\n blobServiceClient.url,\n blobServiceClient.credential,\n appendUserAgentPrefix(options),\n changeFeedClientOptions,\n );\n }\n\n /**\n * Creates an instance of BlobChangeFeedClient.\n *\n * @param url - A Client string pointing to Azure Storage blob service, such as\n * \"https://myaccount.blob.core.windows.net\". You can append a SAS\n * if using AnonymousCredential, such as \"https://myaccount.blob.core.windows.net?sasString\".\n * @param credential - Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used.\n * @param options - Optional. Options to configure the HTTP pipeline.\n *\n * Example using DefaultAzureCredential from `@azure/identity`:\n *\n * ```ts snippet:ReadmeSampleCreateClient_TokenCredential\n * import { DefaultAzureCredential } from \"@azure/identity\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * // Enter your storage account name and shared key\n * const account = \"<account>\";\n * const credential = new DefaultAzureCredential();\n * const changeFeedClient = new BlobChangeFeedClient(\n * // When using AnonymousCredential, following url should include a valid SAS or support public access\n * `https://${account}.blob.core.windows.net`,\n * credential,\n * );\n * ```\n *\n * Example using an account name/key:\n *\n * ```ts snippet:ReadmeSampleCreateClient\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * // Enter your storage account name and shared key\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * // Use StorageSharedKeyCredential with storage account and account key\n * // StorageSharedKeyCredential is only available in Node.js runtime, not in browsers\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * // When using AnonymousCredential, following url should include a valid SAS or support public access\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n * ```\n */\n constructor(\n url: string,\n credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n );\n\n /**\n * Creates an instance of BlobChangeFeedClient.\n *\n * @param url - A Client string pointing to Azure Storage blob service, such as\n * \"https://myaccount.blob.core.windows.net\". You can append a SAS\n * if using AnonymousCredential, such as \"https://myaccount.blob.core.windows.net?sasString\".\n * @param pipeline - Call newPipeline() to create a default\n * pipeline, or provide a customized pipeline.\n */\n constructor(url: string, pipeline: Pipeline);\n constructor(\n urlOrClient: string,\n credentialOrPipeline?:\n | StorageSharedKeyCredential\n | AnonymousCredential\n | TokenCredential\n | Pipeline,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n ) {\n this.changeFeedClientOptions = changeFeedClientOptions || {};\n this.changeFeedFactory = new ChangeFeedFactory(\n this.changeFeedClientOptions.maximumTransferSize,\n );\n\n if (credentialOrPipeline instanceof Pipeline) {\n this.blobServiceClient = new BlobServiceClient(urlOrClient, credentialOrPipeline);\n } else {\n this.blobServiceClient = new BlobServiceClient(\n urlOrClient,\n credentialOrPipeline,\n appendUserAgentPrefix(options),\n );\n }\n }\n\n private async *getChange(\n options: BlobChangeFeedListChangesOptions = {},\n ): AsyncIterableIterator<BlobChangeFeedEvent> {\n const changeFeed: ChangeFeed = await this.changeFeedFactory.create(\n this.blobServiceClient,\n undefined,\n options,\n );\n\n while (changeFeed.hasNext()) {\n const event = await changeFeed.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: options.tracingOptions,\n });\n if (event) {\n yield event;\n } else {\n return;\n }\n }\n }\n\n // start in ChangeFeedListChangesOptions will be ignored when continuationToken is specified.\n private async *getPage(\n continuationToken?: string,\n maxPageSize?: number,\n options: BlobChangeFeedListChangesOptions = {},\n ): AsyncIterableIterator<BlobChangeFeedEventPage> {\n const changeFeed: ChangeFeed = await this.changeFeedFactory.create(\n this.blobServiceClient,\n continuationToken,\n options,\n );\n\n if (!maxPageSize || maxPageSize > CHANGE_FEED_MAX_PAGE_SIZE) {\n maxPageSize = CHANGE_FEED_MAX_PAGE_SIZE;\n }\n while (changeFeed.hasNext()) {\n const eventPage = new BlobChangeFeedEventPage();\n while (changeFeed.hasNext() && eventPage.events.length < maxPageSize) {\n const event = await changeFeed.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: options.tracingOptions,\n });\n if (event) {\n eventPage.events.push(event);\n }\n }\n if (changeFeed.hasNext()) {\n eventPage.continuationToken = JSON.stringify(changeFeed.getCursor());\n }\n if (eventPage.events.length > 0) {\n yield eventPage;\n } else {\n return;\n }\n }\n }\n\n /**\n * Returns an async iterable iterator to list all the change feed events\n * in the specified account.\n *\n * .byPage() returns an async iterable iterator to list the change feed events in pages.\n *\n * Example using `for await` syntax:\n *\n * ```ts snippet:ReadmeSampleListChanges\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n *\n * // Use for await to iterate through the change feed\n * for await (const event of changeFeedClient.listChanges()) {\n * console.log(`Event: ${event.eventType}`);\n * console.log(`Event time: ${event.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(event.data)}`);\n * }\n *\n * // Use `byPage` to iterate through the change feed\n * for await (const page of changeFeedClient.listChanges().byPage()) {\n * console.log(`Page: ${JSON.stringify(page)}`);\n * for (const event of page.events) {\n * console.log(`Event: ${event.eventType}`);\n * console.log(`Event time: ${event.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(event.data)}`);\n * }\n * }\n * ```\n *\n * Example using paging with a marker:\n *\n * ```ts snippet:ReadmeSampleListChanges_Continuation\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n *\n * let iterator = changeFeedClient.listChanges().byPage({ maxPageSize: 2 });\n * let response = (await iterator.next()).value;\n * // Prints 2 page ranges\n * if (response.pageRange) {\n * for (const pageRange of response.pageRange) {\n * console.log(`Event: ${pageRange.eventType}`);\n * console.log(`Event time: ${pageRange.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(pageRange.data)}`);\n * }\n * }\n * // Gets next marker\n * let marker = response.continuationToken;\n * // Passing next marker as continuationToken\n * iterator = changeFeedClient.listChanges().byPage({ continuationToken: marker, maxPageSize: 10 });\n * response = (await iterator.next()).value;\n * // Prints 10 page ranges\n * if (response.pageRange) {\n * for (const pageRange of response.pageRange) {\n * console.log(`Event: ${pageRange.eventType}`);\n * console.log(`Event time: ${pageRange.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(pageRange.data)}`);\n * }\n * }\n * ```\n *\n * @param options - Options to list change feed events.\n * @returns An asyncIterableIterator that supports paging.\n */\n public listChanges(\n options: BlobChangeFeedListChangesOptions = {},\n ): PagedAsyncIterableIterator<BlobChangeFeedEvent, BlobChangeFeedEventPage> {\n const iter = this.getChange(options);\n return {\n /**\n * The next method, part of the iteration protocol\n */\n async next() {\n return iter.next();\n },\n /**\n * The connection to the async iterator, part of the iteration protocol\n */\n [Symbol.asyncIterator]() {\n return this;\n },\n /**\n * Return an AsyncIterableIterator that works a page at a time\n */\n byPage: (settings: PageSettings = {}) => {\n return this.getPage(settings.continuationToken, settings.maxPageSize, options);\n },\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"BlobChangeFeedClient.js","sourceRoot":"","sources":["../../src/BlobChangeFeedClient.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type {\n StoragePipelineOptions,\n StorageSharedKeyCredential,\n AnonymousCredential,\n} from \"@azure/storage-blob\";\nimport { BlobServiceClient, Pipeline } from \"@azure/storage-blob\";\nimport type { PagedAsyncIterableIterator, PageSettings } from \"@azure/core-paging\";\nimport type { BlobChangeFeedEvent } from \"./models/BlobChangeFeedEvent.js\";\nimport { ChangeFeedFactory } from \"./ChangeFeedFactory.js\";\nimport type { ChangeFeed } from \"./ChangeFeed.js\";\nimport { CHANGE_FEED_MAX_PAGE_SIZE, SDK_VERSION } from \"./utils/constants.js\";\nimport type { BlobChangeFeedListChangesOptions } from \"./models/models.js\";\nimport type { TokenCredential } from \"@azure/core-auth\";\n\n/**\n * Contains paged response data for the {@link BlobChangeFeedClient.listChanges} operation.\n */\nexport class BlobChangeFeedEventPage {\n /**\n * Array of {@link BlobChangeFeedEvent}.\n */\n public events: BlobChangeFeedEvent[];\n\n /**\n * The token that keeps track of where to continue the iterator.\n */\n public continuationToken: string;\n\n constructor() {\n this.events = [];\n this.continuationToken = \"\";\n }\n}\n\n/**\n * Creates a new Pipeline object with Credential provided.\n *\n * @param credential - Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used.\n * @param pipelineOptions - Optional. Options.\n * @returns A new Pipeline object.\n */\nexport function newPipeline(\n credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential,\n pipelineOptions: StoragePipelineOptions = {},\n): Pipeline {\n return newPipeline(credential, appendUserAgentPrefix(pipelineOptions));\n}\n\nfunction appendUserAgentPrefix(options?: StoragePipelineOptions): StoragePipelineOptions {\n if (!options) {\n options = {};\n }\n if (options.userAgentOptions === undefined) {\n options.userAgentOptions = {};\n }\n\n if (options.userAgentOptions.userAgentPrefix === undefined) {\n options.userAgentOptions.userAgentPrefix = \"\";\n } else if (options.userAgentOptions.userAgentPrefix !== \"\") {\n options.userAgentOptions.userAgentPrefix += \" \";\n }\n options.userAgentOptions.userAgentPrefix += `changefeed-js/${SDK_VERSION}`;\n return options;\n}\n\n/**\n * Blob Change Feed client options.\n */\nexport interface BlobChangeFeedClientOptions {\n /**\n * The maximum length of an transfer in bytes.\n */\n maximumTransferSize?: number;\n}\n\n/**\n * BlobChangeFeedClient.\n * @see https://learn.microsoft.com/azure/storage/blobs/storage-blob-change-feed?tabs=azure-portal\n */\nexport class BlobChangeFeedClient {\n /**\n * blobServiceClient provided by `@azure/storage-blob` package.\n */\n private blobServiceClient: BlobServiceClient;\n private changeFeedFactory: ChangeFeedFactory;\n private changeFeedClientOptions: BlobChangeFeedClientOptions;\n\n /**\n *\n * Creates an instance of BlobChangeFeedClient from connection string.\n *\n * @param connectionString - Account connection string or a SAS connection string of an Azure storage account.\n * [ Note - Account connection string can only be used in NODE.JS runtime. ]\n * Account connection string example -\n * `DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=accountKey;EndpointSuffix=core.windows.net`\n * SAS connection string example -\n * `BlobEndpoint=https://myaccount.blob.core.windows.net/;QueueEndpoint=https://myaccount.queue.core.windows.net/;FileEndpoint=https://myaccount.file.core.windows.net/;TableEndpoint=https://myaccount.table.core.windows.net/;SharedAccessSignature=sasString`\n * @param options - Optional. Options to configure the HTTP pipeline.\n */\n public static fromConnectionString(\n connectionString: string,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n // Static method to construct an object, the option is for the object not for the method.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n ): BlobChangeFeedClient {\n const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString, options);\n return new BlobChangeFeedClient(\n blobServiceClient.url,\n blobServiceClient.credential,\n appendUserAgentPrefix(options),\n changeFeedClientOptions,\n );\n }\n\n /**\n * Creates an instance of BlobChangeFeedClient.\n *\n * @param url - A Client string pointing to Azure Storage blob service, such as\n * \"https://myaccount.blob.core.windows.net\". You can append a SAS\n * if using AnonymousCredential, such as \"https://myaccount.blob.core.windows.net?sasString\".\n * @param credential - Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used.\n * @param options - Optional. Options to configure the HTTP pipeline.\n *\n * Example using DefaultAzureCredential from `@azure/identity`:\n *\n * ```ts snippet:ReadmeSampleCreateClient_TokenCredential\n * import { DefaultAzureCredential } from \"@azure/identity\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * // Enter your storage account name and shared key\n * const account = \"<account>\";\n * const credential = new DefaultAzureCredential();\n * const changeFeedClient = new BlobChangeFeedClient(\n * // When using AnonymousCredential, following url should include a valid SAS or support public access\n * `https://${account}.blob.core.windows.net`,\n * credential,\n * );\n * ```\n *\n * Example using an account name/key:\n *\n * ```ts snippet:ReadmeSampleCreateClient\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * // Enter your storage account name and shared key\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * // Use StorageSharedKeyCredential with storage account and account key\n * // StorageSharedKeyCredential is only available in Node.js runtime, not in browsers\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * // When using AnonymousCredential, following url should include a valid SAS or support public access\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n * ```\n */\n constructor(\n url: string,\n credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n );\n\n /**\n * Creates an instance of BlobChangeFeedClient.\n *\n * @param url - A Client string pointing to Azure Storage blob service, such as\n * \"https://myaccount.blob.core.windows.net\". You can append a SAS\n * if using AnonymousCredential, such as \"https://myaccount.blob.core.windows.net?sasString\".\n * @param pipeline - Call newPipeline() to create a default\n * pipeline, or provide a customized pipeline.\n */\n constructor(url: string, pipeline: Pipeline);\n constructor(\n urlOrClient: string,\n credentialOrPipeline?:\n | StorageSharedKeyCredential\n | AnonymousCredential\n | TokenCredential\n | Pipeline,\n // Legacy, no way to fix the eslint error without breaking. Disable the rule for this line.\n /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */\n options?: StoragePipelineOptions,\n changeFeedClientOptions?: BlobChangeFeedClientOptions,\n ) {\n this.changeFeedClientOptions = changeFeedClientOptions || {};\n this.changeFeedFactory = new ChangeFeedFactory(\n this.changeFeedClientOptions.maximumTransferSize,\n );\n\n if (credentialOrPipeline instanceof Pipeline) {\n this.blobServiceClient = new BlobServiceClient(urlOrClient, credentialOrPipeline);\n } else {\n this.blobServiceClient = new BlobServiceClient(\n urlOrClient,\n credentialOrPipeline,\n appendUserAgentPrefix(options),\n );\n }\n }\n\n private async *getChange(\n options: BlobChangeFeedListChangesOptions = {},\n ): AsyncIterableIterator<BlobChangeFeedEvent> {\n const changeFeed: ChangeFeed = await this.changeFeedFactory.create(\n this.blobServiceClient,\n undefined,\n options,\n );\n\n while (changeFeed.hasNext()) {\n const event = await changeFeed.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: options.tracingOptions,\n });\n if (event) {\n yield event;\n } else {\n return;\n }\n }\n }\n\n // start in ChangeFeedListChangesOptions will be ignored when continuationToken is specified.\n private async *getPage(\n continuationToken?: string,\n maxPageSize?: number,\n options: BlobChangeFeedListChangesOptions = {},\n ): AsyncIterableIterator<BlobChangeFeedEventPage> {\n const changeFeed: ChangeFeed = await this.changeFeedFactory.create(\n this.blobServiceClient,\n continuationToken,\n options,\n );\n\n if (!maxPageSize || maxPageSize > CHANGE_FEED_MAX_PAGE_SIZE) {\n maxPageSize = CHANGE_FEED_MAX_PAGE_SIZE;\n }\n while (changeFeed.hasNext()) {\n const eventPage = new BlobChangeFeedEventPage();\n while (changeFeed.hasNext() && eventPage.events.length < maxPageSize) {\n const event = await changeFeed.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: options.tracingOptions,\n });\n if (event) {\n eventPage.events.push(event);\n }\n }\n if (changeFeed.hasNext()) {\n eventPage.continuationToken = JSON.stringify(changeFeed.getCursor());\n }\n if (eventPage.events.length > 0) {\n yield eventPage;\n } else {\n return;\n }\n }\n }\n\n /**\n * Returns an async iterable iterator to list all the change feed events\n * in the specified account.\n *\n * .byPage() returns an async iterable iterator to list the change feed events in pages.\n *\n * Example using `for await` syntax:\n *\n * ```ts snippet:ReadmeSampleListChanges\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n *\n * // Use for await to iterate through the change feed\n * for await (const event of changeFeedClient.listChanges()) {\n * console.log(`Event: ${event.eventType}`);\n * console.log(`Event time: ${event.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(event.data)}`);\n * }\n *\n * // Use `byPage` to iterate through the change feed\n * for await (const page of changeFeedClient.listChanges().byPage()) {\n * console.log(`Page: ${JSON.stringify(page)}`);\n * for (const event of page.events) {\n * console.log(`Event: ${event.eventType}`);\n * console.log(`Event time: ${event.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(event.data)}`);\n * }\n * }\n * ```\n *\n * Example using paging with a marker:\n *\n * ```ts snippet:ReadmeSampleListChanges_Continuation\n * import { StorageSharedKeyCredential } from \"@azure/storage-blob\";\n * import { BlobChangeFeedClient } from \"@azure/storage-blob-changefeed\";\n *\n * const account = \"<account>\";\n * const accountKey = \"<accountkey>\";\n * const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);\n * const changeFeedClient = new BlobChangeFeedClient(\n * `https://${account}.blob.core.windows.net`,\n * sharedKeyCredential,\n * );\n *\n * let iterator = changeFeedClient.listChanges().byPage({ maxPageSize: 2 });\n * let response = (await iterator.next()).value;\n * // Prints 2 page ranges\n * if (response.pageRange) {\n * for (const pageRange of response.pageRange) {\n * console.log(`Event: ${pageRange.eventType}`);\n * console.log(`Event time: ${pageRange.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(pageRange.data)}`);\n * }\n * }\n * // Gets next marker\n * let marker = response.continuationToken;\n * // Passing next marker as continuationToken\n * iterator = changeFeedClient.listChanges().byPage({ continuationToken: marker, maxPageSize: 10 });\n * response = (await iterator.next()).value;\n * // Prints 10 page ranges\n * if (response.pageRange) {\n * for (const pageRange of response.pageRange) {\n * console.log(`Event: ${pageRange.eventType}`);\n * console.log(`Event time: ${pageRange.eventTime}`);\n * console.log(`Event data: ${JSON.stringify(pageRange.data)}`);\n * }\n * }\n * ```\n *\n * @param options - Options to list change feed events.\n * @returns An asyncIterableIterator that supports paging.\n */\n public listChanges(\n options: BlobChangeFeedListChangesOptions = {},\n ): PagedAsyncIterableIterator<BlobChangeFeedEvent, BlobChangeFeedEventPage> {\n const iter = this.getChange(options);\n return {\n /**\n * The next method, part of the iteration protocol\n */\n async next() {\n return iter.next();\n },\n /**\n * The connection to the async iterator, part of the iteration protocol\n */\n [Symbol.asyncIterator]() {\n return this;\n },\n /**\n * Return an AsyncIterableIterator that works a page at a time\n */\n byPage: (settings: PageSettings = {}) => {\n return this.getPage(settings.continuationToken, settings.maxPageSize, options);\n },\n };\n }\n}\n"]}
|
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
import { getSegmentsInYear, minDate, getHost } from "./utils/utils.common.js";
|
|
4
4
|
import { tracingClient } from "./utils/tracing.js";
|
|
5
5
|
export class ChangeFeed {
|
|
6
|
+
/**
|
|
7
|
+
* BlobContainerClient for making List Blob requests and creating Segments.
|
|
8
|
+
*/
|
|
9
|
+
containerClient;
|
|
10
|
+
segmentFactory;
|
|
11
|
+
years;
|
|
12
|
+
segments;
|
|
13
|
+
currentSegment;
|
|
14
|
+
lastConsumable;
|
|
15
|
+
startTime;
|
|
16
|
+
endTime;
|
|
17
|
+
end;
|
|
6
18
|
constructor(containerClient, segmentFactory, years, segments, currentSegment, lastConsumable, startTime, endTime) {
|
|
7
19
|
this.containerClient = containerClient;
|
|
8
20
|
this.segmentFactory = segmentFactory;
|
|
@@ -78,14 +90,13 @@ export class ChangeFeed {
|
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
getCursor() {
|
|
81
|
-
var _a;
|
|
82
93
|
if (!this.currentSegment) {
|
|
83
94
|
throw new Error("Empty Change Feed shouldn't call this function.");
|
|
84
95
|
}
|
|
85
96
|
return {
|
|
86
97
|
CursorVersion: 1,
|
|
87
98
|
UrlHost: getHost(this.containerClient.url),
|
|
88
|
-
EndTime:
|
|
99
|
+
EndTime: this.endTime?.toJSON(),
|
|
89
100
|
CurrentSegmentCursor: this.currentSegment.getCursor(),
|
|
90
101
|
};
|
|
91
102
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeFeed.js","sourceRoot":"","sources":["../../src/ChangeFeed.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAOlC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAanD,MAAM,OAAO,UAAU;
|
|
1
|
+
{"version":3,"file":"ChangeFeed.js","sourceRoot":"","sources":["../../src/ChangeFeed.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { ContainerClient, CommonOptions } from \"@azure/storage-blob\";\nimport type { Segment } from \"./Segment.js\";\nimport type { SegmentFactory } from \"./SegmentFactory.js\";\nimport type { BlobChangeFeedEvent } from \"./models/BlobChangeFeedEvent.js\";\nimport type { ChangeFeedCursor } from \"./models/ChangeFeedCursor.js\";\nimport { getSegmentsInYear, minDate, getHost } from \"./utils/utils.common.js\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { tracingClient } from \"./utils/tracing.js\";\n\n/**\n * Options to configure {@link ChangeFeed.getChange} operation.\n */\nexport interface ChangeFeedGetChangeOptions extends CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\nexport class ChangeFeed {\n /**\n * BlobContainerClient for making List Blob requests and creating Segments.\n */\n private readonly containerClient?: ContainerClient;\n\n private readonly segmentFactory?: SegmentFactory;\n\n private readonly years: number[];\n\n private segments: string[];\n\n private currentSegment?: Segment;\n\n private lastConsumable?: Date;\n\n private startTime?: Date;\n\n private endTime?: Date;\n\n private end?: Date;\n\n constructor();\n constructor(\n containerClient: ContainerClient,\n segmentFactory: SegmentFactory,\n years: number[],\n segments: string[],\n currentSegment: Segment,\n lastConsumable: Date,\n startTime?: Date,\n endTime?: Date,\n );\n\n constructor(\n containerClient?: ContainerClient,\n segmentFactory?: SegmentFactory,\n years?: number[],\n segments?: string[],\n currentSegment?: Segment,\n lastConsumable?: Date,\n startTime?: Date,\n endTime?: Date,\n ) {\n this.containerClient = containerClient;\n this.segmentFactory = segmentFactory;\n this.years = years || [];\n this.segments = segments || [];\n this.currentSegment = currentSegment;\n this.lastConsumable = lastConsumable;\n this.startTime = startTime;\n this.endTime = endTime;\n if (this.lastConsumable) {\n this.end = minDate(this.lastConsumable, this.endTime);\n }\n }\n\n private async advanceSegmentIfNecessary(options: ChangeFeedGetChangeOptions = {}): Promise<void> {\n return tracingClient.withSpan(\n \"ChangeFeed-advanceSegmentIfNecessary\",\n options,\n async (updatedOptions) => {\n if (!this.currentSegment) {\n throw new Error(\"Empty Change Feed shouldn't call this function.\");\n }\n\n // If the current segment has more Events, we don't need to do anything.\n if (this.currentSegment.hasNext()) {\n return;\n }\n\n // If the current segment is completed, remove it\n if (this.segments.length > 0) {\n this.currentSegment = await this.segmentFactory!.create(\n this.containerClient!,\n this.segments.shift()!,\n undefined,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n }\n // If segments is empty, refill it\n else if (this.segments.length === 0 && this.years.length > 0) {\n const year = this.years.shift();\n this.segments = await getSegmentsInYear(\n this.containerClient!,\n year!,\n this.startTime,\n this.end,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n\n if (this.segments.length > 0) {\n this.currentSegment = await this.segmentFactory!.create(\n this.containerClient!,\n this.segments.shift()!,\n undefined,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n } else {\n this.currentSegment = undefined;\n }\n }\n },\n );\n }\n\n public hasNext(): boolean {\n // Empty ChangeFeed, using currentSegment as the indicator.\n if (!this.currentSegment) {\n return false;\n }\n\n if (this.segments.length === 0 && this.years.length === 0 && !this.currentSegment.hasNext()) {\n return false;\n }\n\n return this.currentSegment.dateTime < this.end!;\n }\n\n public async getChange(\n options: ChangeFeedGetChangeOptions = {},\n ): Promise<BlobChangeFeedEvent | undefined> {\n return tracingClient.withSpan(\"ChangeFeed-getChange\", options, async (updatedOptions) => {\n let event: BlobChangeFeedEvent | undefined = undefined;\n while (event === undefined && this.hasNext()) {\n event = await this.currentSegment!.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n await this.advanceSegmentIfNecessary({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n }\n return event;\n });\n }\n\n public getCursor(): ChangeFeedCursor {\n if (!this.currentSegment) {\n throw new Error(\"Empty Change Feed shouldn't call this function.\");\n }\n\n return {\n CursorVersion: 1,\n UrlHost: getHost(this.containerClient!.url)!,\n EndTime: this.endTime?.toJSON(),\n CurrentSegmentCursor: this.currentSegment!.getCursor(),\n };\n }\n}\n"]}
|
|
@@ -14,6 +14,8 @@ function isSegmentFactory(segmentFactoryOrMaxTransferSize) {
|
|
|
14
14
|
return segmentFactoryOrMaxTransferSize.create !== undefined;
|
|
15
15
|
}
|
|
16
16
|
export class ChangeFeedFactory {
|
|
17
|
+
segmentFactory;
|
|
18
|
+
maxTransferSize;
|
|
17
19
|
constructor(segmentFactoryOrMaxTransferSize) {
|
|
18
20
|
let segmentFactory;
|
|
19
21
|
if (segmentFactoryOrMaxTransferSize) {
|
|
@@ -109,7 +111,7 @@ export class ChangeFeedFactory {
|
|
|
109
111
|
if (segments.length === 0) {
|
|
110
112
|
return new ChangeFeed();
|
|
111
113
|
}
|
|
112
|
-
const currentSegment = await this.segmentFactory.create(containerClient, segments.shift(), cursor
|
|
114
|
+
const currentSegment = await this.segmentFactory.create(containerClient, segments.shift(), cursor?.CurrentSegmentCursor, {
|
|
113
115
|
abortSignal: options.abortSignal,
|
|
114
116
|
tracingOptions: updatedOptions.tracingOptions,
|
|
115
117
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeFeedFactory.js","sourceRoot":"","sources":["../../src/ChangeFeedFactory.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { BlobServiceClient, ContainerClient } from \"@azure/storage-blob\";\nimport { ChangeFeed } from \"./ChangeFeed.js\";\nimport type { ChangeFeedCursor } from \"./models/ChangeFeedCursor.js\";\nimport { CHANGE_FEED_CONTAINER_NAME, CHANGE_FEED_META_SEGMENT_PATH } from \"./utils/constants.js\";\nimport {\n ceilToNearestHour,\n floorToNearestHour,\n getYearsPaths,\n getSegmentsInYear,\n minDate,\n getHost,\n parseDateFromSegmentPath,\n} from \"./utils/utils.common.js\";\nimport { bodyToString } from \"./utils/utils.node.js\";\nimport { SegmentFactory } from \"./SegmentFactory.js\";\nimport { ShardFactory } from \"./ShardFactory.js\";\nimport { ChunkFactory } from \"./ChunkFactory.js\";\nimport { AvroReaderFactory } from \"./AvroReaderFactory.js\";\nimport type { Segment } from \"./Segment.js\";\nimport type { BlobChangeFeedListChangesOptions } from \"./models/models.js\";\nimport { tracingClient } from \"./utils/tracing.js\";\nimport { LazyLoadingBlobStreamFactory } from \"./LazyLoadingBlobStreamFactory.js\";\n\ninterface MetaSegments {\n version?: number;\n lastConsumable: string;\n}\n\nfunction isSegmentFactory(\n segmentFactoryOrMaxTransferSize: SegmentFactory | number,\n): segmentFactoryOrMaxTransferSize is SegmentFactory {\n return (segmentFactoryOrMaxTransferSize as SegmentFactory).create !== undefined;\n}\n\nexport class ChangeFeedFactory {\n private readonly segmentFactory: SegmentFactory;\n private readonly maxTransferSize?: number;\n\n constructor(maxTransferSize?: number);\n constructor(segmentFactory: SegmentFactory);\n constructor(segmentFactoryOrMaxTransferSize?: SegmentFactory | number) {\n let segmentFactory: SegmentFactory | undefined;\n if (segmentFactoryOrMaxTransferSize) {\n if (Number.isFinite(segmentFactoryOrMaxTransferSize)) {\n this.maxTransferSize = segmentFactoryOrMaxTransferSize as number;\n } else if (isSegmentFactory(segmentFactoryOrMaxTransferSize)) {\n segmentFactory = segmentFactoryOrMaxTransferSize as SegmentFactory;\n }\n }\n\n if (segmentFactory) {\n this.segmentFactory = segmentFactory;\n } else {\n this.segmentFactory = new SegmentFactory(\n new ShardFactory(\n new ChunkFactory(\n new AvroReaderFactory(),\n new LazyLoadingBlobStreamFactory(),\n this.maxTransferSize,\n ),\n ),\n );\n }\n }\n\n private static validateCursor(containerClient: ContainerClient, cursor: ChangeFeedCursor): void {\n if (getHost(containerClient.url) !== cursor.UrlHost) {\n throw new Error(\"Cursor URL host does not match container URL host.\");\n }\n if (cursor.CursorVersion !== 1) {\n throw new Error(\"Unsupported cursor version.\");\n }\n }\n\n public async create(\n blobServiceClient: BlobServiceClient,\n continuationToken?: string,\n options: BlobChangeFeedListChangesOptions = {},\n ): Promise<ChangeFeed> {\n return tracingClient.withSpan(\"ChangeFeedFactory-create\", options, async (updatedOptions) => {\n const containerClient = blobServiceClient.getContainerClient(CHANGE_FEED_CONTAINER_NAME);\n let cursor: ChangeFeedCursor | undefined = undefined;\n // Create cursor.\n if (continuationToken) {\n cursor = JSON.parse(continuationToken);\n ChangeFeedFactory.validateCursor(containerClient, cursor!);\n options.start = parseDateFromSegmentPath(cursor!.CurrentSegmentCursor.SegmentPath!);\n options.end = new Date(cursor!.EndTime!);\n }\n // Round start and end time if we are not using the cursor.\n else {\n options.start = floorToNearestHour(options.start);\n options.end = ceilToNearestHour(options.end);\n }\n\n // Check if Change Feed has been enabled for this account.\n const changeFeedContainerExists = await containerClient.exists({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n if (!changeFeedContainerExists) {\n throw new Error(\n \"Change Feed hasn't been enabled on this account, or is currently being enabled.\",\n );\n }\n\n if (options.start && options.end && options.start >= options.end) {\n return new ChangeFeed();\n }\n\n // Get last consumable.\n const blobClient = containerClient.getBlobClient(CHANGE_FEED_META_SEGMENT_PATH);\n let blobDownloadRes;\n try {\n blobDownloadRes = await blobClient.download(undefined, undefined, {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n } catch (err: any) {\n if (err.statusCode === 404) {\n return new ChangeFeed();\n } else {\n throw err;\n }\n }\n const lastConsumable = new Date(\n (JSON.parse(await bodyToString(blobDownloadRes)) as MetaSegments).lastConsumable,\n );\n\n // Get year paths\n const years: number[] = await getYearsPaths(containerClient, {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n\n // Dequeue any years that occur before start time.\n if (options.start) {\n const startYear = options.start.getUTCFullYear();\n while (years.length > 0 && years[0] < startYear) {\n years.shift();\n }\n }\n if (years.length === 0) {\n return new ChangeFeed();\n }\n\n let segments: string[] = [];\n while (segments.length === 0 && years.length !== 0) {\n segments = await getSegmentsInYear(\n containerClient,\n years.shift()!,\n options.start,\n minDate(lastConsumable, options.end),\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n }\n if (segments.length === 0) {\n return new ChangeFeed();\n }\n const currentSegment: Segment = await this.segmentFactory.create(\n containerClient,\n segments.shift()!,\n cursor?.CurrentSegmentCursor,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n\n return new ChangeFeed(\n containerClient,\n this.segmentFactory,\n years,\n segments,\n currentSegment,\n lastConsumable,\n options.start,\n options.end,\n );\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ChangeFeedFactory.js","sourceRoot":"","sources":["../../src/ChangeFeedFactory.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { BlobServiceClient, ContainerClient } from \"@azure/storage-blob\";\nimport { ChangeFeed } from \"./ChangeFeed.js\";\nimport type { ChangeFeedCursor } from \"./models/ChangeFeedCursor.js\";\nimport { CHANGE_FEED_CONTAINER_NAME, CHANGE_FEED_META_SEGMENT_PATH } from \"./utils/constants.js\";\nimport {\n ceilToNearestHour,\n floorToNearestHour,\n getYearsPaths,\n getSegmentsInYear,\n minDate,\n getHost,\n parseDateFromSegmentPath,\n} from \"./utils/utils.common.js\";\nimport { bodyToString } from \"./utils/utils.node.js\";\nimport { SegmentFactory } from \"./SegmentFactory.js\";\nimport { ShardFactory } from \"./ShardFactory.js\";\nimport { ChunkFactory } from \"./ChunkFactory.js\";\nimport { AvroReaderFactory } from \"./AvroReaderFactory.js\";\nimport type { Segment } from \"./Segment.js\";\nimport type { BlobChangeFeedListChangesOptions } from \"./models/models.js\";\nimport { tracingClient } from \"./utils/tracing.js\";\nimport { LazyLoadingBlobStreamFactory } from \"./LazyLoadingBlobStreamFactory.js\";\n\ninterface MetaSegments {\n version?: number;\n lastConsumable: string;\n}\n\nfunction isSegmentFactory(\n segmentFactoryOrMaxTransferSize: SegmentFactory | number,\n): segmentFactoryOrMaxTransferSize is SegmentFactory {\n return (segmentFactoryOrMaxTransferSize as SegmentFactory).create !== undefined;\n}\n\nexport class ChangeFeedFactory {\n private readonly segmentFactory: SegmentFactory;\n private readonly maxTransferSize?: number;\n\n constructor(maxTransferSize?: number);\n constructor(segmentFactory: SegmentFactory);\n constructor(segmentFactoryOrMaxTransferSize?: SegmentFactory | number) {\n let segmentFactory: SegmentFactory | undefined;\n if (segmentFactoryOrMaxTransferSize) {\n if (Number.isFinite(segmentFactoryOrMaxTransferSize)) {\n this.maxTransferSize = segmentFactoryOrMaxTransferSize as number;\n } else if (isSegmentFactory(segmentFactoryOrMaxTransferSize)) {\n segmentFactory = segmentFactoryOrMaxTransferSize as SegmentFactory;\n }\n }\n\n if (segmentFactory) {\n this.segmentFactory = segmentFactory;\n } else {\n this.segmentFactory = new SegmentFactory(\n new ShardFactory(\n new ChunkFactory(\n new AvroReaderFactory(),\n new LazyLoadingBlobStreamFactory(),\n this.maxTransferSize,\n ),\n ),\n );\n }\n }\n\n private static validateCursor(containerClient: ContainerClient, cursor: ChangeFeedCursor): void {\n if (getHost(containerClient.url) !== cursor.UrlHost) {\n throw new Error(\"Cursor URL host does not match container URL host.\");\n }\n if (cursor.CursorVersion !== 1) {\n throw new Error(\"Unsupported cursor version.\");\n }\n }\n\n public async create(\n blobServiceClient: BlobServiceClient,\n continuationToken?: string,\n options: BlobChangeFeedListChangesOptions = {},\n ): Promise<ChangeFeed> {\n return tracingClient.withSpan(\"ChangeFeedFactory-create\", options, async (updatedOptions) => {\n const containerClient = blobServiceClient.getContainerClient(CHANGE_FEED_CONTAINER_NAME);\n let cursor: ChangeFeedCursor | undefined = undefined;\n // Create cursor.\n if (continuationToken) {\n cursor = JSON.parse(continuationToken);\n ChangeFeedFactory.validateCursor(containerClient, cursor!);\n options.start = parseDateFromSegmentPath(cursor!.CurrentSegmentCursor.SegmentPath!);\n options.end = new Date(cursor!.EndTime!);\n }\n // Round start and end time if we are not using the cursor.\n else {\n options.start = floorToNearestHour(options.start);\n options.end = ceilToNearestHour(options.end);\n }\n\n // Check if Change Feed has been enabled for this account.\n const changeFeedContainerExists = await containerClient.exists({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n if (!changeFeedContainerExists) {\n throw new Error(\n \"Change Feed hasn't been enabled on this account, or is currently being enabled.\",\n );\n }\n\n if (options.start && options.end && options.start >= options.end) {\n return new ChangeFeed();\n }\n\n // Get last consumable.\n const blobClient = containerClient.getBlobClient(CHANGE_FEED_META_SEGMENT_PATH);\n let blobDownloadRes;\n try {\n blobDownloadRes = await blobClient.download(undefined, undefined, {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n } catch (err: any) {\n if (err.statusCode === 404) {\n return new ChangeFeed();\n } else {\n throw err;\n }\n }\n const lastConsumable = new Date(\n (JSON.parse(await bodyToString(blobDownloadRes)) as MetaSegments).lastConsumable,\n );\n\n // Get year paths\n const years: number[] = await getYearsPaths(containerClient, {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n\n // Dequeue any years that occur before start time.\n if (options.start) {\n const startYear = options.start.getUTCFullYear();\n while (years.length > 0 && years[0] < startYear) {\n years.shift();\n }\n }\n if (years.length === 0) {\n return new ChangeFeed();\n }\n\n let segments: string[] = [];\n while (segments.length === 0 && years.length !== 0) {\n segments = await getSegmentsInYear(\n containerClient,\n years.shift()!,\n options.start,\n minDate(lastConsumable, options.end),\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n }\n if (segments.length === 0) {\n return new ChangeFeed();\n }\n const currentSegment: Segment = await this.segmentFactory.create(\n containerClient,\n segments.shift()!,\n cursor?.CurrentSegmentCursor,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n\n return new ChangeFeed(\n containerClient,\n this.segmentFactory,\n years,\n segments,\n currentSegment,\n lastConsumable,\n options.start,\n options.end,\n );\n });\n }\n}\n"]}
|
package/dist/browser/Chunk.js
CHANGED
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
import { rawEventToBlobChangeFeedEvent } from "./utils/utils.common.js";
|
|
4
4
|
export class Chunk {
|
|
5
|
+
chunkPath;
|
|
6
|
+
avroReader;
|
|
7
|
+
iter;
|
|
8
|
+
_blockOffset;
|
|
5
9
|
get blockOffset() {
|
|
6
10
|
return this._blockOffset;
|
|
7
11
|
}
|
|
12
|
+
_eventIndex;
|
|
8
13
|
get eventIndex() {
|
|
9
14
|
return this._eventIndex;
|
|
10
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chunk.js","sourceRoot":"","sources":["../../src/Chunk.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAaxE,MAAM,OAAO,KAAK;
|
|
1
|
+
{"version":3,"file":"Chunk.js","sourceRoot":"","sources":["../../src/Chunk.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAMlC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAaxE,MAAM,OAAO,KAAK;IAkBE;IAjBD,UAAU,CAAa;IACvB,IAAI,CAAoD;IAEjE,YAAY,CAAS;IAC7B,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAEO,WAAW,CAAS;IAC5B,IAAW,UAAU;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,YACE,UAAsB,EACtB,WAAmB,EACnB,UAAkB,EACF,SAAiB,EACjC,cAAgC,EAAE;QADlB,cAAS,GAAT,SAAS,CAAQ;QAGjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAE9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IACxD,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC;IAEM,KAAK,CAAC,SAAS;QACpB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACpB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAChD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC;YAC5B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AvroReader, AvroParseOptions } from \"@azure/storage-internal-avro\";\nimport type { BlobChangeFeedEvent } from \"./models/BlobChangeFeedEvent.js\";\nimport type { CommonOptions } from \"@azure/storage-blob\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { rawEventToBlobChangeFeedEvent } from \"./utils/utils.common.js\";\n\n/**\n * Options to configure {@link Chunk.getChange} operation.\n */\nexport interface ChunkGetChangeOptions extends CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\nexport class Chunk {\n private readonly avroReader: AvroReader;\n private readonly iter: AsyncIterableIterator<Record<string, any> | null>;\n\n private _blockOffset: number;\n public get blockOffset(): number {\n return this._blockOffset;\n }\n\n private _eventIndex: number;\n public get eventIndex(): number {\n return this._eventIndex;\n }\n\n constructor(\n avroReader: AvroReader,\n blockOffset: number,\n eventIndex: number,\n public readonly chunkPath: string,\n avroOptions: AvroParseOptions = {},\n ) {\n this.avroReader = avroReader;\n this._blockOffset = blockOffset;\n this._eventIndex = eventIndex;\n\n this.iter = this.avroReader.parseObjects(avroOptions);\n }\n\n public hasNext(): boolean {\n return this.avroReader.hasNext();\n }\n\n public async getChange(): Promise<BlobChangeFeedEvent | undefined> {\n if (!this.hasNext()) {\n return undefined;\n }\n\n const next = await this.iter.next();\n this._eventIndex = this.avroReader.objectIndex;\n this._blockOffset = this.avroReader.blockOffset;\n if (next.done) {\n return undefined;\n } else {\n const eventRaw = next.value;\n if (eventRaw === null) {\n return undefined;\n }\n\n return rawEventToBlobChangeFeedEvent(eventRaw);\n }\n }\n}\n"]}
|
|
@@ -4,6 +4,9 @@ import { Chunk } from "./Chunk.js";
|
|
|
4
4
|
import { streamToAvroReadable } from "./utils/utils.node.js";
|
|
5
5
|
import { CHANGE_FEED_CHUNK_BLOCK_DOWNLOAD_SIZE } from "./utils/constants.js";
|
|
6
6
|
export class ChunkFactory {
|
|
7
|
+
avroReaderFactory;
|
|
8
|
+
lazyLoadingBlobStreamFactory;
|
|
9
|
+
maxTransferSize;
|
|
7
10
|
constructor(avroReaderFactory, lazyLoadingBlobStreamFactory, maxTransferSize) {
|
|
8
11
|
this.avroReaderFactory = avroReaderFactory;
|
|
9
12
|
this.lazyLoadingBlobStreamFactory = lazyLoadingBlobStreamFactory;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChunkFactory.js","sourceRoot":"","sources":["../../src/ChunkFactory.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAIlC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,qCAAqC,EAAE,MAAM,sBAAsB,CAAC;AAc7E,MAAM,OAAO,YAAY;
|
|
1
|
+
{"version":3,"file":"ChunkFactory.js","sourceRoot":"","sources":["../../src/ChunkFactory.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAIlC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,EAAE,qCAAqC,EAAE,MAAM,sBAAsB,CAAC;AAc7E,MAAM,OAAO,YAAY;IACN,iBAAiB,CAAoB;IACrC,4BAA4B,CAA+B;IAC3D,eAAe,CAAU;IAE1C,YACE,iBAAoC,EACpC,4BAA0D,EAC1D,eAAwB;QAExB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,4BAA4B,GAAG,4BAA4B,CAAC;QACjE,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,CAAC;IAEM,KAAK,CAAC,MAAM,CACjB,eAAgC,EAChC,SAAiB,EACjB,WAAoB,EACpB,UAAmB,EACnB,UAA8B,EAAE;QAEhC,MAAM,UAAU,GAAG,eAAe,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC5D,WAAW,GAAG,WAAW,IAAI,CAAC,CAAC;QAC/B,UAAU,GAAG,UAAU,IAAI,CAAC,CAAC;QAE7B,MAAM,UAAU,GAAG,oBAAoB,CACrC,IAAI,CAAC,4BAA4B,CAAC,MAAM,CACtC,UAAU,EACV,WAAW,EACX,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,qCAAqC,EACnF,OAAO,CACR,CACF,CAAC;QAEF,IAAI,UAAsB,CAAC;QAC3B,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,YAAY,GAAG,oBAAoB,CACvC,IAAI,CAAC,4BAA4B,CAAC,MAAM,CACtC,UAAU,EACV,CAAC,EACD,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,qCAAqC,EACnF,OAAO,CACR,CACF,CAAC;YACF,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,IAAI,KAAK,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE;YAC/D,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AvroReaderFactory } from \"./AvroReaderFactory.js\";\nimport type { ContainerClient, CommonOptions } from \"@azure/storage-blob\";\nimport { Chunk } from \"./Chunk.js\";\nimport { streamToAvroReadable } from \"./utils/utils.node.js\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport type { LazyLoadingBlobStreamFactory } from \"./LazyLoadingBlobStreamFactory.js\";\nimport { CHANGE_FEED_CHUNK_BLOCK_DOWNLOAD_SIZE } from \"./utils/constants.js\";\nimport type { AvroReader } from \"@azure/storage-internal-avro\";\n\n/**\n * Options to configure {@link ChunkFactory.create} operation.\n */\nexport interface CreateChunkOptions extends CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\nexport class ChunkFactory {\n private readonly avroReaderFactory: AvroReaderFactory;\n private readonly lazyLoadingBlobStreamFactory: LazyLoadingBlobStreamFactory;\n private readonly maxTransferSize?: number;\n\n constructor(\n avroReaderFactory: AvroReaderFactory,\n lazyLoadingBlobStreamFactory: LazyLoadingBlobStreamFactory,\n maxTransferSize?: number,\n ) {\n this.avroReaderFactory = avroReaderFactory;\n this.lazyLoadingBlobStreamFactory = lazyLoadingBlobStreamFactory;\n this.maxTransferSize = maxTransferSize;\n }\n\n public async create(\n containerClient: ContainerClient,\n chunkPath: string,\n blockOffset?: number,\n eventIndex?: number,\n options: CreateChunkOptions = {},\n ): Promise<Chunk> {\n const blobClient = containerClient.getBlobClient(chunkPath);\n blockOffset = blockOffset || 0;\n eventIndex = eventIndex || 0;\n\n const dataStream = streamToAvroReadable(\n this.lazyLoadingBlobStreamFactory.create(\n blobClient,\n blockOffset,\n this.maxTransferSize ? this.maxTransferSize : CHANGE_FEED_CHUNK_BLOCK_DOWNLOAD_SIZE,\n options,\n ),\n );\n\n let avroReader: AvroReader;\n if (blockOffset !== 0) {\n const headerStream = streamToAvroReadable(\n this.lazyLoadingBlobStreamFactory.create(\n blobClient,\n 0,\n this.maxTransferSize ? this.maxTransferSize : CHANGE_FEED_CHUNK_BLOCK_DOWNLOAD_SIZE,\n options,\n ),\n );\n avroReader = this.avroReaderFactory.create(dataStream, headerStream, blockOffset, eventIndex);\n } else {\n avroReader = this.avroReaderFactory.create(dataStream);\n }\n\n return new Chunk(avroReader, blockOffset, eventIndex, chunkPath, {\n abortSignal: options.abortSignal,\n });\n }\n}\n"]}
|
|
@@ -6,6 +6,19 @@ import { tracingClient } from "./utils/tracing.js";
|
|
|
6
6
|
* This class generates a readable stream from a blobClient's data.
|
|
7
7
|
*/
|
|
8
8
|
export class LazyLoadingBlobStream extends Readable {
|
|
9
|
+
/**
|
|
10
|
+
* BlobClient to make download calls with.
|
|
11
|
+
*/
|
|
12
|
+
blobClient;
|
|
13
|
+
/**
|
|
14
|
+
* The offset within the blob of the next block we will download.
|
|
15
|
+
*/
|
|
16
|
+
offset;
|
|
17
|
+
blockSize;
|
|
18
|
+
lastDownloadBytes;
|
|
19
|
+
lastDownloadData;
|
|
20
|
+
blobLength;
|
|
21
|
+
options;
|
|
9
22
|
/**
|
|
10
23
|
* Creates an instance of LazyLoadingBlobStream.
|
|
11
24
|
*
|
|
@@ -45,9 +58,7 @@ export class LazyLoadingBlobStream extends Readable {
|
|
|
45
58
|
* @param size - Optional. The size of data to be read
|
|
46
59
|
*/
|
|
47
60
|
async _read(size) {
|
|
48
|
-
|
|
49
|
-
return tracingClient.withSpan("LazyLoadingBlobStream-read", (_a = this.options) !== null && _a !== void 0 ? _a : {}, async (updatedOptions) => {
|
|
50
|
-
var _a, _b, _c, _d;
|
|
61
|
+
return tracingClient.withSpan("LazyLoadingBlobStream-read", this.options ?? {}, async (updatedOptions) => {
|
|
51
62
|
if (!size) {
|
|
52
63
|
size = this.readableHighWaterMark;
|
|
53
64
|
}
|
|
@@ -55,14 +66,14 @@ export class LazyLoadingBlobStream extends Readable {
|
|
|
55
66
|
let chunkSize = 0;
|
|
56
67
|
const chunksToPush = [];
|
|
57
68
|
do {
|
|
58
|
-
if (this.lastDownloadData === undefined ||
|
|
69
|
+
if (this.lastDownloadData === undefined || this.lastDownloadData?.byteLength === 0) {
|
|
59
70
|
await this.downloadBlock({
|
|
60
|
-
abortSignal:
|
|
61
|
-
tracingOptions: updatedOptions
|
|
71
|
+
abortSignal: this.options?.abortSignal,
|
|
72
|
+
tracingOptions: updatedOptions?.tracingOptions,
|
|
62
73
|
});
|
|
63
74
|
}
|
|
64
|
-
if (
|
|
65
|
-
chunkSize = Math.min(size - count,
|
|
75
|
+
if (this.lastDownloadData?.byteLength) {
|
|
76
|
+
chunkSize = Math.min(size - count, this.lastDownloadData?.byteLength);
|
|
66
77
|
chunksToPush.push(this.lastDownloadData.slice(0, chunkSize));
|
|
67
78
|
this.lastDownloadData = this.lastDownloadData.slice(chunkSize);
|
|
68
79
|
count += chunkSize;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LazyLoadingBlobStream.js","sourceRoot":"","sources":["../../src/LazyLoadingBlobStream.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAqBnD;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,QAAQ;
|
|
1
|
+
{"version":3,"file":"LazyLoadingBlobStream.js","sourceRoot":"","sources":["../../src/LazyLoadingBlobStream.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { ReadableOptions } from \"node:stream\";\nimport { Readable } from \"node:stream\";\nimport type { BlobClient, CommonOptions } from \"@azure/storage-blob\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { tracingClient } from \"./utils/tracing.js\";\n\n/**\n * Options to configure the LazyLoadingBlobStream.\n */\nexport interface LazyLoadingBlobStreamOptions extends ReadableOptions, CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\ninterface LazyLoadingBlobStreamDownloadBlockOptions extends CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\n/**\n * This class generates a readable stream from a blobClient's data.\n */\nexport class LazyLoadingBlobStream extends Readable {\n /**\n * BlobClient to make download calls with.\n */\n private readonly blobClient: BlobClient;\n\n /**\n * The offset within the blob of the next block we will download.\n */\n private offset: number;\n\n private readonly blockSize: number;\n\n private lastDownloadBytes: number;\n\n private lastDownloadData?: Buffer;\n\n private blobLength: number;\n\n private options?: LazyLoadingBlobStreamOptions;\n\n /**\n * Creates an instance of LazyLoadingBlobStream.\n *\n * @param byteLength - The total length of data contained in the buffers\n */\n constructor(\n blobClient: BlobClient,\n offset: number,\n blockSize: number,\n options?: LazyLoadingBlobStreamOptions,\n ) {\n super(options);\n this.blobClient = blobClient;\n this.offset = offset;\n this.blockSize = blockSize;\n this.lastDownloadBytes = -1;\n this.blobLength = -1;\n this.options = options;\n }\n\n private async downloadBlock(options: LazyLoadingBlobStreamDownloadBlockOptions = {}) {\n return tracingClient.withSpan(\n \"LazyLoadingBlobStream-downloadBlock\",\n options,\n async (updatedOptions) => {\n const properties = await this.blobClient.getProperties({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n this.blobLength = properties.contentLength!;\n\n this.lastDownloadBytes = Math.min(this.blockSize, this.blobLength - this.offset);\n if (this.lastDownloadBytes === 0) {\n this.lastDownloadData = undefined;\n return;\n }\n\n this.lastDownloadData = await this.blobClient.downloadToBuffer(\n this.offset,\n this.lastDownloadBytes,\n {\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n },\n );\n this.offset += this.lastDownloadBytes;\n },\n );\n }\n\n /**\n * Internal _read() that will be called when the stream wants to pull more data in.\n *\n * @param size - Optional. The size of data to be read\n */\n public async _read(size?: number): Promise<void> {\n return tracingClient.withSpan(\n \"LazyLoadingBlobStream-read\",\n this.options ?? {},\n async (updatedOptions) => {\n if (!size) {\n size = this.readableHighWaterMark;\n }\n let count = 0;\n let chunkSize = 0;\n const chunksToPush = [];\n do {\n if (this.lastDownloadData === undefined || this.lastDownloadData?.byteLength === 0) {\n await this.downloadBlock({\n abortSignal: this.options?.abortSignal,\n tracingOptions: updatedOptions?.tracingOptions,\n });\n }\n if (this.lastDownloadData?.byteLength) {\n chunkSize = Math.min(size - count, this.lastDownloadData?.byteLength);\n chunksToPush.push(this.lastDownloadData.slice(0, chunkSize));\n this.lastDownloadData = this.lastDownloadData.slice(chunkSize);\n count += chunkSize;\n } else {\n chunkSize = 0;\n }\n } while (chunkSize > 0 && count < size);\n\n this.push(Buffer.concat(chunksToPush));\n\n if (count < size) {\n this.push(null);\n }\n },\n );\n }\n}\n"]}
|
package/dist/browser/Segment.js
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
import { tracingClient } from "./utils/tracing.js";
|
|
4
4
|
export class Segment {
|
|
5
|
+
manifestPath;
|
|
6
|
+
shards;
|
|
7
|
+
// Track shards that we have finished reading from.
|
|
8
|
+
shardDone;
|
|
9
|
+
shardDoneCount;
|
|
10
|
+
shardIndex;
|
|
11
|
+
// Assuming the dateTime of segments is rounded to hour. If not, our logic for fetching
|
|
12
|
+
// change events between a time range would be incorrect.
|
|
13
|
+
_dateTime;
|
|
5
14
|
get dateTime() {
|
|
6
15
|
return this._dateTime;
|
|
7
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Segment.js","sourceRoot":"","sources":["../../src/Segment.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAOlC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAanD,MAAM,OAAO,OAAO;
|
|
1
|
+
{"version":3,"file":"Segment.js","sourceRoot":"","sources":["../../src/Segment.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAOlC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAanD,MAAM,OAAO,OAAO;IAoBC;IAnBF,MAAM,CAAU;IAEjC,mDAAmD;IAC3C,SAAS,CAAY;IACrB,cAAc,CAAS;IAEvB,UAAU,CAAS;IAE3B,uFAAuF;IACvF,yDAAyD;IACjD,SAAS,CAAO;IACxB,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,YACE,MAAe,EACf,UAAkB,EAClB,QAAc,EACG,YAAoB;QAApB,iBAAY,GAAZ,YAAY,CAAQ;QAErC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAE1B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IAC1B,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC;IAClD,CAAC;IAEM,KAAK,CAAC,SAAS,CACpB,UAAmC,EAAE;QAErC,OAAO,aAAa,CAAC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;YACnF,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;gBACjE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzC,CAAC;YAED,IAAI,KAAK,GAAoC,SAAS,CAAC;YACvD,OAAO,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC7C,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;oBACpC,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,4BAA4B;oBAC1F,SAAS;gBACX,CAAC;gBAED,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAClD,KAAK,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC;oBACnC,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,cAAc,EAAE,cAAc,CAAC,cAAc;iBAC9C,CAAC,CAAC;gBAEH,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;oBACvC,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,CAAC;gBACD,0BAA0B;gBAC1B,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;YAC/D,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,SAAS;QACd,MAAM,YAAY,GAAkB,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,WAAW,EAAE,CAAC;gBAChB,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,YAAY,EAAE,YAAY;YAC1B,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,SAAS;SACzD,CAAC;IACJ,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { BlobChangeFeedEvent } from \"./models/BlobChangeFeedEvent.js\";\nimport type { Shard } from \"./Shard.js\";\nimport type { SegmentCursor, ShardCursor } from \"./models/ChangeFeedCursor.js\";\nimport type { CommonOptions } from \"@azure/storage-blob\";\nimport type { AbortSignalLike } from \"@azure/abort-controller\";\nimport { tracingClient } from \"./utils/tracing.js\";\n\n/**\n * Options to configure {@link Segment.getChange} operation.\n */\nexport interface SegmentGetChangeOptions extends CommonOptions {\n /**\n * An implementation of the `AbortSignalLike` interface to signal the request to cancel the operation.\n * For example, use the @azure/abort-controller to create an `AbortSignal`.\n */\n abortSignal?: AbortSignalLike;\n}\n\nexport class Segment {\n private readonly shards: Shard[];\n\n // Track shards that we have finished reading from.\n private shardDone: boolean[];\n private shardDoneCount: number;\n\n private shardIndex: number;\n\n // Assuming the dateTime of segments is rounded to hour. If not, our logic for fetching\n // change events between a time range would be incorrect.\n private _dateTime: Date;\n public get dateTime(): Date {\n return this._dateTime;\n }\n\n constructor(\n shards: Shard[],\n shardIndex: number,\n dateTime: Date,\n private readonly manifestPath: string,\n ) {\n this.shards = shards;\n this.shardIndex = shardIndex;\n this._dateTime = dateTime;\n\n this.shardDone = Array(shards.length).fill(false);\n this.shardDoneCount = 0;\n }\n\n public hasNext(): boolean {\n return this.shards.length > this.shardDoneCount;\n }\n\n public async getChange(\n options: SegmentGetChangeOptions = {},\n ): Promise<BlobChangeFeedEvent | undefined> {\n return tracingClient.withSpan(\"Segment-getChange\", options, async (updatedOptions) => {\n if (this.shardIndex >= this.shards.length || this.shardIndex < 0) {\n throw new Error(\"shardIndex invalid.\");\n }\n\n let event: BlobChangeFeedEvent | undefined = undefined;\n while (event === undefined && this.hasNext()) {\n if (this.shardDone[this.shardIndex]) {\n this.shardIndex = (this.shardIndex + 1) % this.shards.length; // find next available shard\n continue;\n }\n\n const currentShard = this.shards[this.shardIndex];\n event = await currentShard.getChange({\n abortSignal: options.abortSignal,\n tracingOptions: updatedOptions.tracingOptions,\n });\n\n if (!currentShard.hasNext()) {\n this.shardDone[this.shardIndex] = true;\n this.shardDoneCount++;\n }\n // Round robin with shards\n this.shardIndex = (this.shardIndex + 1) % this.shards.length;\n }\n return event;\n });\n }\n\n public getCursor(): SegmentCursor {\n const shardCursors: ShardCursor[] = [];\n for (const shard of this.shards) {\n const shardCursor = shard.getCursor();\n if (shardCursor) {\n shardCursors.push(shardCursor);\n }\n }\n\n return {\n SegmentPath: this.manifestPath,\n ShardCursors: shardCursors,\n CurrentShardPath: this.shards[this.shardIndex].shardPath,\n };\n }\n}\n"]}
|
|
@@ -6,6 +6,7 @@ import { bodyToString } from "./utils/utils.node.js";
|
|
|
6
6
|
import { parseDateFromSegmentPath } from "./utils/utils.common.js";
|
|
7
7
|
import { tracingClient } from "./utils/tracing.js";
|
|
8
8
|
export class SegmentFactory {
|
|
9
|
+
shardFactory;
|
|
9
10
|
constructor(shardFactory) {
|
|
10
11
|
this.shardFactory = shardFactory;
|
|
11
12
|
}
|
|
@@ -23,7 +24,7 @@ export class SegmentFactory {
|
|
|
23
24
|
const containerPrefixLength = CHANGE_FEED_CONTAINER_NAME.length + 1; // "$blobchangefeed/"
|
|
24
25
|
for (const shardPath of segmentManifest.chunkFilePaths) {
|
|
25
26
|
const shardPathSubStr = shardPath.substring(containerPrefixLength);
|
|
26
|
-
const shardCursor = cursor
|
|
27
|
+
const shardCursor = cursor?.ShardCursors.find((x) => x.CurrentChunkPath.startsWith(shardPathSubStr));
|
|
27
28
|
const shard = await this.shardFactory.create(containerClient, shardPathSubStr, shardCursor, {
|
|
28
29
|
abortSignal: options.abortSignal,
|
|
29
30
|
tracingOptions: updatedOptions.tracingOptions,
|
|
@@ -33,8 +34,8 @@ export class SegmentFactory {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
let shardIndex = 0;
|
|
36
|
-
if (cursor
|
|
37
|
-
shardIndex = shards.findIndex((s) => s.shardPath ===
|
|
37
|
+
if (cursor?.CurrentShardPath) {
|
|
38
|
+
shardIndex = shards.findIndex((s) => s.shardPath === cursor?.CurrentShardPath);
|
|
38
39
|
if (shardIndex === -1) {
|
|
39
40
|
shardIndex = 0;
|
|
40
41
|
}
|