azure-mock 4.3.1 → 4.4.0

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/index.js DELETED
@@ -1,1312 +0,0 @@
1
- import { ID_SEPARATOR, InvalidOperationError, Operation, checkIsDeepEqual, chunk, exhaustiveGuard, getDecodedUriComponent, getOrCreate, getResult, html, noop, streamToText, takeOne } from "@esposter/shared";
2
- import { toHttpHeadersLike } from "@azure/core-http-compat";
3
- import { RestError, createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";
4
- import { AnonymousCredential } from "@azure/storage-blob";
5
- import { Readable } from "node:stream";
6
- import { AZURE_MAX_PAGE_SIZE, AZURE_MAX_QUEUE_VISIBILITY_TIMEOUT_MS, BinaryOperator, deserializeClause, deserializeKey, getTableNullClause, serializeClauses } from "@esposter/azure";
7
- //#region src/constants.ts
8
- const BLOB_NOT_FOUND_ERROR_CODE = "BlobNotFound";
9
- const BLOB_NOT_FOUND_MESSAGE = "The specified blob does not exist.";
10
- const CONDITION_NOT_MET_ERROR_CODE = "ConditionNotMet";
11
- const CONDITION_NOT_MET_MESSAGE = "The condition specified using HTTP conditional header(s) is not met.";
12
- const MOCK_BLOB_BASE_URL = "https://mockaccount.blob.core.windows.net";
13
- const MOCK_QUEUE_BASE_URL = "https://mockaccount.queue.core.windows.net";
14
- const MOCK_SEARCH_BASE_URL = "https://mockaccount.search.windows.net";
15
- const MOCK_TABLE_BASE_URL = "https://mockaccount.table.core.windows.net";
16
- //#endregion
17
- //#region src/models/shared/NotImplementedError.ts
18
- var NotImplementedError = class extends Error {
19
- constructor(name) {
20
- super(`${name} is not implemented in the mock`);
21
- this.name = "NotImplementedError";
22
- }
23
- };
24
- //#endregion
25
- //#region src/services/container/getMockBlobKey.ts
26
- const getMockBlobKey = (containerName, blobName) => `${encodeURIComponent(containerName)}${ID_SEPARATOR}${encodeURIComponent(blobName)}`;
27
- //#endregion
28
- //#region src/store/MockContainerBlobDatesDatabase.ts
29
- const MockContainerBlobDatesDatabase = /* @__PURE__ */ new Map();
30
- //#endregion
31
- //#region src/store/MockContainerBlobMetadataDatabase.ts
32
- const MockContainerBlobMetadataDatabase = /* @__PURE__ */ new Map();
33
- //#endregion
34
- //#region src/store/MockContainerDatabase.ts
35
- var MockContainerDatabaseMap = class extends Map {
36
- clear() {
37
- super.clear();
38
- MockContainerBlobDatesDatabase.clear();
39
- MockContainerBlobMetadataDatabase.clear();
40
- }
41
- };
42
- const MockContainerDatabase = new MockContainerDatabaseMap();
43
- //#endregion
44
- //#region src/services/container/getMockContainer.ts
45
- const getMockContainer = (containerName) => getOrCreate(MockContainerDatabase, containerName, () => /* @__PURE__ */ new Map());
46
- //#endregion
47
- //#region src/services/container/storeMockBlobMetadata.ts
48
- const storeMockBlobMetadata = (containerName, blobName, metadata) => {
49
- const key = getMockBlobKey(containerName, blobName);
50
- if (metadata) MockContainerBlobMetadataDatabase.set(key, metadata);
51
- else MockContainerBlobMetadataDatabase.delete(key);
52
- };
53
- //#endregion
54
- //#region src/services/container/deleteMockBlob.ts
55
- const deleteMockBlob = (containerName, blobName) => {
56
- if (!getMockContainer(containerName).delete(blobName)) return false;
57
- MockContainerBlobDatesDatabase.delete(getMockBlobKey(containerName, blobName));
58
- storeMockBlobMetadata(containerName, blobName, void 0);
59
- return true;
60
- };
61
- //#endregion
62
- //#region src/services/container/getAzureErrorXml.ts
63
- /**
64
- * Generates a standard Azure Storage error XML response body.
65
- * @param errorCode The official Azure error code (e.g., "BlobNotFound").
66
- * @param errorMessage The user-friendly error message.
67
- * @returns A formatted XML string.
68
- */
69
- const getAzureErrorXml = (errorCode, errorMessage) => html`<?xml version="1.0" encoding="utf-8"?>
70
- <Error>
71
- <code>${errorCode}</code>
72
- <Message>${errorMessage}</Message>
73
- </Error>`;
74
- //#endregion
75
- //#region src/services/container/getBlobUrlParts.ts
76
- const decodeSegment = (segment) => getDecodedUriComponent(segment, segment);
77
- const getBlobUrlParts = (url) => {
78
- const parsedUrl = getResult(() => new URL(url)).unwrapOr(void 0);
79
- if (!parsedUrl) return void 0;
80
- const pathSegments = parsedUrl.pathname.split("/").filter(Boolean);
81
- if (pathSegments.length < 2) return void 0;
82
- return {
83
- blobName: decodeSegment(pathSegments.slice(1).join("/")),
84
- containerName: decodeSegment(takeOne(pathSegments))
85
- };
86
- };
87
- //#endregion
88
- //#region src/services/container/constants.ts
89
- const MOCK_BLOB_SEEDED_DATE = /* @__PURE__ */ new Date(-864e13);
90
- const MOCK_BLOB_SEEDED_PROPERTIES = {
91
- createdOn: MOCK_BLOB_SEEDED_DATE,
92
- etag: "\"seeded\"",
93
- lastModified: MOCK_BLOB_SEEDED_DATE
94
- };
95
- //#endregion
96
- //#region src/services/container/readMockBlobDates.ts
97
- const readMockBlobDates = (containerName, blobName) => MockContainerBlobDatesDatabase.get(getMockBlobKey(containerName, blobName)) ?? MOCK_BLOB_SEEDED_PROPERTIES;
98
- //#endregion
99
- //#region src/services/container/toWebResourceLike.ts
100
- const toWebResourceLike = (request) => ({
101
- abortSignal: request.abortSignal,
102
- agent: request.agent,
103
- body: request.body,
104
- clone: () => {
105
- throw new NotImplementedError(`${toWebResourceLike.name}(…).clone`);
106
- },
107
- formData: request.formData,
108
- headers: toHttpHeadersLike(request.headers),
109
- keepAlive: request.disableKeepAlive,
110
- method: request.method,
111
- onDownloadProgress: request.onDownloadProgress,
112
- onUploadProgress: request.onUploadProgress,
113
- prepare: () => {
114
- throw new NotImplementedError(`${toWebResourceLike.name}(…).prepare`);
115
- },
116
- proxySettings: request.proxySettings,
117
- requestId: request.headers.get("x-ms-client-request-id") ?? request.requestId,
118
- requestOverrides: request.requestOverrides,
119
- streamResponseStatusCodes: request.streamResponseStatusCodes,
120
- timeout: request.timeout,
121
- url: request.url,
122
- validateRequestProperties: noop,
123
- withCredentials: request.withCredentials
124
- });
125
- //#endregion
126
- //#region src/services/shared/createMockResponse.ts
127
- const createMockResponse = (status, url = "") => ({
128
- headers: toHttpHeadersLike(createHttpHeaders()),
129
- parsedHeaders: {},
130
- request: toWebResourceLike(createPipelineRequest({ url })),
131
- status
132
- });
133
- //#endregion
134
- //#region src/models/container/MockBlobBatchClient.ts
135
- var MockBlobBatchClient = class {
136
- url;
137
- constructor(url) {
138
- this.url = url;
139
- }
140
- /**
141
- * Simulates the deletion of multiple blobs in a single batch request.
142
- * It iterates through the requested deletions, removes existing blobs from the
143
- * underlying MockContainerDatabase, and builds a response object that reports
144
- * which deletions succeeded and which failed (e.g. for blobs that didn't exist).
145
- */
146
- deleteBlobs(urls, credential, options) {
147
- const { ifUnmodifiedSince, ...unsupportedConditions } = options?.conditions ?? {};
148
- const unsupportedConditionName = Object.entries(unsupportedConditions).find(([, value]) => value !== void 0)?.[0];
149
- if (unsupportedConditionName !== void 0) return Promise.reject(new NotImplementedError(`deleteBlobs with ${unsupportedConditionName}`));
150
- const subResponses = [];
151
- let subResponsesSucceededCount = 0;
152
- let subResponsesFailedCount = 0;
153
- for (const url of urls) {
154
- const urlParts = getBlobUrlParts(url);
155
- if (!urlParts) {
156
- subResponses.push(this.#createFailedSubResponse(credential, 400, "InvalidUri", "Invalid blob URL format."));
157
- subResponsesFailedCount++;
158
- continue;
159
- }
160
- const { blobName, containerName } = urlParts;
161
- if (this.#checkIsModifiedSince(containerName, blobName, ifUnmodifiedSince)) {
162
- subResponses.push(this.#createFailedSubResponse(credential, 412, CONDITION_NOT_MET_ERROR_CODE, CONDITION_NOT_MET_MESSAGE));
163
- subResponsesFailedCount++;
164
- continue;
165
- }
166
- if (deleteMockBlob(containerName, blobName)) {
167
- subResponses.push({
168
- _request: {
169
- credential,
170
- url: this.url
171
- },
172
- headers: toHttpHeadersLike(createHttpHeaders()),
173
- status: 202,
174
- statusMessage: "Accepted"
175
- });
176
- subResponsesSucceededCount++;
177
- } else {
178
- subResponses.push(this.#createFailedSubResponse(credential, 404, BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE));
179
- subResponsesFailedCount++;
180
- }
181
- }
182
- return Promise.resolve({
183
- _response: {
184
- ...createMockResponse(202, this.url),
185
- headers: toHttpHeadersLike(createHttpHeaders({
186
- "content-type": "multipart/mixed",
187
- "x-ms-request-id": crypto.randomUUID()
188
- }))
189
- },
190
- subResponses,
191
- subResponsesFailedCount,
192
- subResponsesSucceededCount
193
- });
194
- }
195
- getContainer(containerName) {
196
- return getMockContainer(containerName);
197
- }
198
- #checkIsModifiedSince(containerName, blobName, ifUnmodifiedSince) {
199
- return ifUnmodifiedSince !== void 0 && getMockContainer(containerName).has(blobName) && readMockBlobDates(containerName, blobName).lastModified > ifUnmodifiedSince;
200
- }
201
- #createFailedSubResponse(credential, status, errorCode, statusMessage) {
202
- return {
203
- _request: {
204
- credential,
205
- url: this.url
206
- },
207
- bodyAsText: getAzureErrorXml(errorCode, statusMessage),
208
- errorCode,
209
- headers: toHttpHeadersLike(createHttpHeaders()),
210
- status,
211
- statusMessage
212
- };
213
- }
214
- };
215
- //#endregion
216
- //#region src/models/shared/MockRestError.ts
217
- var MockRestError = class extends RestError {
218
- constructor(message, statusCode) {
219
- super(message, { statusCode });
220
- this.name = "MockRestError";
221
- }
222
- };
223
- //#endregion
224
- //#region src/services/container/getBlobUrl.ts
225
- const getBlobUrl = (containerName, blobName) => `${MOCK_BLOB_BASE_URL}/${containerName}/${blobName.split("/").map((segment) => encodeURIComponent(segment)).join("/")}`;
226
- //#endregion
227
- //#region src/services/container/storeMockBlobWrite.ts
228
- const storeMockBlobWrite = (containerName, blobName, isExisting) => {
229
- const key = getMockBlobKey(containerName, blobName);
230
- const lastModified = /* @__PURE__ */ new Date();
231
- MockContainerBlobDatesDatabase.set(key, {
232
- createdOn: MockContainerBlobDatesDatabase.get(key)?.createdOn ?? (isExisting ? MOCK_BLOB_SEEDED_DATE : lastModified),
233
- etag: `"${crypto.randomUUID()}"`,
234
- lastModified
235
- });
236
- };
237
- //#endregion
238
- //#region src/services/shared/getMockSasUrl.ts
239
- 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"}`;
240
- //#endregion
241
- //#region src/models/container/MockBlobClient.ts
242
- var MockBlobClient = class {
243
- connectionString;
244
- containerName;
245
- credential = new AnonymousCredential();
246
- name;
247
- url;
248
- get container() {
249
- return getMockContainer(this.containerName);
250
- }
251
- constructor(connectionString, containerName, blobName) {
252
- this.connectionString = connectionString;
253
- this.containerName = containerName;
254
- this.name = blobName;
255
- this.url = getBlobUrl(this.containerName, this.name);
256
- }
257
- abortCopyFromURL() {
258
- throw new NotImplementedError(this.abortCopyFromURL.name);
259
- }
260
- beginCopyFromURL(copySource) {
261
- const sourceParts = getBlobUrlParts(copySource);
262
- if (!sourceParts) throw new MockRestError("Invalid copy source URL format", 400);
263
- const { blobName: sourceBlobName, containerName: sourceContainerName } = sourceParts;
264
- const sourceContainer = MockContainerDatabase.get(sourceContainerName);
265
- if (!sourceContainer) throw new MockRestError("Source container not found", 404);
266
- const sourceData = sourceContainer.get(sourceBlobName);
267
- if (!sourceData) throw new MockRestError("Source blob not found", 404);
268
- storeMockBlobWrite(this.containerName, this.name, this.container.has(this.name));
269
- this.container.set(this.name, Buffer.from(sourceData));
270
- const response = { _response: createMockResponse(202, `${this.url}?comp=copy`) };
271
- return Promise.resolve({
272
- cancelOperation: () => Promise.resolve(),
273
- getOperationState: () => ({
274
- isCompleted: true,
275
- result: response
276
- }),
277
- getResult: () => response,
278
- isDone: () => true,
279
- isStopped: () => false,
280
- onProgress: () => noop,
281
- poll: () => Promise.resolve(),
282
- pollUntilDone: () => Promise.resolve(response),
283
- stopPolling: noop
284
- });
285
- }
286
- createSnapshot() {
287
- throw new NotImplementedError(this.createSnapshot.name);
288
- }
289
- delete() {
290
- if (!deleteMockBlob(this.containerName, this.name)) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
291
- return Promise.resolve({ _response: createMockResponse(200) });
292
- }
293
- deleteIfExists() {
294
- const succeeded = deleteMockBlob(this.containerName, this.name);
295
- return Promise.resolve({
296
- _response: createMockResponse(succeeded ? 200 : 404),
297
- succeeded
298
- });
299
- }
300
- deleteImmutabilityPolicy() {
301
- throw new NotImplementedError(this.deleteImmutabilityPolicy.name);
302
- }
303
- download() {
304
- const buffer = this.container.get(this.name);
305
- if (!buffer) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
306
- return Promise.resolve({
307
- _response: createMockResponse(200),
308
- etag: readMockBlobDates(this.containerName, this.name).etag,
309
- readableStreamBody: Readable.from(buffer)
310
- });
311
- }
312
- downloadToBuffer() {
313
- const data = this.container.get(this.name);
314
- if (!data) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
315
- return Promise.resolve(Buffer.from(data));
316
- }
317
- downloadToFile() {
318
- throw new NotImplementedError(this.downloadToFile.name);
319
- }
320
- exists() {
321
- return Promise.resolve(this.container.has(this.name));
322
- }
323
- generateSasStringToSign() {
324
- throw new NotImplementedError(this.generateSasStringToSign.name);
325
- }
326
- generateSasUrl(options) {
327
- return Promise.resolve(getMockSasUrl(this.url, options.permissions, "b"));
328
- }
329
- generateUserDelegationSasStringToSign() {
330
- throw new NotImplementedError(this.generateUserDelegationSasStringToSign.name);
331
- }
332
- generateUserDelegationSasUrl() {
333
- throw new NotImplementedError(this.generateUserDelegationSasUrl.name);
334
- }
335
- getAccountInfo() {
336
- throw new NotImplementedError(this.getAccountInfo.name);
337
- }
338
- getAppendBlobClient() {
339
- throw new NotImplementedError(this.getAppendBlobClient.name);
340
- }
341
- getBlobLeaseClient() {
342
- throw new NotImplementedError(this.getBlobLeaseClient.name);
343
- }
344
- getBlockBlobClient() {
345
- throw new NotImplementedError(this.getBlockBlobClient.name);
346
- }
347
- getPageBlobClient() {
348
- throw new NotImplementedError(this.getPageBlobClient.name);
349
- }
350
- getProperties() {
351
- const blob = this.container.get(this.name);
352
- if (!blob) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
353
- return Promise.resolve({
354
- _response: createMockResponse(200),
355
- contentLength: blob.byteLength,
356
- ...readMockBlobDates(this.containerName, this.name)
357
- });
358
- }
359
- getTags() {
360
- throw new NotImplementedError(this.getTags.name);
361
- }
362
- setAccessTier() {
363
- throw new NotImplementedError(this.setAccessTier.name);
364
- }
365
- setHTTPHeaders() {
366
- throw new NotImplementedError(this.setHTTPHeaders.name);
367
- }
368
- setImmutabilityPolicy() {
369
- throw new NotImplementedError(this.setImmutabilityPolicy.name);
370
- }
371
- setLegalHold() {
372
- throw new NotImplementedError(this.setLegalHold.name);
373
- }
374
- setMetadata(metadata) {
375
- if (!this.container.has(this.name)) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
376
- MockContainerBlobMetadataDatabase.set(getMockBlobKey(this.containerName, this.name), metadata ?? {});
377
- storeMockBlobWrite(this.containerName, this.name, true);
378
- return Promise.resolve({
379
- _response: createMockResponse(200),
380
- ...readMockBlobDates(this.containerName, this.name)
381
- });
382
- }
383
- setTags() {
384
- throw new NotImplementedError(this.setTags.name);
385
- }
386
- syncCopyFromURL() {
387
- throw new NotImplementedError(this.syncCopyFromURL.name);
388
- }
389
- undelete() {
390
- throw new NotImplementedError(this.undelete.name);
391
- }
392
- withSnapshot() {
393
- throw new NotImplementedError(this.withSnapshot.name);
394
- }
395
- withVersion() {
396
- throw new NotImplementedError(this.withVersion.name);
397
- }
398
- };
399
- //#endregion
400
- //#region src/services/container/checkIsReadableStream.ts
401
- const checkIsReadableStream = (value) => value instanceof Readable;
402
- //#endregion
403
- //#region src/services/container/bodyToBuffer.ts
404
- const bodyToBuffer = async (body) => {
405
- if (body === null) return Buffer.alloc(0);
406
- else if (typeof body === "string") return Buffer.from(body);
407
- else if (body instanceof ArrayBuffer) return Buffer.from(body);
408
- else if (ArrayBuffer.isView(body)) return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
409
- else if (typeof body === "function") {
410
- const streamOrBlob = body();
411
- return bodyToBuffer(streamOrBlob);
412
- } else if (body instanceof Blob) {
413
- const arrayBuffer = await body.arrayBuffer();
414
- return Buffer.from(arrayBuffer);
415
- } else if (checkIsReadableStream(body)) return Buffer.from(await streamToText(body));
416
- else if (body instanceof ReadableStream) {
417
- const reader = body.getReader();
418
- const chunks = [];
419
- while (true) {
420
- const { done, value } = await reader.read();
421
- if (done) break;
422
- else chunks.push(value);
423
- }
424
- return Buffer.concat(chunks);
425
- } else if (body instanceof FormData) throw new NotImplementedError(`${bodyToBuffer.name}(FormData)`);
426
- else {
427
- exhaustiveGuard(body);
428
- return Buffer.alloc(0);
429
- }
430
- };
431
- //#endregion
432
- //#region src/models/container/MockBlockBlobClient.ts
433
- var MockBlockBlobClient = class extends MockBlobClient {
434
- commitBlockList() {
435
- throw new NotImplementedError(this.commitBlockList.name);
436
- }
437
- getBlockList() {
438
- throw new NotImplementedError(this.getBlockList.name);
439
- }
440
- query() {
441
- throw new NotImplementedError(this.query.name);
442
- }
443
- stageBlock() {
444
- throw new NotImplementedError(this.stageBlock.name);
445
- }
446
- stageBlockFromURL() {
447
- throw new NotImplementedError(this.stageBlockFromURL.name);
448
- }
449
- syncUploadFromURL() {
450
- throw new NotImplementedError(this.syncUploadFromURL.name);
451
- }
452
- async upload(body, _contentLength, options) {
453
- const buffer = await bodyToBuffer(body);
454
- if (options?.conditions?.ifNoneMatch === "*" && this.container.has(this.name)) throw new MockRestError("The specified blob already exists.", 409);
455
- if (options?.conditions?.ifMatch !== void 0 && options.conditions.ifMatch !== (this.container.has(this.name) ? readMockBlobDates(this.containerName, this.name).etag : void 0)) throw new MockRestError("The condition specified using HTTP conditional header(s) is not met.", 412);
456
- storeMockBlobWrite(this.containerName, this.name, this.container.has(this.name));
457
- storeMockBlobMetadata(this.containerName, this.name, options?.metadata);
458
- this.container.set(this.name, buffer);
459
- const { etag } = readMockBlobDates(this.containerName, this.name);
460
- return {
461
- _response: createMockResponse(201),
462
- etag
463
- };
464
- }
465
- uploadBrowserData() {
466
- throw new NotImplementedError(this.uploadBrowserData.name);
467
- }
468
- uploadData() {
469
- throw new NotImplementedError(this.uploadData.name);
470
- }
471
- uploadFile() {
472
- throw new NotImplementedError(this.uploadFile.name);
473
- }
474
- uploadStream() {
475
- throw new NotImplementedError(this.uploadStream.name);
476
- }
477
- };
478
- //#endregion
479
- //#region src/services/container/getBlobItemXml.ts
480
- const getBlobItemXml = ({ name, properties }) => html`<Blob>
481
- <Name>${name}</Name>
482
- <Properties>
483
- <Last-Modified>${properties.lastModified.toUTCString()}</Last-Modified>
484
- <Etag>${properties.etag}</Etag>
485
- <Content-Length>${properties.contentLength}</Content-Length>
486
- <Content-Type>${properties.contentType}</Content-Type>
487
- <BlobType>BlockBlob</BlobType>
488
- <LeaseStatus>unlocked</LeaseStatus>
489
- <LeaseState>available</LeaseState>
490
- </Properties>
491
- </Blob>`;
492
- //#endregion
493
- //#region src/services/container/getBlobPrefixXml.ts
494
- const getBlobPrefixXml = (name) => html`<BlobPrefix><Name>${name}</Name></BlobPrefix>`;
495
- //#endregion
496
- //#region src/services/container/getListBlobsXml.ts
497
- /**
498
- * Generates a standard Azure Storage list blobs XML response body.
499
- * @param containerName The container name.
500
- * @param blobsXml The blobs xml data.
501
- * @returns A formatted XML string.
502
- */
503
- const getListBlobsXml = (containerName, blobsXml) => html`<?xml version="1.0" encoding="utf8"?>
504
- <EnumerationResults ServiceEndpoint="" ContainerName="${containerName}">
505
- <Blobs>${blobsXml}</Blobs>
506
- <NextMarker />
507
- </EnumerationResults>`;
508
- //#endregion
509
- //#region src/services/container/getListBlobsSegmentResponse.ts
510
- const getListBlobsSegmentResponse = (containerName, prefix, segment, blobsXml) => {
511
- const segmentResponse = {
512
- containerName,
513
- marker: "",
514
- prefix,
515
- segment,
516
- serviceEndpoint: ""
517
- };
518
- return {
519
- _response: {
520
- ...createMockResponse(200),
521
- bodyAsText: getListBlobsXml(containerName, blobsXml),
522
- parsedBody: segmentResponse
523
- },
524
- ...segmentResponse
525
- };
526
- };
527
- //#endregion
528
- //#region src/services/container/readMockBlobMetadata.ts
529
- const readMockBlobMetadata = (containerName, blobName) => MockContainerBlobMetadataDatabase.get(getMockBlobKey(containerName, blobName));
530
- //#endregion
531
- //#region src/models/container/MockContainerClient.ts
532
- /**
533
- * An in-memory mock of the Azure ContainerClient — no emulator and no network.
534
- *
535
- * @example
536
- * const mockContainerClient = new MockContainerClient("", "hello world");
537
- * const blockBlobClient = mockContainerClient.getBlockBlobClient("hello world.txt");
538
- * await blockBlobClient.upload("hello world", 11);
539
- * const content = await blockBlobClient.downloadToBuffer();
540
- */
541
- var MockContainerClient = class {
542
- connectionString;
543
- containerName;
544
- credential = new AnonymousCredential();
545
- url;
546
- get container() {
547
- return getMockContainer(this.containerName);
548
- }
549
- constructor(connectionString, containerName) {
550
- this.connectionString = connectionString;
551
- this.containerName = containerName;
552
- this.url = `${MOCK_BLOB_BASE_URL}/${this.containerName}`;
553
- }
554
- create() {
555
- throw new NotImplementedError(this.create.name);
556
- }
557
- createIfNotExists() {
558
- throw new NotImplementedError(this.createIfNotExists.name);
559
- }
560
- delete() {
561
- throw new NotImplementedError(this.delete.name);
562
- }
563
- deleteBlob(blobName) {
564
- if (!deleteMockBlob(this.containerName, blobName)) throw new MockRestError(BLOB_NOT_FOUND_MESSAGE, 404);
565
- return Promise.resolve({ _response: createMockResponse(200, getBlobUrl(this.containerName, blobName)) });
566
- }
567
- deleteIfExists() {
568
- throw new NotImplementedError(this.deleteIfExists.name);
569
- }
570
- exists() {
571
- throw new NotImplementedError(this.exists.name);
572
- }
573
- findBlobsByTags() {
574
- throw new NotImplementedError(this.findBlobsByTags.name);
575
- }
576
- generateSasStringToSign() {
577
- throw new NotImplementedError(this.generateSasStringToSign.name);
578
- }
579
- generateSasUrl(options) {
580
- return Promise.resolve(getMockSasUrl(this.url, options.permissions, "c"));
581
- }
582
- generateUserDelegationSasStringToSign() {
583
- throw new NotImplementedError(this.generateUserDelegationSasStringToSign.name);
584
- }
585
- generateUserDelegationSasUrl() {
586
- throw new NotImplementedError(this.generateUserDelegationSasUrl.name);
587
- }
588
- getAccessPolicy() {
589
- throw new NotImplementedError(this.getAccessPolicy.name);
590
- }
591
- getAccountInfo() {
592
- throw new NotImplementedError(this.getAccountInfo.name);
593
- }
594
- getAppendBlobClient() {
595
- throw new NotImplementedError(this.getAppendBlobClient.name);
596
- }
597
- getBlobBatchClient() {
598
- return new MockBlobBatchClient(this.url);
599
- }
600
- getBlobClient(blobName) {
601
- return new MockBlockBlobClient(this.connectionString, this.containerName, blobName);
602
- }
603
- getBlobLeaseClient() {
604
- throw new NotImplementedError(this.getBlobLeaseClient.name);
605
- }
606
- getBlockBlobClient(blobName) {
607
- return new MockBlockBlobClient(this.connectionString, this.containerName, blobName);
608
- }
609
- getPageBlobClient() {
610
- throw new NotImplementedError(this.getPageBlobClient.name);
611
- }
612
- getProperties() {
613
- throw new NotImplementedError(this.getProperties.name);
614
- }
615
- listBlobsByHierarchy(delimiter, options) {
616
- const blobHierarchyItemIterator = this.#getBlobHierarchyItemIterator(delimiter, options);
617
- return {
618
- byPage: () => async function* () {
619
- const allBlobItems = [];
620
- const allBlobItemXml = [];
621
- const allBlobPrefixes = [];
622
- const allBlobPrefixXml = [];
623
- for await (const blobHierarchyItem of blobHierarchyItemIterator) if (blobHierarchyItem.kind === "blob") {
624
- allBlobItems.push(blobHierarchyItem);
625
- allBlobItemXml.push(getBlobItemXml(blobHierarchyItem));
626
- } else {
627
- allBlobPrefixes.push({ name: blobHierarchyItem.name });
628
- allBlobPrefixXml.push(getBlobPrefixXml(blobHierarchyItem.name));
629
- }
630
- if (allBlobItems.length > 0 || allBlobPrefixes.length > 0) yield await Promise.resolve(getListBlobsSegmentResponse(this.containerName, options?.prefix ?? "", {
631
- blobItems: allBlobItems,
632
- blobPrefixes: allBlobPrefixes
633
- }, `${allBlobItemXml.join("")}${allBlobPrefixXml.join("")}`));
634
- }.bind(this)(),
635
- next: blobHierarchyItemIterator.next.bind(blobHierarchyItemIterator),
636
- [Symbol.asyncIterator]() {
637
- return this;
638
- }
639
- };
640
- }
641
- listBlobsFlat(options) {
642
- const blobItemIterator = this.#getBlobItemIterator(options);
643
- return {
644
- byPage: () => async function* () {
645
- const allBlobItems = [];
646
- const allBlobItemXml = [];
647
- for await (const blobItem of blobItemIterator) {
648
- allBlobItems.push(blobItem);
649
- allBlobItemXml.push(getBlobItemXml(blobItem));
650
- }
651
- if (allBlobItems.length > 0) yield await Promise.resolve(getListBlobsSegmentResponse(this.containerName, options?.prefix ?? "", { blobItems: allBlobItems }, allBlobItemXml.join("")));
652
- }.bind(this)(),
653
- next: blobItemIterator.next.bind(blobItemIterator),
654
- [Symbol.asyncIterator]() {
655
- return this;
656
- }
657
- };
658
- }
659
- setAccessPolicy() {
660
- throw new NotImplementedError(this.setAccessPolicy.name);
661
- }
662
- setMetadata() {
663
- throw new NotImplementedError(this.setMetadata.name);
664
- }
665
- async uploadBlockBlob(blobName, body, contentLength) {
666
- const blockBlobClient = this.getBlockBlobClient(blobName);
667
- return {
668
- blockBlobClient,
669
- response: await blockBlobClient.upload(body, contentLength)
670
- };
671
- }
672
- async *#getBlobHierarchyItemIterator(delimiter, options) {
673
- const prefix = options?.prefix ?? "";
674
- const uniqueSubprefixes = /* @__PURE__ */ new Set();
675
- const blobsInCurrentLevel = [];
676
- for (const [name, buffer] of this.container.entries()) {
677
- if (!name.startsWith(prefix)) continue;
678
- const nameAfterPrefix = name.slice(prefix.length);
679
- const delimiterIndex = nameAfterPrefix.indexOf(delimiter);
680
- if (delimiterIndex === -1) blobsInCurrentLevel.push(this.#getBlobItem(name, buffer, options?.includeMetadata));
681
- else {
682
- const subprefix = `${prefix}${nameAfterPrefix.slice(0, delimiterIndex + delimiter.length)}`;
683
- uniqueSubprefixes.add(subprefix);
684
- }
685
- }
686
- for (const prefixName of [...uniqueSubprefixes].toSorted()) yield await Promise.resolve({
687
- kind: "prefix",
688
- name: prefixName
689
- });
690
- for (const blobItem of blobsInCurrentLevel) yield await Promise.resolve({
691
- kind: "blob",
692
- ...blobItem
693
- });
694
- }
695
- #getBlobItem(name, buffer, isMetadataIncluded) {
696
- const { createdOn, etag, lastModified } = readMockBlobDates(this.containerName, name);
697
- return {
698
- deleted: false,
699
- ...isMetadataIncluded && { metadata: readMockBlobMetadata(this.containerName, name) },
700
- name,
701
- properties: {
702
- blobType: "BlockBlob",
703
- contentLength: buffer.length,
704
- contentType: "application/octet-stream",
705
- createdOn,
706
- etag,
707
- lastModified,
708
- leaseState: "available",
709
- leaseStatus: "unlocked"
710
- },
711
- snapshot: ""
712
- };
713
- }
714
- async *#getBlobItemIterator(options) {
715
- const prefix = options?.prefix ?? "";
716
- for (const [name, buffer] of this.container.entries()) {
717
- if (!name.startsWith(prefix)) continue;
718
- yield await Promise.resolve(this.#getBlobItem(name, buffer, options?.includeMetadata));
719
- }
720
- }
721
- };
722
- //#endregion
723
- //#region src/store/MockEventGridDatabase.ts
724
- const MockEventGridDatabase = /* @__PURE__ */ new Map();
725
- //#endregion
726
- //#region src/models/eventGrid/MockEventGridPublisherClient.ts
727
- /**
728
- * An in-memory mock of the Azure EventGridPublisherClient — no emulator and no network.
729
- * `client` is excluded because it is a private member of the real class and cannot be satisfied structurally.
730
- */
731
- var MockEventGridPublisherClient = class {
732
- endpointUrl;
733
- inputSchema;
734
- topicType;
735
- constructor(endpoint, topicType) {
736
- this.endpointUrl = endpoint;
737
- this.topicType = topicType;
738
- this.inputSchema = topicType;
739
- }
740
- send(newEvents) {
741
- getOrCreate(MockEventGridDatabase, this.endpointUrl, () => []).push(...newEvents);
742
- return Promise.resolve();
743
- }
744
- };
745
- //#endregion
746
- //#region src/services/queue/getMockQueueMessageItem.ts
747
- const getMockQueueMessageItem = (messageText) => {
748
- const insertedOn = /* @__PURE__ */ new Date();
749
- return {
750
- expiresOn: new Date(insertedOn.getTime() + AZURE_MAX_QUEUE_VISIBILITY_TIMEOUT_MS),
751
- insertedOn,
752
- messageId: crypto.randomUUID(),
753
- messageText
754
- };
755
- };
756
- //#endregion
757
- //#region src/store/MockQueueDatabase.ts
758
- const MockQueueDatabase = /* @__PURE__ */ new Map();
759
- //#endregion
760
- //#region src/models/queue/MockQueueClient.ts
761
- /**
762
- * An in-memory mock of the Azure QueueClient — no emulator and no network.
763
- *
764
- * @example
765
- * const mockQueueClient = new MockQueueClient("", "hello world");
766
- * await mockQueueClient.createIfNotExists();
767
- * await mockQueueClient.sendMessage("hello world");
768
- * const messages = await mockQueueClient.peekMessages();
769
- */
770
- var MockQueueClient = class {
771
- connectionString;
772
- name;
773
- url;
774
- get queue() {
775
- return getOrCreate(MockQueueDatabase, this.name, () => []);
776
- }
777
- constructor(connectionString, queueName) {
778
- this.connectionString = connectionString;
779
- this.name = queueName;
780
- this.url = `${MOCK_QUEUE_BASE_URL}/${this.name}`;
781
- }
782
- clearMessages() {
783
- throw new NotImplementedError(this.clearMessages.name);
784
- }
785
- create(_options) {
786
- throw new NotImplementedError(this.create.name);
787
- }
788
- createIfNotExists() {
789
- throw new NotImplementedError(this.createIfNotExists.name);
790
- }
791
- delete() {
792
- throw new NotImplementedError(this.delete.name);
793
- }
794
- deleteIfExists() {
795
- throw new NotImplementedError(this.deleteIfExists.name);
796
- }
797
- deleteMessage() {
798
- throw new NotImplementedError(this.deleteMessage.name);
799
- }
800
- exists() {
801
- throw new NotImplementedError(this.exists.name);
802
- }
803
- generateSasStringToSign() {
804
- throw new NotImplementedError(this.generateSasStringToSign.name);
805
- }
806
- generateSasUrl(options) {
807
- return getMockSasUrl(this.url, options.permissions);
808
- }
809
- generateUserDelegationSasUrl() {
810
- throw new NotImplementedError(this.generateUserDelegationSasUrl.name);
811
- }
812
- generateUserDelegationStringToSign() {
813
- throw new NotImplementedError(this.generateUserDelegationStringToSign.name);
814
- }
815
- getAccessPolicy() {
816
- throw new NotImplementedError(this.getAccessPolicy.name);
817
- }
818
- getProperties() {
819
- throw new NotImplementedError(this.getProperties.name);
820
- }
821
- getServiceProperties() {
822
- throw new NotImplementedError(this.getServiceProperties.name);
823
- }
824
- listQueues() {
825
- throw new NotImplementedError(this.listQueues.name);
826
- }
827
- peekMessages(_options) {
828
- const peekedMessageItems = this.queue.map((text) => ({
829
- dequeueCount: 0,
830
- ...getMockQueueMessageItem(text)
831
- }));
832
- return Promise.resolve({
833
- _response: {
834
- ...createMockResponse(200, this.url),
835
- bodyAsText: "",
836
- parsedBody: peekedMessageItems
837
- },
838
- peekedMessageItems
839
- });
840
- }
841
- receiveMessages(_options) {
842
- const queuedTexts = this.queue;
843
- MockQueueDatabase.set(this.name, []);
844
- const receivedMessageItems = queuedTexts.map((text) => Object.assign(getMockQueueMessageItem(text), {
845
- dequeueCount: 1,
846
- nextVisibleOn: /* @__PURE__ */ new Date(),
847
- popReceipt: crypto.randomUUID()
848
- }));
849
- return Promise.resolve({
850
- _response: {
851
- ...createMockResponse(200, this.url),
852
- bodyAsText: "",
853
- parsedBody: receivedMessageItems
854
- },
855
- receivedMessageItems
856
- });
857
- }
858
- sendMessage(messageText, _options) {
859
- this.queue.push(messageText);
860
- const { expiresOn, insertedOn, messageId } = getMockQueueMessageItem(messageText);
861
- const enqueuedMessage = {
862
- expiresOn,
863
- insertedOn,
864
- messageId,
865
- nextVisibleOn: insertedOn,
866
- popReceipt: crypto.randomUUID()
867
- };
868
- const enqueuedMessages = [enqueuedMessage];
869
- return Promise.resolve({
870
- _response: {
871
- ...createMockResponse(200, this.url),
872
- bodyAsText: "",
873
- parsedBody: enqueuedMessages
874
- },
875
- ...enqueuedMessage
876
- });
877
- }
878
- setAccessPolicy(_identifiers) {
879
- throw new NotImplementedError(this.setAccessPolicy.name);
880
- }
881
- setMetadata() {
882
- throw new NotImplementedError(this.setMetadata.name);
883
- }
884
- updateMessage() {
885
- throw new NotImplementedError(this.updateMessage.name);
886
- }
887
- };
888
- //#endregion
889
- //#region src/services/filter/checkIsNullClause.ts
890
- const checkIsNullClause = (clause) => {
891
- const tableNullClause = getTableNullClause(clause.key);
892
- return checkIsDeepEqual(clause, tableNullClause);
893
- };
894
- //#endregion
895
- //#region src/services/filter/compare.ts
896
- const compare = (operator, leftHandSide, rightHandSide) => {
897
- if (rightHandSide === null || rightHandSide === void 0) {
898
- if (operator !== BinaryOperator.Eq) throw new InvalidOperationError(Operation.Read, compare.name, JSON.stringify({
899
- leftHandSide,
900
- operator,
901
- rightHandSide
902
- }));
903
- return leftHandSide === null || leftHandSide === void 0;
904
- }
905
- switch (operator) {
906
- case BinaryOperator.Eq: return leftHandSide === rightHandSide;
907
- case BinaryOperator.Ge: return leftHandSide >= rightHandSide;
908
- case BinaryOperator.Gt: return leftHandSide > rightHandSide;
909
- case BinaryOperator.Le: return leftHandSide <= rightHandSide;
910
- case BinaryOperator.Lt: return leftHandSide < rightHandSide;
911
- case BinaryOperator.Ne: return leftHandSide !== rightHandSide;
912
- default: return exhaustiveGuard(operator);
913
- }
914
- };
915
- //#endregion
916
- //#region src/services/filter/createFilterPredicate.ts
917
- const createFilterPredicate = (filter) => {
918
- 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) => {
919
- const clause = deserializeClause(clauseString);
920
- return {
921
- clause,
922
- isNull: checkIsNullClause(clause)
923
- };
924
- }));
925
- return (document) => {
926
- for (const orGroup of orGroups) {
927
- let isGroupMatched = false;
928
- for (const { clause, isNull } of orGroup) {
929
- const value = takeOne(document, clause.key);
930
- let isMatched;
931
- if (isNull) isMatched = compare(BinaryOperator.Eq, value, null);
932
- else {
933
- const comparisonResult = compare(clause.operator, value, clause.value);
934
- isMatched = clause.not ? !comparisonResult : comparisonResult;
935
- }
936
- if (isMatched) {
937
- isGroupMatched = true;
938
- break;
939
- }
940
- }
941
- if (!isGroupMatched) return false;
942
- }
943
- return true;
944
- };
945
- };
946
- //#endregion
947
- //#region src/store/MockSearchDatabase.ts
948
- const MockSearchDatabase = /* @__PURE__ */ new Map();
949
- //#endregion
950
- //#region src/models/search/MockSearchClient.ts
951
- const toComparable = (value) => {
952
- if (value instanceof Date) return value.getTime();
953
- else if (typeof value === "number" || typeof value === "string") return value;
954
- else return String(value);
955
- };
956
- const compareValues = (firstValue, secondValue) => {
957
- const firstComparable = toComparable(firstValue);
958
- const secondComparable = toComparable(secondValue);
959
- if (typeof firstComparable === "number" && typeof secondComparable === "number") return firstComparable - secondComparable;
960
- else return String(firstComparable).localeCompare(String(secondComparable));
961
- };
962
- const sortDocuments = (documents, orderBy) => {
963
- const parsedOrderBy = orderBy.map((clause) => {
964
- const [field = "", direction = "asc"] = clause.split(/\s+/u);
965
- return {
966
- direction,
967
- key: deserializeKey(field)
968
- };
969
- });
970
- return documents.toSorted((firstDocument, secondDocument) => {
971
- for (const { direction, key } of parsedOrderBy) {
972
- const comparison = compareValues(firstDocument[key], secondDocument[key]);
973
- if (comparison !== 0) return direction === "desc" ? -comparison : comparison;
974
- }
975
- return 0;
976
- });
977
- };
978
- const getSearchFieldValues = (value, pathSegments) => {
979
- if (pathSegments.length === 0) return [value];
980
- else if (Array.isArray(value)) return value.flatMap((item) => getSearchFieldValues(item, pathSegments));
981
- else if (typeof value === "object" && value !== null) {
982
- const [field = "", ...remainingPathSegments] = pathSegments;
983
- return getSearchFieldValues(value[deserializeKey(field)], remainingPathSegments);
984
- } else return [];
985
- };
986
- const searchDocuments = (documents, searchText, searchFields) => {
987
- if (!searchText || searchText === "*") return documents;
988
- const normalizedSearchText = searchText.toLocaleLowerCase();
989
- const searchFieldPaths = searchFields?.map((searchField) => searchField.split("/"));
990
- 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))));
991
- };
992
- /**
993
- * An in-memory mock of the Azure SearchClient — no emulator and no network. It applies the same OData filtering
994
- * as the other mock clients, so a query behaves the same here as it does against the service.
995
- *
996
- * @example
997
- * const mockSearchClient = new MockSearchClient(SearchIndex.Messages);
998
- * await mockSearchClient.uploadDocuments([{ ... }]);
999
- * const { count, results } = await mockSearchClient.search("*", { filter, includeTotalCount: true });
1000
- */
1001
- var MockSearchClient = class {
1002
- apiVersion = "";
1003
- endpoint = MOCK_SEARCH_BASE_URL;
1004
- indexName;
1005
- serviceVersion = "";
1006
- get documents() {
1007
- return getOrCreate(MockSearchDatabase, this.indexName, () => []);
1008
- }
1009
- constructor(indexName) {
1010
- this.indexName = indexName;
1011
- }
1012
- autocomplete() {
1013
- throw new NotImplementedError(this.autocomplete.name);
1014
- }
1015
- deleteDocuments() {
1016
- throw new NotImplementedError(this.deleteDocuments.name);
1017
- }
1018
- getDocument(_key, _options) {
1019
- throw new NotImplementedError(this.getDocument.name);
1020
- }
1021
- getDocumentsCount(_options) {
1022
- return Promise.resolve(this.documents.length);
1023
- }
1024
- indexDocuments(_batch, _options) {
1025
- throw new NotImplementedError(this.indexDocuments.name);
1026
- }
1027
- mergeDocuments(_documents, _options) {
1028
- throw new NotImplementedError(this.mergeDocuments.name);
1029
- }
1030
- mergeOrUploadDocuments(_documents, _options) {
1031
- throw new NotImplementedError(this.mergeOrUploadDocuments.name);
1032
- }
1033
- search(searchText, options) {
1034
- const { filter, includeTotalCount, orderBy, searchFields, skip = 0, top } = options ?? {};
1035
- let documents = searchDocuments(this.documents, searchText, searchFields);
1036
- if (filter) {
1037
- const predicate = createFilterPredicate(filter);
1038
- documents = documents.filter((document) => predicate(document));
1039
- }
1040
- if (orderBy) documents = sortDocuments(documents, orderBy);
1041
- const count = documents.length;
1042
- const paginatedDocuments = documents.slice(skip, top === void 0 ? void 0 : skip + top);
1043
- const results = { async *[Symbol.asyncIterator]() {
1044
- for (const document of paginatedDocuments) yield { document };
1045
- } };
1046
- return Promise.resolve({
1047
- ...includeTotalCount ? { count } : {},
1048
- results
1049
- });
1050
- }
1051
- suggest(_searchText, _suggesterName, _options) {
1052
- throw new NotImplementedError(this.suggest.name);
1053
- }
1054
- uploadDocuments(documents, _options) {
1055
- this.documents.push(...documents);
1056
- return Promise.resolve({ results: [] });
1057
- }
1058
- };
1059
- //#endregion
1060
- //#region src/store/MockServiceBusDatabase.ts
1061
- const MockServiceBusDatabase = /* @__PURE__ */ new Map();
1062
- //#endregion
1063
- //#region src/models/serviceBus/MockServiceBusSender.ts
1064
- /**
1065
- * An in-memory mock of the Azure ServiceBusSender — no emulator and no network.
1066
- *
1067
- * @example
1068
- * const mockServiceBusSender = new MockServiceBusSender("hello world");
1069
- * await mockServiceBusSender.scheduleMessages({ body: "hello world" }, new Date());
1070
- */
1071
- var MockServiceBusSender = class {
1072
- entityPath;
1073
- identifier;
1074
- isClosed = false;
1075
- get queue() {
1076
- return getOrCreate(MockServiceBusDatabase, this.entityPath, () => []);
1077
- }
1078
- constructor(queueName) {
1079
- this.entityPath = queueName;
1080
- this.identifier = queueName;
1081
- }
1082
- cancelScheduledMessages() {
1083
- throw new NotImplementedError(this.cancelScheduledMessages.name);
1084
- }
1085
- close() {
1086
- this.isClosed = true;
1087
- return Promise.resolve();
1088
- }
1089
- createMessageBatch() {
1090
- throw new NotImplementedError(this.createMessageBatch.name);
1091
- }
1092
- scheduleMessages(messages, scheduledEnqueueTimeUtc) {
1093
- for (const message of Array.isArray(messages) ? messages : [messages]) this.queue.push({
1094
- ...message,
1095
- scheduledEnqueueTimeUtc
1096
- });
1097
- return Promise.resolve([]);
1098
- }
1099
- sendMessages(messages) {
1100
- if (!Array.isArray(messages) && "tryAddMessage" in messages) throw new NotImplementedError(`${this.sendMessages.name}(ServiceBusMessageBatch)`);
1101
- this.queue.push(...Array.isArray(messages) ? messages : [messages]);
1102
- return Promise.resolve();
1103
- }
1104
- };
1105
- //#endregion
1106
- //#region src/services/table/compareByCompositeKey.ts
1107
- const compareByCompositeKey = (firstEntity, secondEntity) => {
1108
- if (firstEntity.partitionKey !== secondEntity.partitionKey) return firstEntity.partitionKey < secondEntity.partitionKey ? -1 : 1;
1109
- else if (firstEntity.rowKey === secondEntity.rowKey) return 0;
1110
- else return firstEntity.rowKey < secondEntity.rowKey ? -1 : 1;
1111
- };
1112
- //#endregion
1113
- //#region src/store/MockTableDatabase.ts
1114
- const MockTableDatabase = /* @__PURE__ */ new Map();
1115
- //#endregion
1116
- //#region src/models/table/MockTableClient.ts
1117
- /**
1118
- * An in-memory mock of the Azure TableClient — no emulator and no network.
1119
- *
1120
- * @example
1121
- * const mockTableClient = new MockTableClient("", "hello world");
1122
- * await mockTableClient.createEntity({ partitionKey: "partitionKey", rowKey: "rowKey" });
1123
- * const entity = await mockTableClient.getEntity("partitionKey", "rowKey");
1124
- */
1125
- var MockTableClient = class {
1126
- tableName;
1127
- url;
1128
- get table() {
1129
- return getOrCreate(MockTableDatabase, this.tableName, () => /* @__PURE__ */ new Map());
1130
- }
1131
- constructor(_url, tableName) {
1132
- this.tableName = tableName;
1133
- this.url = `${MOCK_TABLE_BASE_URL}/${this.tableName}`;
1134
- }
1135
- createEntity(entity) {
1136
- this.#applyCreate(entity);
1137
- return Promise.resolve({
1138
- date: /* @__PURE__ */ new Date(),
1139
- etag: this.#getEtag()
1140
- });
1141
- }
1142
- createTable() {
1143
- throw new NotImplementedError(this.createTable.name);
1144
- }
1145
- deleteEntity(partitionKey, rowKey, options) {
1146
- this.#applyDelete(partitionKey, rowKey, options?.etag);
1147
- return Promise.resolve({});
1148
- }
1149
- deleteTable() {
1150
- throw new NotImplementedError(this.deleteTable.name);
1151
- }
1152
- getAccessPolicy() {
1153
- throw new NotImplementedError(this.getAccessPolicy.name);
1154
- }
1155
- getEntity(partitionKey, rowKey) {
1156
- const key = this.#getCompositeKey(partitionKey, rowKey);
1157
- const entity = this.table.get(key);
1158
- if (!entity) throw new MockRestError("The specified resource does not exist.", 404);
1159
- return Promise.resolve({
1160
- ...entity,
1161
- etag: entity.etag ?? this.#getEtag()
1162
- });
1163
- }
1164
- listEntities(options) {
1165
- const withMetadata = this.#withMetadata.bind(this);
1166
- const filter = options?.queryOptions?.filter;
1167
- const tableEntities = [...this.table.values()];
1168
- const predicate = filter ? createFilterPredicate(filter) : void 0;
1169
- const resultTableEntities = (predicate ? tableEntities.filter((entity) => predicate(entity)) : tableEntities).toSorted(compareByCompositeKey);
1170
- const entityIterator = (async function* (entities) {
1171
- for (const entity of entities) yield await Promise.resolve(withMetadata(entity));
1172
- })(resultTableEntities);
1173
- return {
1174
- byPage: ({ maxPageSize } = {}) => (async function* (entities) {
1175
- if (maxPageSize !== void 0 && maxPageSize <= 0) throw new RangeError("maxPageSize must be greater than 0.");
1176
- else if (maxPageSize !== void 0 && maxPageSize > AZURE_MAX_PAGE_SIZE) throw new MockRestError("One of the request inputs is not valid.", 400);
1177
- if (entities.length === 0) return;
1178
- else if (!maxPageSize) {
1179
- yield await Promise.resolve(entities.map((entity) => withMetadata(entity)));
1180
- return;
1181
- }
1182
- for (const page of chunk(entities, maxPageSize)) yield await Promise.resolve(page.map((entity) => withMetadata(entity)));
1183
- })(resultTableEntities),
1184
- next: () => entityIterator.next(),
1185
- [Symbol.asyncIterator]() {
1186
- return this;
1187
- }
1188
- };
1189
- }
1190
- setAccessPolicy() {
1191
- throw new NotImplementedError(this.setAccessPolicy.name);
1192
- }
1193
- submitTransaction(actions) {
1194
- let partitionKey;
1195
- for (const [, entity] of actions) if (partitionKey === void 0) partitionKey = entity.partitionKey;
1196
- else if (entity.partitionKey !== partitionKey) throw new MockRestError("All transaction actions must target the same partitionKey.", 400);
1197
- const snapshot = new Map(this.table);
1198
- getResult(() => {
1199
- for (const [type, entity, updateMode] of actions) switch (type) {
1200
- case "create":
1201
- this.#applyCreate(entity);
1202
- break;
1203
- case "delete":
1204
- this.#applyDelete(entity.partitionKey, entity.rowKey);
1205
- break;
1206
- case "update":
1207
- this.#applyUpdate(entity, updateMode);
1208
- break;
1209
- case "upsert":
1210
- this.#applyUpsert(entity, updateMode);
1211
- break;
1212
- default: exhaustiveGuard(type);
1213
- }
1214
- }).orTee(() => {
1215
- this.table.clear();
1216
- for (const [key, value] of snapshot) this.table.set(key, value);
1217
- }).match(noop, (error) => {
1218
- throw error;
1219
- });
1220
- return Promise.resolve({
1221
- getResponseForEntity: () => void 0,
1222
- status: 202,
1223
- subResponses: []
1224
- });
1225
- }
1226
- updateEntity(entity, mode = "Merge", options) {
1227
- this.#applyUpdate(entity, mode, options?.etag);
1228
- return Promise.resolve({
1229
- date: /* @__PURE__ */ new Date(),
1230
- etag: this.#getEtag()
1231
- });
1232
- }
1233
- upsertEntity(entity, mode = "Merge") {
1234
- this.#applyUpsert(entity, mode);
1235
- return Promise.resolve({
1236
- date: /* @__PURE__ */ new Date(),
1237
- etag: this.#getEtag()
1238
- });
1239
- }
1240
- #applyCreate(entity) {
1241
- const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
1242
- if (this.table.has(key)) throw new MockRestError("The specified entity already exists.", 409);
1243
- this.table.set(key, {
1244
- ...entity,
1245
- etag: this.#getEtag()
1246
- });
1247
- }
1248
- #applyDelete(partitionKey, rowKey, etag) {
1249
- const key = this.#getCompositeKey(partitionKey, rowKey);
1250
- const existingEntity = this.table.get(key);
1251
- if (!existingEntity) throw new MockRestError("The specified resource does not exist.", 404);
1252
- this.#assertEtag(existingEntity.etag, etag);
1253
- this.table.delete(key);
1254
- }
1255
- #applyUpdate(entity, mode = "Merge", etag) {
1256
- const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
1257
- const existingEntity = this.table.get(key);
1258
- if (!existingEntity) throw new MockRestError("The specified resource does not exist.", 404);
1259
- this.#assertEtag(existingEntity.etag, etag);
1260
- this.#writeEntity(key, entity, mode, existingEntity);
1261
- }
1262
- #applyUpsert(entity, mode = "Merge") {
1263
- const key = this.#getCompositeKey(entity.partitionKey, entity.rowKey);
1264
- const existingEntity = this.table.get(key);
1265
- this.#writeEntity(key, entity, mode, existingEntity);
1266
- }
1267
- #assertEtag(existingEtag, etag) {
1268
- if (etag !== void 0 && etag !== "*" && etag !== existingEtag) throw new MockRestError("The update condition specified in the request was not satisfied.", 412);
1269
- }
1270
- #getCompositeKey(partitionKey, rowKey) {
1271
- return `${encodeURIComponent(partitionKey)}${ID_SEPARATOR}${encodeURIComponent(rowKey)}`;
1272
- }
1273
- #getEtag() {
1274
- return `W/"${crypto.randomUUID()}"`;
1275
- }
1276
- #withMetadata(entity) {
1277
- return {
1278
- ...entity,
1279
- etag: entity.etag ?? this.#getEtag()
1280
- };
1281
- }
1282
- #writeEntity(key, entity, mode, existingEntity) {
1283
- if (existingEntity && mode === "Merge") this.table.set(key, {
1284
- ...existingEntity,
1285
- ...entity,
1286
- etag: this.#getEtag()
1287
- });
1288
- else this.table.set(key, {
1289
- ...entity,
1290
- etag: this.#getEtag()
1291
- });
1292
- }
1293
- };
1294
- //#endregion
1295
- //#region src/models/webPubSub/MockWebPubSubServiceClient.ts
1296
- /**
1297
- * A minimal mock of the Azure WebPubSubServiceClient for testing purposes.
1298
- * Only implements `group().sendToAll` — the only method used in azure-functions tests.
1299
- */
1300
- var MockWebPubSubServiceClient = class {
1301
- group(_groupName) {
1302
- return { sendToAll: () => Promise.resolve() };
1303
- }
1304
- };
1305
- //#endregion
1306
- //#region src/services/filter/applyFilter.ts
1307
- const applyFilter = (documents, clauses) => {
1308
- const predicate = createFilterPredicate(serializeClauses(clauses));
1309
- return documents.filter((document) => predicate(document));
1310
- };
1311
- //#endregion
1312
- export { BLOB_NOT_FOUND_ERROR_CODE, BLOB_NOT_FOUND_MESSAGE, CONDITION_NOT_MET_ERROR_CODE, CONDITION_NOT_MET_MESSAGE, MOCK_BLOB_BASE_URL, MOCK_BLOB_SEEDED_DATE, MOCK_BLOB_SEEDED_PROPERTIES, MOCK_QUEUE_BASE_URL, MOCK_SEARCH_BASE_URL, MOCK_TABLE_BASE_URL, MockBlobBatchClient, MockBlobClient, MockBlockBlobClient, MockContainerBlobDatesDatabase, MockContainerBlobMetadataDatabase, MockContainerClient, MockContainerDatabase, MockEventGridDatabase, MockEventGridPublisherClient, MockQueueClient, MockQueueDatabase, MockRestError, MockSearchClient, MockSearchDatabase, MockServiceBusDatabase, MockServiceBusSender, MockTableClient, MockTableDatabase, MockWebPubSubServiceClient, NotImplementedError, applyFilter, bodyToBuffer, checkIsNullClause, checkIsReadableStream, compare, compareByCompositeKey, createFilterPredicate, createMockResponse, deleteMockBlob, getAzureErrorXml, getBlobItemXml, getBlobPrefixXml, getBlobUrl, getBlobUrlParts, getListBlobsSegmentResponse, getListBlobsXml, getMockBlobKey, getMockContainer, getMockQueueMessageItem, getMockSasUrl, readMockBlobDates, readMockBlobMetadata, storeMockBlobMetadata, storeMockBlobWrite, toWebResourceLike };