azure-mock 2.35.0 → 2.37.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/README.md +17 -10
- package/dist/index.d.ts +65 -45
- package/dist/index.js +226 -192
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[![NPM downloads][badge-npm-downloads]][url-npm]
|
|
6
6
|
[![NPM Unpacked Size (with version)][badge-npm-unpacked-size]][url-npm]
|
|
7
7
|
|
|
8
|
-
Mock Azure service classes for local development and testing. Provides in-memory implementations of Azure Table Storage, Blob Storage,
|
|
8
|
+
Mock Azure service classes for local development and testing. Provides in-memory implementations of Azure Table Storage, Blob Storage, Service Bus, and EventGrid clients that mirror the real Azure SDK interfaces.
|
|
9
9
|
|
|
10
10
|
## Table of Contents
|
|
11
11
|
|
|
@@ -18,22 +18,29 @@ Mock Azure service classes for local development and testing. Provides in-memory
|
|
|
18
18
|
## <a name="getting-started">🚀 Getting Started</a>
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
pnpm i -D azure-mock @azure/core-http-compat @azure/core-rest-pipeline @azure/data-tables @azure/eventgrid @azure/service-bus @azure/storage-blob
|
|
21
|
+
pnpm i -D azure-mock @azure/core-http-compat @azure/core-rest-pipeline @azure/data-tables @azure/eventgrid @azure/service-bus @azure/storage-blob
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## <a name="documentation">📖 Documentation</a>
|
|
25
25
|
|
|
26
|
-
We highly recommend you take a look at the [documentation](https://esposter.com/docs/modules/azure-mock.html) to level up.
|
|
26
|
+
We highly recommend you take a look at the [documentation](https://esposter.com/docs/api/modules/azure-mock.html) to level up.
|
|
27
27
|
|
|
28
28
|
### Available Mocks
|
|
29
29
|
|
|
30
|
-
| Class | Azure Equivalent | Description
|
|
31
|
-
| ------------------------------ | -------------------------- |
|
|
32
|
-
| `MockTableClient` | `TableClient` | In-memory Azure Table Storage
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
30
|
+
| Class | Azure Equivalent | Description |
|
|
31
|
+
| ------------------------------ | -------------------------- | -------------------------------------------- |
|
|
32
|
+
| `MockTableClient` | `TableClient` | In-memory Azure Table Storage |
|
|
33
|
+
| `MockContainerClient` | `ContainerClient` | In-memory blob container, listing and paging |
|
|
34
|
+
| `MockBlobClient` | `BlobClient` | In-memory blob read, copy and delete |
|
|
35
|
+
| `MockBlockBlobClient` | `BlockBlobClient` | In-memory block blob upload and download |
|
|
36
|
+
| `MockBlobBatchClient` | `BlobBatchClient` | In-memory batched blob deletion |
|
|
37
|
+
| `MockSearchClient` | `SearchClient` | In-memory Azure AI Search index |
|
|
38
|
+
| `MockQueueClient` | `QueueClient` | In-memory Azure Storage Queue |
|
|
39
|
+
| `MockServiceBusSender` | `ServiceBusSender` | In-memory Azure Service Bus |
|
|
40
|
+
| `MockWebPubSubServiceClient` | `WebPubSubServiceClient` | In-memory Azure Web PubSub |
|
|
41
|
+
| `MockEventGridPublisherClient` | `EventGridPublisherClient` | In-memory EventGrid publisher |
|
|
42
|
+
|
|
43
|
+
Each client's state lives in an exported `Mock*Database` map (`MockTableDatabase`, `MockContainerDatabase`, …), so a test resets by clearing the one it seeded.
|
|
37
44
|
|
|
38
45
|
### Usage
|
|
39
46
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
|
+
import { PipelineRequest, RestError } from "@azure/core-rest-pipeline";
|
|
1
2
|
import { HttpHeadersLike, WebResourceLike } from "@azure/core-http-compat";
|
|
2
3
|
import { MapValue } from "@esposter/shared";
|
|
3
|
-
import {
|
|
4
|
-
import { AnonymousCredential, AppendBlobClient, BlobAbortCopyFromURLResponse, BlobBatchClient, BlobBatchDeleteBlobsResponse, BlobBeginCopyFromURLResponse, BlobClient, BlobCopyFromURLResponse, BlobCreateSnapshotResponse, BlobDeleteIfExistsResponse, BlobDeleteImmutabilityPolicyResponse, BlobDeleteOptions, BlobDeleteResponse, BlobDownloadResponseModel, BlobDownloadResponseParsed, BlobGenerateSasUrlOptions, BlobGetAccountInfoResponse, BlobGetPropertiesResponse, BlobGetTagsResponse, BlobItem, BlobLeaseClient, BlobPrefix, BlobSetHTTPHeadersResponse, BlobSetImmutabilityPolicyResponse, BlobSetLegalHoldResponse, BlobSetMetadataResponse, BlobSetTagsResponse, BlobSetTierResponse, BlobUndeleteResponse, BlobUploadCommonResponse, BlockBlobClient, BlockBlobCommitBlockListResponse, BlockBlobGetBlockListResponse, BlockBlobPutBlobFromUrlResponse, BlockBlobStageBlockFromURLResponse, BlockBlobStageBlockResponse, BlockBlobUploadResponse, ContainerClient, ContainerCreateIfNotExistsResponse, ContainerCreateResponse, ContainerDeleteIfExistsResponse, ContainerDeleteResponse, ContainerFindBlobsByTagsSegmentResponse, ContainerGenerateSasUrlOptions, ContainerGetAccessPolicyResponse, ContainerGetAccountInfoResponse, ContainerGetPropertiesResponse, ContainerListBlobFlatSegmentResponse, ContainerListBlobHierarchySegmentResponse, ContainerListBlobsOptions, ContainerSetAccessPolicyResponse, ContainerSetMetadataResponse, FilterBlobItem, HttpRequestBody, PageBlobClient, PollOperationState, PollerLikeWithCancellation, StorageSharedKeyCredential } from "@azure/storage-blob";
|
|
4
|
+
import { AnonymousCredential, AppendBlobClient, BlobAbortCopyFromURLResponse, BlobBatchClient, BlobBatchDeleteBlobsResponse, BlobBeginCopyFromURLResponse, BlobClient, BlobCopyFromURLResponse, BlobCreateSnapshotResponse, BlobDeleteIfExistsResponse, BlobDeleteImmutabilityPolicyResponse, BlobDeleteOptions, BlobDeleteResponse, BlobDownloadResponseModel, BlobDownloadResponseParsed, BlobGenerateSasUrlOptions, BlobGetAccountInfoResponse, BlobGetPropertiesResponse, BlobGetTagsResponse, BlobHierarchyListSegment, BlobItem, BlobLeaseClient, BlobPrefix, BlobSetHTTPHeadersResponse, BlobSetImmutabilityPolicyResponse, BlobSetLegalHoldResponse, BlobSetMetadataResponse, BlobSetTagsResponse, BlobSetTierResponse, BlobUndeleteResponse, BlobUploadCommonResponse, BlockBlobClient, BlockBlobCommitBlockListResponse, BlockBlobGetBlockListResponse, BlockBlobPutBlobFromUrlResponse, BlockBlobStageBlockFromURLResponse, BlockBlobStageBlockResponse, BlockBlobUploadOptions, BlockBlobUploadResponse, ContainerClient, ContainerCreateIfNotExistsResponse, ContainerCreateResponse, ContainerDeleteIfExistsResponse, ContainerDeleteResponse, ContainerFindBlobsByTagsSegmentResponse, ContainerGenerateSasUrlOptions, ContainerGetAccessPolicyResponse, ContainerGetAccountInfoResponse, ContainerGetPropertiesResponse, ContainerListBlobFlatSegmentResponse, ContainerListBlobHierarchySegmentResponse, ContainerListBlobsOptions, ContainerSetAccessPolicyResponse, ContainerSetMetadataResponse, FilterBlobItem, HttpRequestBody, PageBlobClient, PollOperationState, PollerLikeWithCancellation, StorageSharedKeyCredential } from "@azure/storage-blob";
|
|
5
5
|
import { BinaryOperator, Clause } from "@esposter/db-schema";
|
|
6
6
|
import { EventGridEvent, EventGridPublisherClient } from "@azure/eventgrid";
|
|
7
7
|
import { ServiceBusMessage, ServiceBusMessageBatch, ServiceBusSender } from "@azure/service-bus";
|
|
8
8
|
import { CreateTableEntityResponse, GetAccessPolicyResponse, GetTableEntityResponse, ListTableEntitiesOptions, TableClient, TableDeleteEntityHeaders, TableEntity, TableEntityResult, TableEntityResultPage, TableMergeEntityHeaders, TableSetAccessPolicyHeaders, TableTransactionResponse, UpdateMode } from "@azure/data-tables";
|
|
9
9
|
import { QueueClearMessagesResponse, QueueClient, QueueCreateIfNotExistsResponse, QueueCreateOptions, QueueCreateResponse, QueueDeleteIfExistsResponse, QueueDeleteMessageResponse, QueueDeleteResponse, QueueGenerateSasUrlOptions, QueueGetAccessPolicyResponse, QueueGetPropertiesResponse, QueueItem, QueuePeekMessagesOptions, QueuePeekMessagesResponse, QueueReceiveMessageOptions, QueueReceiveMessageResponse, QueueSendMessageOptions, QueueSendMessageResponse, QueueServiceProperties, QueueSetAccessPolicyResponse, QueueSetMetadataResponse, QueueUpdateMessageResponse, SignedIdentifier } from "@azure/storage-queue";
|
|
10
10
|
import { AutocompleteResult, CountDocumentsOptions, DeleteDocumentsOptions, GetDocumentOptions, IndexDocumentsBatch, IndexDocumentsOptions, IndexDocumentsResult, MergeDocumentsOptions, MergeOrUploadDocumentsOptions, NarrowedModel, SearchClient, SearchDocumentsResult, SearchOptions, SelectFields, SuggestDocumentsResult, SuggestOptions, UploadDocumentsOptions } from "@azure/search-documents";
|
|
11
|
-
declare const
|
|
12
|
-
declare const
|
|
13
|
-
declare const
|
|
14
|
-
declare const
|
|
15
|
-
|
|
11
|
+
export declare const BLOB_NOT_FOUND_ERROR_CODE = "BlobNotFound";
|
|
12
|
+
export declare const BLOB_NOT_FOUND_MESSAGE = "The specified blob does not exist.";
|
|
13
|
+
export declare const MOCK_BLOB_BASE_URL = "https://mockaccount.blob.core.windows.net";
|
|
14
|
+
export declare const MOCK_QUEUE_BASE_URL = "https://mockaccount.queue.core.windows.net";
|
|
15
|
+
export declare const MOCK_SEARCH_BASE_URL = "https://mockaccount.search.windows.net";
|
|
16
|
+
export declare const MOCK_TABLE_BASE_URL = "https://mockaccount.table.core.windows.net";
|
|
17
|
+
export interface MockResponse {
|
|
16
18
|
headers: HttpHeadersLike;
|
|
17
19
|
parsedHeaders: Record<string, never>;
|
|
18
20
|
request: WebResourceLike;
|
|
19
21
|
status: number;
|
|
20
22
|
}
|
|
21
|
-
declare class MockRestError extends
|
|
22
|
-
statusCode: number;
|
|
23
|
+
export declare class MockRestError extends RestError {
|
|
23
24
|
constructor(message: string, statusCode: number);
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* An interface that tracks the settings for paged iteration
|
|
27
28
|
*/
|
|
28
|
-
interface PageSettings {
|
|
29
|
+
export interface PageSettings {
|
|
29
30
|
/**
|
|
30
31
|
* The token that keeps track of where to continue the iterator
|
|
31
32
|
*/
|
|
@@ -38,7 +39,7 @@ interface PageSettings {
|
|
|
38
39
|
/**
|
|
39
40
|
* An interface that allows async iterable iteration both to completion and by page.
|
|
40
41
|
*/
|
|
41
|
-
interface PagedAsyncIterableIterator<TElement, TPage = TElement[], TPageSettings = PageSettings> {
|
|
42
|
+
export interface PagedAsyncIterableIterator<TElement, TPage = TElement[], TPageSettings = PageSettings> {
|
|
42
43
|
/**
|
|
43
44
|
* The connection to the async iterator, part of the iteration protocol
|
|
44
45
|
*/
|
|
@@ -52,22 +53,26 @@ interface PagedAsyncIterableIterator<TElement, TPage = TElement[], TPageSettings
|
|
|
52
53
|
*/
|
|
53
54
|
next: () => Promise<IteratorResult<TElement>>;
|
|
54
55
|
}
|
|
55
|
-
declare const createMockResponse: (status: number, url?: string) => MockResponse;
|
|
56
|
-
declare const getMockSasUrl: (url: string, permissions: undefined | {
|
|
56
|
+
export declare const createMockResponse: (status: number, url?: string) => MockResponse;
|
|
57
|
+
export declare const getMockSasUrl: (url: string, permissions: undefined | {
|
|
57
58
|
toString: () => string;
|
|
58
59
|
}, resourceType?: string) => string;
|
|
59
|
-
declare const
|
|
60
|
-
declare const
|
|
61
|
-
declare const
|
|
62
|
-
declare const
|
|
63
|
-
declare const
|
|
64
|
-
declare const
|
|
65
|
-
|
|
60
|
+
export declare const MockContainerCreatedOnDatabase: Map<string, Date>;
|
|
61
|
+
export declare const MOCK_BLOB_SEEDED_CREATED_ON: Date;
|
|
62
|
+
export declare const getMockContainerCreatedOnKey: (containerName: string, blobName: string) => string;
|
|
63
|
+
export declare const MockContainerDatabase: Map<string, Map<string, Buffer>>;
|
|
64
|
+
export declare const MockEventGridDatabase: Map<string, EventGridEvent<unknown>[]>;
|
|
65
|
+
export declare const MockQueueDatabase: Map<string, string[]>;
|
|
66
|
+
export declare const MockSearchDatabase: Map<string, object[]>;
|
|
67
|
+
export declare const MockServiceBusDatabase: Map<string, ServiceBusMessage[]>;
|
|
68
|
+
export declare const MockTableDatabase: Map<string, Map<string, TableEntity>>;
|
|
69
|
+
export type BlobHierarchyItem = (BlobItem & {
|
|
66
70
|
kind: "blob";
|
|
67
71
|
}) | (BlobPrefix & {
|
|
68
72
|
kind: "prefix";
|
|
69
73
|
});
|
|
70
|
-
declare class MockBlobBatchClient implements BlobBatchClient {
|
|
74
|
+
export declare class MockBlobBatchClient implements BlobBatchClient {
|
|
75
|
+
#private;
|
|
71
76
|
url: string;
|
|
72
77
|
constructor(url: string);
|
|
73
78
|
/**
|
|
@@ -812,7 +817,7 @@ type PostPayloadFixed = Except<UserData, 'email'>;
|
|
|
812
817
|
*/
|
|
813
818
|
type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {}> = _Except<ObjectType, KeysType, ApplyDefaultOptions<ExceptOptions, DefaultExceptOptions, Options>>;
|
|
814
819
|
type _Except<ObjectType, KeysType extends keyof ObjectType, Options extends Required<ExceptOptions>> = { [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType]; } & (Options['requireExactProps'] extends true ? Partial<Record<KeysType, never>> : {});
|
|
815
|
-
declare class MockBlobClient implements Except<BlobClient, "accountName"> {
|
|
820
|
+
export declare class MockBlobClient implements Except<BlobClient, "accountName"> {
|
|
816
821
|
connectionString: string;
|
|
817
822
|
containerName: string;
|
|
818
823
|
credential: AnonymousCredential;
|
|
@@ -852,14 +857,14 @@ declare class MockBlobClient implements Except<BlobClient, "accountName"> {
|
|
|
852
857
|
withSnapshot(): BlockBlobClient;
|
|
853
858
|
withVersion(): BlobClient;
|
|
854
859
|
}
|
|
855
|
-
declare class MockBlockBlobClient extends MockBlobClient implements Except<BlockBlobClient, "accountName"> {
|
|
860
|
+
export declare class MockBlockBlobClient extends MockBlobClient implements Except<BlockBlobClient, "accountName"> {
|
|
856
861
|
commitBlockList(): Promise<BlockBlobCommitBlockListResponse>;
|
|
857
862
|
getBlockList(): Promise<BlockBlobGetBlockListResponse>;
|
|
858
863
|
query(): Promise<BlobDownloadResponseModel>;
|
|
859
864
|
stageBlock(): Promise<BlockBlobStageBlockResponse>;
|
|
860
865
|
stageBlockFromURL(): Promise<BlockBlobStageBlockFromURLResponse>;
|
|
861
866
|
syncUploadFromURL(): Promise<BlockBlobPutBlobFromUrlResponse>;
|
|
862
|
-
upload(body: HttpRequestBody, _contentLength: number): Promise<BlockBlobUploadResponse>;
|
|
867
|
+
upload(body: HttpRequestBody, _contentLength: number, options?: BlockBlobUploadOptions): Promise<BlockBlobUploadResponse>;
|
|
863
868
|
uploadBrowserData(): Promise<BlobUploadCommonResponse>;
|
|
864
869
|
uploadData(): Promise<BlobUploadCommonResponse>;
|
|
865
870
|
uploadFile(): Promise<BlobUploadCommonResponse>;
|
|
@@ -875,7 +880,7 @@ declare class MockBlockBlobClient extends MockBlobClient implements Except<Block
|
|
|
875
880
|
* await blockBlobClient.upload("hello world", 11);
|
|
876
881
|
* const content = await blockBlobClient.downloadToBuffer();
|
|
877
882
|
*/
|
|
878
|
-
declare class MockContainerClient implements Except<ContainerClient, "accountName"> {
|
|
883
|
+
export declare class MockContainerClient implements Except<ContainerClient, "accountName"> {
|
|
879
884
|
#private;
|
|
880
885
|
connectionString: string;
|
|
881
886
|
containerName: string;
|
|
@@ -904,7 +909,7 @@ declare class MockContainerClient implements Except<ContainerClient, "accountNam
|
|
|
904
909
|
getPageBlobClient(): PageBlobClient;
|
|
905
910
|
getProperties(): Promise<ContainerGetPropertiesResponse>;
|
|
906
911
|
listBlobsByHierarchy(delimiter: string, options?: ContainerListBlobsOptions): PagedAsyncIterableIterator<BlobHierarchyItem, ContainerListBlobHierarchySegmentResponse>;
|
|
907
|
-
listBlobsFlat(): PagedAsyncIterableIterator<BlobItem, ContainerListBlobFlatSegmentResponse>;
|
|
912
|
+
listBlobsFlat(options?: ContainerListBlobsOptions): PagedAsyncIterableIterator<BlobItem, ContainerListBlobFlatSegmentResponse>;
|
|
908
913
|
setAccessPolicy(): Promise<ContainerSetAccessPolicyResponse>;
|
|
909
914
|
setMetadata(): Promise<ContainerSetMetadataResponse>;
|
|
910
915
|
uploadBlockBlob(blobName: string, body: HttpRequestBody, contentLength: number): Promise<{
|
|
@@ -917,7 +922,7 @@ declare class MockContainerClient implements Except<ContainerClient, "accountNam
|
|
|
917
922
|
* It uses a Map to simulate event grid storage and correctly implements the EventGridPublisherClient interface.
|
|
918
923
|
* `client` is excluded because it is a private member of the real class and cannot be satisfied structurally.
|
|
919
924
|
*/
|
|
920
|
-
declare class MockEventGridPublisherClient implements Except<EventGridPublisherClient<"EventGrid">, "apiVersion"> {
|
|
925
|
+
export declare class MockEventGridPublisherClient implements Except<EventGridPublisherClient<"EventGrid">, "apiVersion"> {
|
|
921
926
|
readonly endpointUrl: string;
|
|
922
927
|
readonly inputSchema: "EventGrid";
|
|
923
928
|
readonly topicType: "EventGrid";
|
|
@@ -934,7 +939,7 @@ declare class MockEventGridPublisherClient implements Except<EventGridPublisherC
|
|
|
934
939
|
* await mockQueueClient.sendMessage("hello world");
|
|
935
940
|
* const messages = await mockQueueClient.peekMessages();
|
|
936
941
|
*/
|
|
937
|
-
declare class MockQueueClient implements Except<QueueClient, "accountName"> {
|
|
942
|
+
export declare class MockQueueClient implements Except<QueueClient, "accountName"> {
|
|
938
943
|
connectionString: string;
|
|
939
944
|
name: string;
|
|
940
945
|
url: string;
|
|
@@ -971,7 +976,7 @@ declare class MockQueueClient implements Except<QueueClient, "accountName"> {
|
|
|
971
976
|
* await mockSearchClient.uploadDocuments([{ ... }]);
|
|
972
977
|
* const { count, results } = await mockSearchClient.search("*", { filter, includeTotalCount: true });
|
|
973
978
|
*/
|
|
974
|
-
declare class MockSearchClient<TModel extends object = Record<string, unknown>> implements Except<SearchClient<TModel>, "pipeline"> {
|
|
979
|
+
export declare class MockSearchClient<TModel extends object = Record<string, unknown>> implements Except<SearchClient<TModel>, "pipeline"> {
|
|
975
980
|
readonly apiVersion: string;
|
|
976
981
|
readonly endpoint: string;
|
|
977
982
|
readonly indexName: string;
|
|
@@ -998,7 +1003,7 @@ declare class MockSearchClient<TModel extends object = Record<string, unknown>>
|
|
|
998
1003
|
* const mockServiceBusSender = new MockServiceBusSender("hello world");
|
|
999
1004
|
* await mockServiceBusSender.scheduleMessages({ body: "hello world" }, new Date());
|
|
1000
1005
|
*/
|
|
1001
|
-
declare class MockServiceBusSender implements ServiceBusSender {
|
|
1006
|
+
export declare class MockServiceBusSender implements ServiceBusSender {
|
|
1002
1007
|
entityPath: string;
|
|
1003
1008
|
identifier: string;
|
|
1004
1009
|
isClosed: boolean;
|
|
@@ -1019,7 +1024,7 @@ declare class MockServiceBusSender implements ServiceBusSender {
|
|
|
1019
1024
|
* await mockTableClient.createEntity({ partitionKey: "partitionKey", rowKey: "rowKey" });
|
|
1020
1025
|
* const entity = await mockTableClient.getEntity("partitionKey", "rowKey");
|
|
1021
1026
|
*/
|
|
1022
|
-
declare class MockTableClient<TEntity extends TableEntity = TableEntity> implements Except<TableClient, "pipeline"> {
|
|
1027
|
+
export declare class MockTableClient<TEntity extends TableEntity = TableEntity> implements Except<TableClient, "pipeline"> {
|
|
1023
1028
|
#private;
|
|
1024
1029
|
entityType: TEntity;
|
|
1025
1030
|
tableName: string;
|
|
@@ -1035,39 +1040,54 @@ declare class MockTableClient<TEntity extends TableEntity = TableEntity> impleme
|
|
|
1035
1040
|
listEntities<T extends object>(options?: ListTableEntitiesOptions): PagedAsyncIterableIterator<TableEntityResult<T>, TableEntityResultPage<T>>;
|
|
1036
1041
|
setAccessPolicy(): Promise<TableSetAccessPolicyHeaders>;
|
|
1037
1042
|
submitTransaction(actions: Parameters<TableClient["submitTransaction"]>[0]): Promise<TableTransactionResponse>;
|
|
1038
|
-
updateEntity<T extends object>(entity: TableEntity<T>, mode?: UpdateMode
|
|
1043
|
+
updateEntity<T extends object>(entity: TableEntity<T>, mode?: UpdateMode, options?: {
|
|
1044
|
+
etag?: string;
|
|
1045
|
+
}): Promise<TableMergeEntityHeaders>;
|
|
1039
1046
|
upsertEntity<T extends object>(entity: TableEntity<T>, mode?: UpdateMode): Promise<TableMergeEntityHeaders>;
|
|
1040
1047
|
}
|
|
1041
1048
|
/**
|
|
1042
1049
|
* A minimal mock of the Azure WebPubSubServiceClient for testing purposes.
|
|
1043
1050
|
* Only implements `group().sendToAll` — the only method used in azure-functions tests.
|
|
1044
1051
|
*/
|
|
1045
|
-
declare class MockWebPubSubServiceClient {
|
|
1052
|
+
export declare class MockWebPubSubServiceClient {
|
|
1046
1053
|
group(_groupName: string): {
|
|
1047
1054
|
sendToAll: () => Promise<void>;
|
|
1048
1055
|
};
|
|
1049
1056
|
}
|
|
1050
|
-
declare const bodyToBuffer: (body: HttpRequestBody) => Promise<Buffer>;
|
|
1057
|
+
export declare const bodyToBuffer: (body: HttpRequestBody) => Promise<Buffer>;
|
|
1051
1058
|
/**
|
|
1052
1059
|
* Generates a standard Azure Storage error XML response body.
|
|
1053
1060
|
* @param errorCode The official Azure error code (e.g., "BlobNotFound").
|
|
1054
1061
|
* @param errorMessage The user-friendly error message.
|
|
1055
1062
|
* @returns A formatted XML string.
|
|
1056
1063
|
*/
|
|
1057
|
-
declare const getAzureErrorXml: (errorCode: string, errorMessage: string) => string;
|
|
1058
|
-
declare const getBlobItemXml: ({ name, properties }: BlobItem) => string;
|
|
1059
|
-
declare const getBlobPrefixXml: (name: string) => string;
|
|
1064
|
+
export declare const getAzureErrorXml: (errorCode: string, errorMessage: string) => string;
|
|
1065
|
+
export declare const getBlobItemXml: ({ name, properties }: BlobItem) => string;
|
|
1066
|
+
export declare const getBlobPrefixXml: (name: string) => string;
|
|
1067
|
+
export declare const getBlobUrl: (containerName: string, blobName: string) => string;
|
|
1068
|
+
export declare const getBlobUrlParts: (url: string) => undefined | {
|
|
1069
|
+
blobName: string;
|
|
1070
|
+
containerName: string;
|
|
1071
|
+
};
|
|
1072
|
+
export declare const getListBlobsSegmentResponse: (containerName: string, prefix: string, segment: BlobHierarchyListSegment, blobsXml: string) => ContainerListBlobHierarchySegmentResponse;
|
|
1060
1073
|
/**
|
|
1061
1074
|
* Generates a standard Azure Storage list blobs XML response body.
|
|
1062
1075
|
* @param containerName The container name.
|
|
1063
1076
|
* @param blobsXml The blobs xml data.
|
|
1064
1077
|
* @returns A formatted XML string.
|
|
1065
1078
|
*/
|
|
1066
|
-
declare const getListBlobsXml: (containerName: string, blobsXml: string) => string;
|
|
1067
|
-
declare const
|
|
1068
|
-
declare const
|
|
1069
|
-
declare const
|
|
1070
|
-
declare const
|
|
1071
|
-
declare const
|
|
1072
|
-
declare const
|
|
1073
|
-
export
|
|
1079
|
+
export declare const getListBlobsXml: (containerName: string, blobsXml: string) => string;
|
|
1080
|
+
export declare const getMockContainer: (containerName: string) => MapValue<typeof MockContainerDatabase>;
|
|
1081
|
+
export declare const isReadableStream: (value: unknown) => value is NodeJS.ReadableStream;
|
|
1082
|
+
export declare const toWebResourceLike: (request: PipelineRequest) => WebResourceLike;
|
|
1083
|
+
export declare const applyFilter: <T extends Record<string, unknown>>(documents: T[], clauses: Clause<T>[]) => T[];
|
|
1084
|
+
export declare const compare: <T>(operator: BinaryOperator, leftHandSide: T, rightHandSide: null | T) => boolean;
|
|
1085
|
+
export declare const createFilterPredicate: (filter: string) => ((document: Record<string, unknown>) => boolean);
|
|
1086
|
+
export declare const isNullClause: (clause: Clause<Record<string, unknown>>) => boolean;
|
|
1087
|
+
export declare const getMockQueueMessageItem: (messageText: string) => {
|
|
1088
|
+
expiresOn: Date;
|
|
1089
|
+
insertedOn: Date;
|
|
1090
|
+
messageId: string;
|
|
1091
|
+
messageText: string;
|
|
1092
|
+
};
|
|
1093
|
+
export declare const compareByCompositeKey: (a: TableEntity, b: TableEntity) => number;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { RestError, createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
1
2
|
import { toHttpHeadersLike } from "@azure/core-http-compat";
|
|
2
|
-
import { ID_SEPARATOR, InvalidOperationError, Operation, exhaustiveGuard, getOrCreate,
|
|
3
|
-
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
|
|
3
|
+
import { ID_SEPARATOR, InvalidOperationError, Operation, chunk, exhaustiveGuard, getDecodedUriComponent, getOrCreate, getResult, html, noop, streamToText, takeOne } from "@esposter/shared";
|
|
4
4
|
import { AnonymousCredential } from "@azure/storage-blob";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { MAX_QUEUE_VISIBILITY_TIMEOUT_MS, deserializeClause, deserializeKey, getTableNullClause, serializeClauses } from "@esposter/db";
|
|
@@ -22,20 +22,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
22
22
|
}
|
|
23
23
|
return to;
|
|
24
24
|
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
26
26
|
value: mod,
|
|
27
27
|
enumerable: true
|
|
28
28
|
}) : target, mod));
|
|
29
|
+
const BLOB_NOT_FOUND_ERROR_CODE = "BlobNotFound";
|
|
30
|
+
const BLOB_NOT_FOUND_MESSAGE = "The specified blob does not exist.";
|
|
29
31
|
const MOCK_BLOB_BASE_URL = "https://mockaccount.blob.core.windows.net";
|
|
30
32
|
const MOCK_QUEUE_BASE_URL = "https://mockaccount.queue.core.windows.net";
|
|
31
33
|
const MOCK_SEARCH_BASE_URL = "https://mockaccount.search.windows.net";
|
|
32
34
|
const MOCK_TABLE_BASE_URL = "https://mockaccount.table.core.windows.net";
|
|
33
|
-
var MockRestError = class extends
|
|
34
|
-
statusCode;
|
|
35
|
+
var MockRestError = class extends RestError {
|
|
35
36
|
constructor(message, statusCode) {
|
|
36
|
-
super(message);
|
|
37
|
+
super(message, { statusCode });
|
|
37
38
|
this.name = "MockRestError";
|
|
38
|
-
this.statusCode = statusCode;
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
const toWebResourceLike = (request) => ({
|
|
@@ -70,7 +70,16 @@ const createMockResponse = (status, url = "") => ({
|
|
|
70
70
|
status
|
|
71
71
|
});
|
|
72
72
|
const getMockSasUrl = (url, permissions, resourceType) => `${url}?sv=2025-11-05&${resourceType ? `sr=${resourceType}&` : ""}sig=mock-signature&st=1970-01-01T00:00:00Z&se=2099-12-31T23:59:59Z&sp=${permissions?.toString() ?? "r"}`;
|
|
73
|
-
const
|
|
73
|
+
const MockContainerCreatedOnDatabase = /* @__PURE__ */ new Map();
|
|
74
|
+
const MOCK_BLOB_SEEDED_CREATED_ON = /* @__PURE__ */ new Date(-864e13);
|
|
75
|
+
const getMockContainerCreatedOnKey = (containerName, blobName) => `${containerName}/${blobName}`;
|
|
76
|
+
var MockContainerDatabaseMap = class extends Map {
|
|
77
|
+
clear() {
|
|
78
|
+
super.clear();
|
|
79
|
+
MockContainerCreatedOnDatabase.clear();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const MockContainerDatabase = new MockContainerDatabaseMap();
|
|
74
83
|
const MockEventGridDatabase = /* @__PURE__ */ new Map();
|
|
75
84
|
const MockQueueDatabase = /* @__PURE__ */ new Map();
|
|
76
85
|
const MockSearchDatabase = /* @__PURE__ */ new Map();
|
|
@@ -87,6 +96,18 @@ const getAzureErrorXml = (errorCode, errorMessage) => html`<?xml version="1.0" e
|
|
|
87
96
|
<code>${errorCode}</code>
|
|
88
97
|
<Message>${errorMessage}</Message>
|
|
89
98
|
</Error>`;
|
|
99
|
+
const decodeSegment = (segment) => getDecodedUriComponent(segment, segment);
|
|
100
|
+
const getBlobUrlParts = (url) => {
|
|
101
|
+
const parsedUrl = getResult(() => new URL(url)).unwrapOr(void 0);
|
|
102
|
+
if (!parsedUrl) return void 0;
|
|
103
|
+
const pathSegments = parsedUrl.pathname.split("/").filter(Boolean);
|
|
104
|
+
if (pathSegments.length < 2) return void 0;
|
|
105
|
+
return {
|
|
106
|
+
blobName: decodeSegment(pathSegments.slice(1).join("/")),
|
|
107
|
+
containerName: decodeSegment(takeOne(pathSegments))
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const getMockContainer = (containerName) => getOrCreate(MockContainerDatabase, containerName, () => /* @__PURE__ */ new Map());
|
|
90
111
|
var MockBlobBatchClient = class {
|
|
91
112
|
url;
|
|
92
113
|
constructor(url) {
|
|
@@ -103,29 +124,17 @@ var MockBlobBatchClient = class {
|
|
|
103
124
|
let subResponsesSucceededCount = 0;
|
|
104
125
|
let subResponsesFailedCount = 0;
|
|
105
126
|
for (const url of urls) {
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
const statusMessage = "Invalid blob URL format.";
|
|
110
|
-
subResponses.push({
|
|
111
|
-
_request: {
|
|
112
|
-
credential,
|
|
113
|
-
url: this.url
|
|
114
|
-
},
|
|
115
|
-
bodyAsText: getAzureErrorXml(errorCode, statusMessage),
|
|
116
|
-
errorCode,
|
|
117
|
-
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
118
|
-
status: 400,
|
|
119
|
-
statusMessage
|
|
120
|
-
});
|
|
127
|
+
const urlParts = getBlobUrlParts(url);
|
|
128
|
+
if (!urlParts) {
|
|
129
|
+
subResponses.push(this.#createFailedSubResponse(credential, 400, "InvalidUri", "Invalid blob URL format."));
|
|
121
130
|
subResponsesFailedCount++;
|
|
122
131
|
continue;
|
|
123
132
|
}
|
|
124
|
-
const containerName =
|
|
125
|
-
const blobName = pathSegments.slice(1).join("/");
|
|
133
|
+
const { blobName, containerName } = urlParts;
|
|
126
134
|
const container = this.getContainer(containerName);
|
|
127
135
|
if (container.has(blobName)) {
|
|
128
136
|
container.delete(blobName);
|
|
137
|
+
MockContainerCreatedOnDatabase.delete(getMockContainerCreatedOnKey(containerName, blobName));
|
|
129
138
|
subResponses.push({
|
|
130
139
|
_request: {
|
|
131
140
|
credential,
|
|
@@ -137,19 +146,7 @@ var MockBlobBatchClient = class {
|
|
|
137
146
|
});
|
|
138
147
|
subResponsesSucceededCount++;
|
|
139
148
|
} else {
|
|
140
|
-
|
|
141
|
-
const statusMessage = "The specified blob does not exist.";
|
|
142
|
-
subResponses.push({
|
|
143
|
-
_request: {
|
|
144
|
-
credential,
|
|
145
|
-
url: this.url
|
|
146
|
-
},
|
|
147
|
-
bodyAsText: getAzureErrorXml(errorCode, statusMessage),
|
|
148
|
-
errorCode,
|
|
149
|
-
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
150
|
-
status: 404,
|
|
151
|
-
statusMessage
|
|
152
|
-
});
|
|
149
|
+
subResponses.push(this.#createFailedSubResponse(credential, 404, BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE));
|
|
153
150
|
subResponsesFailedCount++;
|
|
154
151
|
}
|
|
155
152
|
}
|
|
@@ -167,9 +164,23 @@ var MockBlobBatchClient = class {
|
|
|
167
164
|
});
|
|
168
165
|
}
|
|
169
166
|
getContainer(containerName) {
|
|
170
|
-
return
|
|
167
|
+
return getMockContainer(containerName);
|
|
168
|
+
}
|
|
169
|
+
#createFailedSubResponse(credential, status, errorCode, statusMessage) {
|
|
170
|
+
return {
|
|
171
|
+
_request: {
|
|
172
|
+
credential,
|
|
173
|
+
url: this.url
|
|
174
|
+
},
|
|
175
|
+
bodyAsText: getAzureErrorXml(errorCode, statusMessage),
|
|
176
|
+
errorCode,
|
|
177
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
178
|
+
status,
|
|
179
|
+
statusMessage
|
|
180
|
+
};
|
|
171
181
|
}
|
|
172
182
|
};
|
|
183
|
+
const getBlobUrl = (containerName, blobName) => `${MOCK_BLOB_BASE_URL}/${containerName}/${blobName.split("/").map((segment) => encodeURIComponent(segment)).join("/")}`;
|
|
173
184
|
var MockBlobClient = class {
|
|
174
185
|
connectionString;
|
|
175
186
|
containerName;
|
|
@@ -177,27 +188,27 @@ var MockBlobClient = class {
|
|
|
177
188
|
name;
|
|
178
189
|
url;
|
|
179
190
|
get container() {
|
|
180
|
-
return
|
|
191
|
+
return getMockContainer(this.containerName);
|
|
181
192
|
}
|
|
182
193
|
constructor(connectionString, containerName, blobName) {
|
|
183
194
|
this.connectionString = connectionString;
|
|
184
195
|
this.containerName = containerName;
|
|
185
196
|
this.name = blobName;
|
|
186
|
-
this.url =
|
|
197
|
+
this.url = getBlobUrl(this.containerName, this.name);
|
|
187
198
|
}
|
|
188
199
|
abortCopyFromURL() {
|
|
189
200
|
throw new Error("Method not implemented.");
|
|
190
201
|
}
|
|
191
202
|
beginCopyFromURL(copySource) {
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
194
|
-
const sourceContainerName =
|
|
195
|
-
const sourceBlobName = pathSegments.slice(1).join("/");
|
|
203
|
+
const sourceParts = getBlobUrlParts(copySource);
|
|
204
|
+
if (!sourceParts) throw new MockRestError("Invalid copy source URL format", 400);
|
|
205
|
+
const { blobName: sourceBlobName, containerName: sourceContainerName } = sourceParts;
|
|
196
206
|
const sourceContainer = MockContainerDatabase.get(sourceContainerName);
|
|
197
207
|
if (!sourceContainer) throw new MockRestError("Source container not found", 404);
|
|
198
208
|
const sourceData = sourceContainer.get(sourceBlobName);
|
|
199
209
|
if (!sourceData) throw new MockRestError("Source blob not found", 404);
|
|
200
210
|
this.container.set(this.name, Buffer.from(sourceData));
|
|
211
|
+
MockContainerCreatedOnDatabase.set(getMockContainerCreatedOnKey(this.containerName, this.name), /* @__PURE__ */ new Date());
|
|
201
212
|
const response = { _response: createMockResponse(202, `${this.url}?comp=copy`) };
|
|
202
213
|
return Promise.resolve({
|
|
203
214
|
cancelOperation: () => Promise.resolve(),
|
|
@@ -218,13 +229,17 @@ var MockBlobClient = class {
|
|
|
218
229
|
throw new Error("Method not implemented.");
|
|
219
230
|
}
|
|
220
231
|
delete() {
|
|
221
|
-
if (!this.container.has(this.name)) throw new MockRestError(
|
|
232
|
+
if (!this.container.has(this.name)) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
|
|
222
233
|
this.container.delete(this.name);
|
|
234
|
+
MockContainerCreatedOnDatabase.delete(getMockContainerCreatedOnKey(this.containerName, this.name));
|
|
223
235
|
return Promise.resolve({ _response: createMockResponse(200) });
|
|
224
236
|
}
|
|
225
237
|
deleteIfExists() {
|
|
226
238
|
const succeeded = this.container.has(this.name);
|
|
227
|
-
if (succeeded)
|
|
239
|
+
if (succeeded) {
|
|
240
|
+
this.container.delete(this.name);
|
|
241
|
+
MockContainerCreatedOnDatabase.delete(getMockContainerCreatedOnKey(this.containerName, this.name));
|
|
242
|
+
}
|
|
228
243
|
return Promise.resolve({
|
|
229
244
|
_response: createMockResponse(succeeded ? 200 : 404),
|
|
230
245
|
succeeded
|
|
@@ -242,14 +257,14 @@ var MockBlobClient = class {
|
|
|
242
257
|
}
|
|
243
258
|
downloadToBuffer() {
|
|
244
259
|
const data = this.container.get(this.name);
|
|
245
|
-
if (!data) throw new MockRestError(
|
|
260
|
+
if (!data) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
|
|
246
261
|
return Promise.resolve(Buffer.from(data));
|
|
247
262
|
}
|
|
248
263
|
downloadToFile() {
|
|
249
264
|
throw new Error("Method not implemented.");
|
|
250
265
|
}
|
|
251
266
|
exists() {
|
|
252
|
-
|
|
267
|
+
return Promise.resolve(this.container.has(this.name));
|
|
253
268
|
}
|
|
254
269
|
generateSasStringToSign() {
|
|
255
270
|
throw new Error("Method not implemented.");
|
|
@@ -362,8 +377,11 @@ var MockBlockBlobClient = class extends MockBlobClient {
|
|
|
362
377
|
syncUploadFromURL() {
|
|
363
378
|
throw new Error("Method not implemented.");
|
|
364
379
|
}
|
|
365
|
-
async upload(body, _contentLength) {
|
|
366
|
-
|
|
380
|
+
async upload(body, _contentLength, options) {
|
|
381
|
+
const buffer = await bodyToBuffer(body);
|
|
382
|
+
if (options?.conditions?.ifNoneMatch === "*" && this.container.has(this.name)) throw new MockRestError("The specified blob already exists.", 409);
|
|
383
|
+
this.container.set(this.name, buffer);
|
|
384
|
+
MockContainerCreatedOnDatabase.set(getMockContainerCreatedOnKey(this.containerName, this.name), /* @__PURE__ */ new Date());
|
|
367
385
|
return { _response: createMockResponse(201) };
|
|
368
386
|
}
|
|
369
387
|
uploadBrowserData() {
|
|
@@ -403,6 +421,23 @@ const getListBlobsXml = (containerName, blobsXml) => html`<?xml version="1.0" en
|
|
|
403
421
|
<Blobs>${blobsXml}</Blobs>
|
|
404
422
|
<NextMarker />
|
|
405
423
|
</EnumerationResults>`;
|
|
424
|
+
const getListBlobsSegmentResponse = (containerName, prefix, segment, blobsXml) => {
|
|
425
|
+
const segmentResponse = {
|
|
426
|
+
containerName,
|
|
427
|
+
marker: "",
|
|
428
|
+
prefix,
|
|
429
|
+
segment,
|
|
430
|
+
serviceEndpoint: ""
|
|
431
|
+
};
|
|
432
|
+
return {
|
|
433
|
+
_response: {
|
|
434
|
+
...createMockResponse(200),
|
|
435
|
+
bodyAsText: getListBlobsXml(containerName, blobsXml),
|
|
436
|
+
parsedBody: segmentResponse
|
|
437
|
+
},
|
|
438
|
+
...segmentResponse
|
|
439
|
+
};
|
|
440
|
+
};
|
|
406
441
|
/**
|
|
407
442
|
* An in-memory mock of the Azure ContainerClient.
|
|
408
443
|
* It uses a Map to simulate blob storage.
|
|
@@ -419,7 +454,7 @@ var MockContainerClient = class {
|
|
|
419
454
|
credential = new AnonymousCredential();
|
|
420
455
|
url;
|
|
421
456
|
get container() {
|
|
422
|
-
return
|
|
457
|
+
return getMockContainer(this.containerName);
|
|
423
458
|
}
|
|
424
459
|
constructor(connectionString, containerName) {
|
|
425
460
|
this.connectionString = connectionString;
|
|
@@ -436,9 +471,10 @@ var MockContainerClient = class {
|
|
|
436
471
|
throw new Error("Method not implemented.");
|
|
437
472
|
}
|
|
438
473
|
deleteBlob(blobName) {
|
|
439
|
-
if (!this.container.has(blobName)) throw new MockRestError(
|
|
474
|
+
if (!this.container.has(blobName)) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
|
|
440
475
|
this.container.delete(blobName);
|
|
441
|
-
|
|
476
|
+
MockContainerCreatedOnDatabase.delete(getMockContainerCreatedOnKey(this.containerName, blobName));
|
|
477
|
+
return Promise.resolve({ _response: createMockResponse(200, getBlobUrl(this.containerName, blobName)) });
|
|
442
478
|
}
|
|
443
479
|
deleteIfExists() {
|
|
444
480
|
throw new Error("Method not implemented.");
|
|
@@ -503,24 +539,10 @@ var MockContainerClient = class {
|
|
|
503
539
|
allBlobPrefixes.push({ name: blobHierarchyItem.name });
|
|
504
540
|
allBlobPrefixXml.push(getBlobPrefixXml(blobHierarchyItem.name));
|
|
505
541
|
}
|
|
506
|
-
if (allBlobItems.length > 0 || allBlobPrefixes.length > 0) yield await Promise.resolve({
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
parsedBody: {
|
|
511
|
-
containerName: this.containerName,
|
|
512
|
-
marker: "",
|
|
513
|
-
prefix: options?.prefix ?? "",
|
|
514
|
-
segment: { blobItems: allBlobItems },
|
|
515
|
-
serviceEndpoint: ""
|
|
516
|
-
}
|
|
517
|
-
},
|
|
518
|
-
containerName: this.containerName,
|
|
519
|
-
marker: "",
|
|
520
|
-
prefix: options?.prefix ?? "",
|
|
521
|
-
segment: { blobItems: allBlobItems },
|
|
522
|
-
serviceEndpoint: ""
|
|
523
|
-
});
|
|
542
|
+
if (allBlobItems.length > 0 || allBlobPrefixes.length > 0) yield await Promise.resolve(getListBlobsSegmentResponse(this.containerName, options?.prefix ?? "", {
|
|
543
|
+
blobItems: allBlobItems,
|
|
544
|
+
blobPrefixes: allBlobPrefixes
|
|
545
|
+
}, `${allBlobItemXml.join("")}${allBlobPrefixXml.join("")}`));
|
|
524
546
|
}.bind(this)(),
|
|
525
547
|
next: blobHierarchyItemIterator.next.bind(blobHierarchyItemIterator),
|
|
526
548
|
[Symbol.asyncIterator]() {
|
|
@@ -528,8 +550,8 @@ var MockContainerClient = class {
|
|
|
528
550
|
}
|
|
529
551
|
};
|
|
530
552
|
}
|
|
531
|
-
listBlobsFlat() {
|
|
532
|
-
const blobItemIterator = this.#getBlobItemIterator();
|
|
553
|
+
listBlobsFlat(options) {
|
|
554
|
+
const blobItemIterator = this.#getBlobItemIterator(options);
|
|
533
555
|
return {
|
|
534
556
|
byPage: () => async function* () {
|
|
535
557
|
const allBlobItems = [];
|
|
@@ -538,24 +560,7 @@ var MockContainerClient = class {
|
|
|
538
560
|
allBlobItems.push(blobItem);
|
|
539
561
|
allBlobItemXml.push(getBlobItemXml(blobItem));
|
|
540
562
|
}
|
|
541
|
-
if (allBlobItems.length > 0) yield await Promise.resolve({
|
|
542
|
-
_response: {
|
|
543
|
-
...createMockResponse(200),
|
|
544
|
-
bodyAsText: getListBlobsXml(this.containerName, allBlobItemXml.join("")),
|
|
545
|
-
parsedBody: {
|
|
546
|
-
containerName: this.containerName,
|
|
547
|
-
marker: "",
|
|
548
|
-
prefix: "",
|
|
549
|
-
segment: { blobItems: allBlobItems },
|
|
550
|
-
serviceEndpoint: ""
|
|
551
|
-
}
|
|
552
|
-
},
|
|
553
|
-
containerName: this.containerName,
|
|
554
|
-
marker: "",
|
|
555
|
-
prefix: "",
|
|
556
|
-
segment: { blobItems: allBlobItems },
|
|
557
|
-
serviceEndpoint: ""
|
|
558
|
-
});
|
|
563
|
+
if (allBlobItems.length > 0) yield await Promise.resolve(getListBlobsSegmentResponse(this.containerName, options?.prefix ?? "", { blobItems: allBlobItems }, allBlobItemXml.join("")));
|
|
559
564
|
}.bind(this)(),
|
|
560
565
|
next: blobItemIterator.next.bind(blobItemIterator),
|
|
561
566
|
[Symbol.asyncIterator]() {
|
|
@@ -584,20 +589,7 @@ var MockContainerClient = class {
|
|
|
584
589
|
if (!name.startsWith(prefix)) continue;
|
|
585
590
|
const nameAfterPrefix = name.slice(prefix.length);
|
|
586
591
|
const delimiterIndex = nameAfterPrefix.indexOf(delimiter);
|
|
587
|
-
if (delimiterIndex === -1) blobsInCurrentLevel.push(
|
|
588
|
-
deleted: false,
|
|
589
|
-
name,
|
|
590
|
-
properties: {
|
|
591
|
-
blobType: "BlockBlob",
|
|
592
|
-
contentLength: buffer.length,
|
|
593
|
-
contentType: "application/octet-stream",
|
|
594
|
-
etag: `"${crypto.randomUUID()}"`,
|
|
595
|
-
lastModified: /* @__PURE__ */ new Date(),
|
|
596
|
-
leaseState: "available",
|
|
597
|
-
leaseStatus: "unlocked"
|
|
598
|
-
},
|
|
599
|
-
snapshot: ""
|
|
600
|
-
});
|
|
592
|
+
if (delimiterIndex === -1) blobsInCurrentLevel.push(this.#getBlobItem(name, buffer));
|
|
601
593
|
else {
|
|
602
594
|
const subprefix = `${prefix}${nameAfterPrefix.slice(0, delimiterIndex + delimiter.length)}`;
|
|
603
595
|
uniqueSubprefixes.add(subprefix);
|
|
@@ -612,21 +604,29 @@ var MockContainerClient = class {
|
|
|
612
604
|
...blobItem
|
|
613
605
|
});
|
|
614
606
|
}
|
|
615
|
-
|
|
616
|
-
|
|
607
|
+
#getBlobItem(name, buffer) {
|
|
608
|
+
return {
|
|
617
609
|
deleted: false,
|
|
618
610
|
name,
|
|
619
611
|
properties: {
|
|
620
612
|
blobType: "BlockBlob",
|
|
621
613
|
contentLength: buffer.length,
|
|
622
614
|
contentType: "application/octet-stream",
|
|
615
|
+
createdOn: MockContainerCreatedOnDatabase.get(getMockContainerCreatedOnKey(this.containerName, name)) ?? MOCK_BLOB_SEEDED_CREATED_ON,
|
|
623
616
|
etag: `"${crypto.randomUUID()}"`,
|
|
624
617
|
lastModified: /* @__PURE__ */ new Date(),
|
|
625
618
|
leaseState: "available",
|
|
626
619
|
leaseStatus: "unlocked"
|
|
627
620
|
},
|
|
628
621
|
snapshot: ""
|
|
629
|
-
}
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
async *#getBlobItemIterator(options) {
|
|
625
|
+
const prefix = options?.prefix ?? "";
|
|
626
|
+
for (const [name, buffer] of this.container.entries()) {
|
|
627
|
+
if (!name.startsWith(prefix)) continue;
|
|
628
|
+
yield await Promise.resolve(this.#getBlobItem(name, buffer));
|
|
629
|
+
}
|
|
630
630
|
}
|
|
631
631
|
};
|
|
632
632
|
/**
|
|
@@ -648,6 +648,15 @@ var MockEventGridPublisherClient = class {
|
|
|
648
648
|
return Promise.resolve();
|
|
649
649
|
}
|
|
650
650
|
};
|
|
651
|
+
const getMockQueueMessageItem = (messageText) => {
|
|
652
|
+
const insertedOn = /* @__PURE__ */ new Date();
|
|
653
|
+
return {
|
|
654
|
+
expiresOn: new Date(insertedOn.getTime() + MAX_QUEUE_VISIBILITY_TIMEOUT_MS),
|
|
655
|
+
insertedOn,
|
|
656
|
+
messageId: crypto.randomUUID(),
|
|
657
|
+
messageText
|
|
658
|
+
};
|
|
659
|
+
};
|
|
651
660
|
/**
|
|
652
661
|
* An in-memory mock of the Azure QueueClient.
|
|
653
662
|
* It uses a Map to simulate queue storage and correctly implements the QueueClient interface.
|
|
@@ -718,10 +727,7 @@ var MockQueueClient = class {
|
|
|
718
727
|
peekMessages(_options) {
|
|
719
728
|
const peekedMessageItems = this.queue.map((text) => ({
|
|
720
729
|
dequeueCount: 0,
|
|
721
|
-
|
|
722
|
-
insertedOn: /* @__PURE__ */ new Date(),
|
|
723
|
-
messageId: crypto.randomUUID(),
|
|
724
|
-
messageText: text
|
|
730
|
+
...getMockQueueMessageItem(text)
|
|
725
731
|
}));
|
|
726
732
|
return Promise.resolve({
|
|
727
733
|
_response: {
|
|
@@ -733,12 +739,8 @@ var MockQueueClient = class {
|
|
|
733
739
|
});
|
|
734
740
|
}
|
|
735
741
|
receiveMessages(_options) {
|
|
736
|
-
const receivedMessageItems = this.queue.splice(0).map((text) => ({
|
|
742
|
+
const receivedMessageItems = this.queue.splice(0).map((text) => Object.assign(getMockQueueMessageItem(text), {
|
|
737
743
|
dequeueCount: 1,
|
|
738
|
-
expiresOn: new Date(Date.now() + MAX_QUEUE_VISIBILITY_TIMEOUT_MS),
|
|
739
|
-
insertedOn: /* @__PURE__ */ new Date(),
|
|
740
|
-
messageId: crypto.randomUUID(),
|
|
741
|
-
messageText: text,
|
|
742
744
|
nextVisibleOn: /* @__PURE__ */ new Date(),
|
|
743
745
|
popReceipt: crypto.randomUUID()
|
|
744
746
|
}));
|
|
@@ -753,11 +755,8 @@ var MockQueueClient = class {
|
|
|
753
755
|
}
|
|
754
756
|
sendMessage(messageText, _options) {
|
|
755
757
|
this.queue.push(messageText);
|
|
756
|
-
const
|
|
757
|
-
const
|
|
758
|
-
const insertedOn = now;
|
|
759
|
-
const messageId = crypto.randomUUID();
|
|
760
|
-
const nextVisibleOn = now;
|
|
758
|
+
const { expiresOn, insertedOn, messageId } = getMockQueueMessageItem(messageText);
|
|
759
|
+
const nextVisibleOn = insertedOn;
|
|
761
760
|
const popReceipt = crypto.randomUUID();
|
|
762
761
|
const enqueuedMessages = [{
|
|
763
762
|
expiresOn,
|
|
@@ -837,18 +836,24 @@ var import_fast_deep_equal = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJS
|
|
|
837
836
|
};
|
|
838
837
|
})))(), 1);
|
|
839
838
|
const isNullClause = (clause) => {
|
|
840
|
-
|
|
839
|
+
const tableNullClause = getTableNullClause(clause.key);
|
|
840
|
+
return (0, import_fast_deep_equal.default)(clause, tableNullClause);
|
|
841
841
|
};
|
|
842
842
|
const createFilterPredicate = (filter) => {
|
|
843
|
-
const orGroups = filter.replaceAll(String.raw`(`, " ").replaceAll(String.raw`)`, "").split(/\s+and\s+/iu).filter(Boolean).map((group) => group.split(/\s+or\s+/iu).filter(Boolean))
|
|
843
|
+
const orGroups = filter.replaceAll(String.raw`(`, " ").replaceAll(String.raw`)`, "").split(/\s+and\s+/iu).filter(Boolean).map((group) => group.split(/\s+or\s+/iu).filter(Boolean).map((clauseString) => {
|
|
844
|
+
const clause = deserializeClause(clauseString);
|
|
845
|
+
return {
|
|
846
|
+
clause,
|
|
847
|
+
isNull: isNullClause(clause)
|
|
848
|
+
};
|
|
849
|
+
}));
|
|
844
850
|
return (document) => {
|
|
845
851
|
for (const orGroup of orGroups) {
|
|
846
852
|
let isGroupMatched = false;
|
|
847
|
-
for (const
|
|
848
|
-
const clause = deserializeClause(group);
|
|
853
|
+
for (const { clause, isNull } of orGroup) {
|
|
849
854
|
const value = takeOne(document, clause.key);
|
|
850
855
|
let isMatched;
|
|
851
|
-
if (
|
|
856
|
+
if (isNull) isMatched = compare(BinaryOperator.eq, value, null);
|
|
852
857
|
else {
|
|
853
858
|
const comparisonResult = compare(clause.operator, value, clause.value);
|
|
854
859
|
isMatched = clause.not ? !comparisonResult : comparisonResult;
|
|
@@ -874,15 +879,22 @@ const compareValues = (leftHandSide, rightHandSide) => {
|
|
|
874
879
|
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
875
880
|
return String(left).localeCompare(String(right));
|
|
876
881
|
};
|
|
877
|
-
const sortDocuments = (documents, orderBy) =>
|
|
878
|
-
|
|
882
|
+
const sortDocuments = (documents, orderBy) => {
|
|
883
|
+
const parsedOrderBy = orderBy.map((clause) => {
|
|
879
884
|
const [field = "", direction = "asc"] = clause.split(/\s+/u);
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
885
|
+
return {
|
|
886
|
+
direction,
|
|
887
|
+
key: deserializeKey(field)
|
|
888
|
+
};
|
|
889
|
+
});
|
|
890
|
+
return documents.toSorted((leftHandSide, rightHandSide) => {
|
|
891
|
+
for (const { direction, key } of parsedOrderBy) {
|
|
892
|
+
const comparison = compareValues(leftHandSide[key], rightHandSide[key]);
|
|
893
|
+
if (comparison !== 0) return direction === "desc" ? -comparison : comparison;
|
|
894
|
+
}
|
|
895
|
+
return 0;
|
|
896
|
+
});
|
|
897
|
+
};
|
|
886
898
|
const getSearchFieldValues = (value, pathSegments) => {
|
|
887
899
|
if (pathSegments.length === 0) return [value];
|
|
888
900
|
if (Array.isArray(value)) return value.flatMap((item) => getSearchFieldValues(item, pathSegments));
|
|
@@ -893,7 +905,8 @@ const getSearchFieldValues = (value, pathSegments) => {
|
|
|
893
905
|
const searchDocuments = (documents, searchText, searchFields) => {
|
|
894
906
|
if (!searchText || searchText === "*") return documents;
|
|
895
907
|
const normalizedSearchText = searchText.toLocaleLowerCase();
|
|
896
|
-
|
|
908
|
+
const searchFieldPaths = searchFields?.map((searchField) => searchField.split("/"));
|
|
909
|
+
return documents.filter((document) => (searchFieldPaths ?? Object.keys(document).map((field) => field.split("/"))).some((pathSegments) => getSearchFieldValues(document, pathSegments).some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(normalizedSearchText))));
|
|
897
910
|
};
|
|
898
911
|
/**
|
|
899
912
|
* An in-memory mock of the Azure SearchClient.
|
|
@@ -1004,6 +1017,11 @@ var MockServiceBusSender = class {
|
|
|
1004
1017
|
return Promise.resolve();
|
|
1005
1018
|
}
|
|
1006
1019
|
};
|
|
1020
|
+
const compareByCompositeKey = (a, b) => {
|
|
1021
|
+
if (a.partitionKey !== b.partitionKey) return a.partitionKey < b.partitionKey ? -1 : 1;
|
|
1022
|
+
else if (a.rowKey === b.rowKey) return 0;
|
|
1023
|
+
else return a.rowKey < b.rowKey ? -1 : 1;
|
|
1024
|
+
};
|
|
1007
1025
|
/**
|
|
1008
1026
|
* An in-memory mock of the Azure TableClient.
|
|
1009
1027
|
* It uses a Map to simulate table storage and correctly implements the TableClient interface.
|
|
@@ -1024,9 +1042,7 @@ var MockTableClient = class {
|
|
|
1024
1042
|
this.url = `${MOCK_TABLE_BASE_URL}/${this.tableName}`;
|
|
1025
1043
|
}
|
|
1026
1044
|
createEntity(entity) {
|
|
1027
|
-
|
|
1028
|
-
if (this.table.has(key)) throw new MockRestError("The specified entity already exists.", 409);
|
|
1029
|
-
this.table.set(key, entity);
|
|
1045
|
+
this.#applyCreate(entity);
|
|
1030
1046
|
return Promise.resolve({
|
|
1031
1047
|
date: /* @__PURE__ */ new Date(),
|
|
1032
1048
|
etag: this.#getEtag()
|
|
@@ -1036,9 +1052,7 @@ var MockTableClient = class {
|
|
|
1036
1052
|
throw new Error("Method not implemented.");
|
|
1037
1053
|
}
|
|
1038
1054
|
deleteEntity(partitionKey, rowKey) {
|
|
1039
|
-
|
|
1040
|
-
if (!this.table.has(key)) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1041
|
-
this.table.delete(key);
|
|
1055
|
+
this.#applyDelete(partitionKey, rowKey);
|
|
1042
1056
|
return Promise.resolve({});
|
|
1043
1057
|
}
|
|
1044
1058
|
deleteTable() {
|
|
@@ -1053,7 +1067,7 @@ var MockTableClient = class {
|
|
|
1053
1067
|
if (!entity) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1054
1068
|
return Promise.resolve({
|
|
1055
1069
|
...entity,
|
|
1056
|
-
etag: this.#getEtag()
|
|
1070
|
+
etag: entity.etag ?? this.#getEtag()
|
|
1057
1071
|
});
|
|
1058
1072
|
}
|
|
1059
1073
|
listEntities(options) {
|
|
@@ -1061,22 +1075,22 @@ var MockTableClient = class {
|
|
|
1061
1075
|
const filter = options?.queryOptions?.filter;
|
|
1062
1076
|
const tableEntities = [...this.table.values()];
|
|
1063
1077
|
const predicate = filter ? createFilterPredicate(filter) : void 0;
|
|
1064
|
-
const resultTableEntities = predicate ? tableEntities.filter((e) => predicate(e)) : tableEntities;
|
|
1078
|
+
const resultTableEntities = (predicate ? tableEntities.filter((e) => predicate(e)) : tableEntities).toSorted(compareByCompositeKey);
|
|
1079
|
+
const entityIterator = (async function* (entities) {
|
|
1080
|
+
for (const entity of entities) yield await Promise.resolve(withMetadata(entity));
|
|
1081
|
+
})(resultTableEntities);
|
|
1065
1082
|
return {
|
|
1066
1083
|
byPage: ({ maxPageSize } = {}) => (async function* (entities) {
|
|
1067
1084
|
if (maxPageSize !== void 0 && maxPageSize <= 0) throw new RangeError("maxPageSize must be greater than 0.");
|
|
1068
1085
|
else if (maxPageSize !== void 0 && maxPageSize > AZURE_MAX_PAGE_SIZE) throw new MockRestError("One of the request inputs is not valid.", 400);
|
|
1069
|
-
|
|
1070
|
-
if (allEntitiesWithMetadata.length === 0) return;
|
|
1086
|
+
if (entities.length === 0) return;
|
|
1071
1087
|
else if (!maxPageSize) {
|
|
1072
|
-
yield await Promise.resolve(
|
|
1088
|
+
yield await Promise.resolve(entities.map((e) => withMetadata(e)));
|
|
1073
1089
|
return;
|
|
1074
1090
|
}
|
|
1075
|
-
for (
|
|
1091
|
+
for (const page of chunk(entities, maxPageSize)) yield await Promise.resolve(page.map((e) => withMetadata(e)));
|
|
1076
1092
|
})(resultTableEntities),
|
|
1077
|
-
next: () => (
|
|
1078
|
-
for (const entity of entities) yield await Promise.resolve(withMetadata(entity));
|
|
1079
|
-
})(resultTableEntities).next(),
|
|
1093
|
+
next: () => entityIterator.next(),
|
|
1080
1094
|
[Symbol.asyncIterator]() {
|
|
1081
1095
|
return this;
|
|
1082
1096
|
}
|
|
@@ -1085,24 +1099,24 @@ var MockTableClient = class {
|
|
|
1085
1099
|
setAccessPolicy() {
|
|
1086
1100
|
throw new Error("Method not implemented.");
|
|
1087
1101
|
}
|
|
1088
|
-
|
|
1102
|
+
submitTransaction(actions) {
|
|
1089
1103
|
let partitionKey;
|
|
1090
1104
|
for (const [, entity] of actions) if (partitionKey === void 0) partitionKey = entity.partitionKey;
|
|
1091
1105
|
else if (entity.partitionKey !== partitionKey) throw new MockRestError("All transaction actions must target the same partitionKey.", 400);
|
|
1092
1106
|
const snapshot = new Map(this.table);
|
|
1093
|
-
|
|
1107
|
+
getResult(() => {
|
|
1094
1108
|
for (const [type, entity, updateMode] of actions) switch (type) {
|
|
1095
1109
|
case "create":
|
|
1096
|
-
|
|
1110
|
+
this.#applyCreate(entity);
|
|
1097
1111
|
break;
|
|
1098
1112
|
case "delete":
|
|
1099
|
-
|
|
1113
|
+
this.#applyDelete(entity.partitionKey, entity.rowKey);
|
|
1100
1114
|
break;
|
|
1101
1115
|
case "update":
|
|
1102
|
-
|
|
1116
|
+
this.#applyUpdate(entity, updateMode);
|
|
1103
1117
|
break;
|
|
1104
1118
|
case "upsert":
|
|
1105
|
-
|
|
1119
|
+
this.#applyUpsert(entity, updateMode);
|
|
1106
1120
|
break;
|
|
1107
1121
|
default: exhaustiveGuard(type);
|
|
1108
1122
|
}
|
|
@@ -1112,57 +1126,77 @@ var MockTableClient = class {
|
|
|
1112
1126
|
}).match(noop, (error) => {
|
|
1113
1127
|
throw error;
|
|
1114
1128
|
});
|
|
1115
|
-
return {
|
|
1116
|
-
getResponseForEntity:
|
|
1129
|
+
return Promise.resolve({
|
|
1130
|
+
getResponseForEntity: () => void 0,
|
|
1117
1131
|
status: 202,
|
|
1118
1132
|
subResponses: []
|
|
1119
|
-
};
|
|
1133
|
+
});
|
|
1120
1134
|
}
|
|
1121
|
-
updateEntity(entity, mode = "Merge") {
|
|
1135
|
+
updateEntity(entity, mode = "Merge", options) {
|
|
1136
|
+
this.#applyUpdate(entity, mode, options?.etag);
|
|
1137
|
+
return Promise.resolve({
|
|
1138
|
+
date: /* @__PURE__ */ new Date(),
|
|
1139
|
+
etag: this.#getEtag()
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
upsertEntity(entity, mode = "Merge") {
|
|
1143
|
+
this.#applyUpsert(entity, mode);
|
|
1144
|
+
return Promise.resolve({
|
|
1145
|
+
date: /* @__PURE__ */ new Date(),
|
|
1146
|
+
etag: this.#getEtag()
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
#applyCreate(entity) {
|
|
1150
|
+
const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1151
|
+
if (this.table.has(key)) throw new MockRestError("The specified entity already exists.", 409);
|
|
1152
|
+
this.table.set(key, {
|
|
1153
|
+
...entity,
|
|
1154
|
+
etag: this.#getEtag()
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
#applyDelete(partitionKey, rowKey) {
|
|
1158
|
+
const key = this.#getCompositeKey(partitionKey, rowKey);
|
|
1159
|
+
if (!this.table.has(key)) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1160
|
+
this.table.delete(key);
|
|
1161
|
+
}
|
|
1162
|
+
#applyUpdate(entity, mode = "Merge", etag) {
|
|
1122
1163
|
const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1123
1164
|
const existingEntity = this.table.get(key);
|
|
1124
1165
|
if (!existingEntity) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1125
|
-
else if (
|
|
1126
|
-
else {
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1166
|
+
else if (etag !== void 0 && etag !== "*" && etag !== existingEntity.etag) throw new MockRestError("The update condition specified in the request was not satisfied.", 412);
|
|
1167
|
+
else if (mode === "Merge") this.table.set(key, {
|
|
1168
|
+
...existingEntity,
|
|
1169
|
+
...entity,
|
|
1170
|
+
etag: this.#getEtag()
|
|
1171
|
+
});
|
|
1172
|
+
else this.table.set(key, {
|
|
1173
|
+
...entity,
|
|
1174
|
+
etag: this.#getEtag()
|
|
1175
|
+
});
|
|
1133
1176
|
}
|
|
1134
|
-
|
|
1177
|
+
#applyUpsert(entity, mode = "Merge") {
|
|
1135
1178
|
const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1136
1179
|
const existingEntity = this.table.get(key);
|
|
1137
|
-
if (existingEntity && mode === "Merge")
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1180
|
+
if (existingEntity && mode === "Merge") this.table.set(key, {
|
|
1181
|
+
...existingEntity,
|
|
1182
|
+
...entity,
|
|
1183
|
+
etag: this.#getEtag()
|
|
1184
|
+
});
|
|
1185
|
+
else this.table.set(key, {
|
|
1186
|
+
...entity,
|
|
1187
|
+
etag: this.#getEtag()
|
|
1188
|
+
});
|
|
1145
1189
|
}
|
|
1146
1190
|
#getCompositeKey(partitionKey, rowKey) {
|
|
1147
1191
|
return `${partitionKey}${ID_SEPARATOR}${rowKey}`;
|
|
1148
1192
|
}
|
|
1149
1193
|
#getEtag() {
|
|
1150
|
-
return `W/"
|
|
1151
|
-
}
|
|
1152
|
-
#mergeEntity(key, entity, entityToMerge) {
|
|
1153
|
-
this.table.set(key, {
|
|
1154
|
-
...entity,
|
|
1155
|
-
...entityToMerge
|
|
1156
|
-
});
|
|
1157
|
-
return Promise.resolve({
|
|
1158
|
-
date: /* @__PURE__ */ new Date(),
|
|
1159
|
-
etag: this.#getEtag()
|
|
1160
|
-
});
|
|
1194
|
+
return `W/"${crypto.randomUUID()}"`;
|
|
1161
1195
|
}
|
|
1162
1196
|
#withMetadata(entity) {
|
|
1163
1197
|
return {
|
|
1164
1198
|
...entity,
|
|
1165
|
-
etag: this.#getEtag()
|
|
1199
|
+
etag: entity.etag ?? this.#getEtag()
|
|
1166
1200
|
};
|
|
1167
1201
|
}
|
|
1168
1202
|
};
|
|
@@ -1179,4 +1213,4 @@ const applyFilter = (documents, clauses) => {
|
|
|
1179
1213
|
const predicate = createFilterPredicate(serializeClauses(clauses));
|
|
1180
1214
|
return documents.filter((document) => predicate(document));
|
|
1181
1215
|
};
|
|
1182
|
-
export { MOCK_BLOB_BASE_URL, MOCK_QUEUE_BASE_URL, MOCK_SEARCH_BASE_URL, MOCK_TABLE_BASE_URL, MockBlobBatchClient, MockBlobClient, MockBlockBlobClient, MockContainerClient, MockContainerDatabase, MockEventGridDatabase, MockEventGridPublisherClient, MockQueueClient, MockQueueDatabase, MockRestError, MockSearchClient, MockSearchDatabase, MockServiceBusDatabase, MockServiceBusSender, MockTableClient, MockTableDatabase, MockWebPubSubServiceClient, applyFilter, bodyToBuffer, compare, createFilterPredicate, createMockResponse, getAzureErrorXml, getBlobItemXml, getBlobPrefixXml, getListBlobsXml, getMockSasUrl, isNullClause, isReadableStream, toWebResourceLike };
|
|
1216
|
+
export { BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE, MOCK_BLOB_BASE_URL, MOCK_BLOB_SEEDED_CREATED_ON, MOCK_QUEUE_BASE_URL, MOCK_SEARCH_BASE_URL, MOCK_TABLE_BASE_URL, MockBlobBatchClient, MockBlobClient, MockBlockBlobClient, MockContainerClient, MockContainerCreatedOnDatabase, MockContainerDatabase, MockEventGridDatabase, MockEventGridPublisherClient, MockQueueClient, MockQueueDatabase, MockRestError, MockSearchClient, MockSearchDatabase, MockServiceBusDatabase, MockServiceBusSender, MockTableClient, MockTableDatabase, MockWebPubSubServiceClient, applyFilter, bodyToBuffer, compare, compareByCompositeKey, createFilterPredicate, createMockResponse, getAzureErrorXml, getBlobItemXml, getBlobPrefixXml, getBlobUrl, getBlobUrlParts, getListBlobsSegmentResponse, getListBlobsXml, getMockContainer, getMockContainerCreatedOnKey, getMockQueueMessageItem, getMockSasUrl, isNullClause, isReadableStream, toWebResourceLike };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azure-mock",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.37.2",
|
|
4
4
|
"description": "A library that contains azure mock classes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"azure",
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
"typecheck": "tsgo"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@esposter/db": "2.
|
|
51
|
-
"@esposter/db-schema": "2.
|
|
52
|
-
"@esposter/shared": "2.
|
|
50
|
+
"@esposter/db": "2.37.2",
|
|
51
|
+
"@esposter/db-schema": "2.37.2",
|
|
52
|
+
"@esposter/shared": "2.37.2",
|
|
53
53
|
"fast-deep-equal": "^3.1.3"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@esposter/configuration": "2.
|
|
57
|
-
"ctix": "^2.8.
|
|
58
|
-
"rolldown": "^1.
|
|
56
|
+
"@esposter/configuration": "2.37.2",
|
|
57
|
+
"ctix": "^2.8.2",
|
|
58
|
+
"rolldown": "^1.2.4",
|
|
59
59
|
"type-fest": "^5.8.0",
|
|
60
60
|
"typedoc": "^0.28.20",
|
|
61
61
|
"vitest": "^4.1.10"
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"@azure/storage-blob": "^12.33.0",
|
|
71
71
|
"@azure/storage-queue": "^12.31.0"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "4d775dbd8289e6caaee48f08038b65fddb4babbc"
|
|
74
74
|
}
|