azure-mock 2.7.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/LICENSE +201 -0
- package/README.md +45 -0
- package/dist/index.d.ts +839 -0
- package/dist/index.js +1054 -0
- package/package.json +38 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1054 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
|
|
3
|
+
//#region src/models/MockRestError.ts
|
|
4
|
+
var MockRestError = class extends Error {
|
|
5
|
+
statusCode;
|
|
6
|
+
constructor(message, statusCode) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "MockRestError";
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/util/isReadableStream.ts
|
|
15
|
+
const isReadableStream = (value) => value instanceof Readable;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region ../shared/dist/index.js
|
|
19
|
+
var InvalidOperationError = class extends Error {
|
|
20
|
+
constructor(operation, name, message) {
|
|
21
|
+
super(`Invalid operation: ${operation}, name: ${name}, ${message}`);
|
|
22
|
+
this.name = "InvalidOperationError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
let Operation = /* @__PURE__ */ function(Operation$1) {
|
|
26
|
+
Operation$1["Create"] = "Create";
|
|
27
|
+
Operation$1["Delete"] = "Delete";
|
|
28
|
+
Operation$1["Push"] = "Push";
|
|
29
|
+
Operation$1["Read"] = "Read";
|
|
30
|
+
Operation$1["Update"] = "Update";
|
|
31
|
+
return Operation$1;
|
|
32
|
+
}({});
|
|
33
|
+
const css = String.raw;
|
|
34
|
+
const html = String.raw;
|
|
35
|
+
const ID_SEPARATOR = "|";
|
|
36
|
+
const streamToText = async (readable) => {
|
|
37
|
+
readable.setEncoding("utf8");
|
|
38
|
+
let data = "";
|
|
39
|
+
for await (const chunk of readable) data += chunk.toString();
|
|
40
|
+
return data;
|
|
41
|
+
};
|
|
42
|
+
const exhaustiveGuard = (value) => {
|
|
43
|
+
throw new InvalidOperationError(Operation.Read, exhaustiveGuard.name, JSON.stringify(value));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/util/bodyToBuffer.ts
|
|
48
|
+
const bodyToBuffer = async (body) => {
|
|
49
|
+
if (body === null) return Buffer.alloc(0);
|
|
50
|
+
else if (typeof body === "string") return Buffer.from(body);
|
|
51
|
+
else if (body instanceof ArrayBuffer) return Buffer.from(body);
|
|
52
|
+
else if (ArrayBuffer.isView(body)) return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
53
|
+
else if (typeof body === "function") {
|
|
54
|
+
const streamOrBlob = body();
|
|
55
|
+
return bodyToBuffer(streamOrBlob);
|
|
56
|
+
} else if (body instanceof Blob) {
|
|
57
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
58
|
+
return Buffer.from(arrayBuffer);
|
|
59
|
+
} else if (isReadableStream(body)) return Buffer.from(await streamToText(body));
|
|
60
|
+
else if (body instanceof ReadableStream) {
|
|
61
|
+
const reader = body.getReader();
|
|
62
|
+
const chunks = [];
|
|
63
|
+
while (true) {
|
|
64
|
+
const { done, value } = await reader.read();
|
|
65
|
+
if (done) break;
|
|
66
|
+
else chunks.push(value);
|
|
67
|
+
}
|
|
68
|
+
return Buffer.concat(chunks);
|
|
69
|
+
} else if (body instanceof FormData) throw new Error("FormData is not supported in this mock implementation.");
|
|
70
|
+
else exhaustiveGuard(body);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region ../../node_modules/.pnpm/@typespec+ts-http-runtime@0.2.3/node_modules/@typespec/ts-http-runtime/dist/browser/httpHeaders.js
|
|
75
|
+
function normalizeName(name) {
|
|
76
|
+
return name.toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
function* headerIterator(map) {
|
|
79
|
+
for (const entry of map.values()) yield [entry.name, entry.value];
|
|
80
|
+
}
|
|
81
|
+
var HttpHeadersImpl = class {
|
|
82
|
+
constructor(rawHeaders) {
|
|
83
|
+
this._headersMap = /* @__PURE__ */ new Map();
|
|
84
|
+
if (rawHeaders) for (const headerName of Object.keys(rawHeaders)) this.set(headerName, rawHeaders[headerName]);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Set a header in this collection with the provided name and value. The name is
|
|
88
|
+
* case-insensitive.
|
|
89
|
+
* @param name - The name of the header to set. This value is case-insensitive.
|
|
90
|
+
* @param value - The value of the header to set.
|
|
91
|
+
*/
|
|
92
|
+
set(name, value) {
|
|
93
|
+
this._headersMap.set(normalizeName(name), {
|
|
94
|
+
name,
|
|
95
|
+
value: String(value).trim()
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get the header value for the provided header name, or undefined if no header exists in this
|
|
100
|
+
* collection with the provided name.
|
|
101
|
+
* @param name - The name of the header. This value is case-insensitive.
|
|
102
|
+
*/
|
|
103
|
+
get(name) {
|
|
104
|
+
var _a$1;
|
|
105
|
+
return (_a$1 = this._headersMap.get(normalizeName(name))) === null || _a$1 === void 0 ? void 0 : _a$1.value;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get whether or not this header collection contains a header entry for the provided header name.
|
|
109
|
+
* @param name - The name of the header to set. This value is case-insensitive.
|
|
110
|
+
*/
|
|
111
|
+
has(name) {
|
|
112
|
+
return this._headersMap.has(normalizeName(name));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Remove the header with the provided headerName.
|
|
116
|
+
* @param name - The name of the header to remove.
|
|
117
|
+
*/
|
|
118
|
+
delete(name) {
|
|
119
|
+
this._headersMap.delete(normalizeName(name));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the JSON object representation of this HTTP header collection.
|
|
123
|
+
*/
|
|
124
|
+
toJSON(options = {}) {
|
|
125
|
+
const result = {};
|
|
126
|
+
if (options.preserveCase) for (const entry of this._headersMap.values()) result[entry.name] = entry.value;
|
|
127
|
+
else for (const [normalizedName, entry] of this._headersMap) result[normalizedName] = entry.value;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the string representation of this HTTP header collection.
|
|
132
|
+
*/
|
|
133
|
+
toString() {
|
|
134
|
+
return JSON.stringify(this.toJSON({ preserveCase: true }));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Iterate over tuples of header [name, value] pairs.
|
|
138
|
+
*/
|
|
139
|
+
[Symbol.iterator]() {
|
|
140
|
+
return headerIterator(this._headersMap);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Creates an object that satisfies the `HttpHeaders` interface.
|
|
145
|
+
* @param rawHeaders - A simple object representing initial headers
|
|
146
|
+
*/
|
|
147
|
+
function createHttpHeaders$1(rawHeaders) {
|
|
148
|
+
return new HttpHeadersImpl(rawHeaders);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region ../../node_modules/.pnpm/@typespec+ts-http-runtime@0.2.3/node_modules/@typespec/ts-http-runtime/dist/browser/util/uuidUtils.common.js
|
|
153
|
+
/**
|
|
154
|
+
* Generated Universally Unique Identifier
|
|
155
|
+
*
|
|
156
|
+
* @returns RFC4122 v4 UUID.
|
|
157
|
+
*/
|
|
158
|
+
function generateUUID() {
|
|
159
|
+
let uuid = "";
|
|
160
|
+
for (let i = 0; i < 32; i++) {
|
|
161
|
+
const randomNumber = Math.floor(Math.random() * 16);
|
|
162
|
+
if (i === 12) uuid += "4";
|
|
163
|
+
else if (i === 16) uuid += randomNumber & 3 | 8;
|
|
164
|
+
else uuid += randomNumber.toString(16);
|
|
165
|
+
if (i === 7 || i === 11 || i === 15 || i === 19) uuid += "-";
|
|
166
|
+
}
|
|
167
|
+
return uuid;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region ../../node_modules/.pnpm/@typespec+ts-http-runtime@0.2.3/node_modules/@typespec/ts-http-runtime/dist/browser/util/uuidUtils.js
|
|
172
|
+
var _a;
|
|
173
|
+
const uuidFunction = typeof ((_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.crypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === "function" ? globalThis.crypto.randomUUID.bind(globalThis.crypto) : generateUUID;
|
|
174
|
+
/**
|
|
175
|
+
* Generated Universally Unique Identifier
|
|
176
|
+
*
|
|
177
|
+
* @returns RFC4122 v4 UUID.
|
|
178
|
+
*/
|
|
179
|
+
function randomUUID() {
|
|
180
|
+
return uuidFunction();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ../../node_modules/.pnpm/@typespec+ts-http-runtime@0.2.3/node_modules/@typespec/ts-http-runtime/dist/browser/pipelineRequest.js
|
|
185
|
+
var PipelineRequestImpl = class {
|
|
186
|
+
constructor(options) {
|
|
187
|
+
var _a$1, _b, _c, _d, _e, _f, _g;
|
|
188
|
+
this.url = options.url;
|
|
189
|
+
this.body = options.body;
|
|
190
|
+
this.headers = (_a$1 = options.headers) !== null && _a$1 !== void 0 ? _a$1 : createHttpHeaders$1();
|
|
191
|
+
this.method = (_b = options.method) !== null && _b !== void 0 ? _b : "GET";
|
|
192
|
+
this.timeout = (_c = options.timeout) !== null && _c !== void 0 ? _c : 0;
|
|
193
|
+
this.multipartBody = options.multipartBody;
|
|
194
|
+
this.formData = options.formData;
|
|
195
|
+
this.disableKeepAlive = (_d = options.disableKeepAlive) !== null && _d !== void 0 ? _d : false;
|
|
196
|
+
this.proxySettings = options.proxySettings;
|
|
197
|
+
this.streamResponseStatusCodes = options.streamResponseStatusCodes;
|
|
198
|
+
this.withCredentials = (_e = options.withCredentials) !== null && _e !== void 0 ? _e : false;
|
|
199
|
+
this.abortSignal = options.abortSignal;
|
|
200
|
+
this.onUploadProgress = options.onUploadProgress;
|
|
201
|
+
this.onDownloadProgress = options.onDownloadProgress;
|
|
202
|
+
this.requestId = options.requestId || randomUUID();
|
|
203
|
+
this.allowInsecureConnection = (_f = options.allowInsecureConnection) !== null && _f !== void 0 ? _f : false;
|
|
204
|
+
this.enableBrowserStreams = (_g = options.enableBrowserStreams) !== null && _g !== void 0 ? _g : false;
|
|
205
|
+
this.requestOverrides = options.requestOverrides;
|
|
206
|
+
this.authSchemes = options.authSchemes;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Creates a new pipeline request with the given options.
|
|
211
|
+
* This method is to allow for the easy setting of default values and not required.
|
|
212
|
+
* @param options - The options to create the request with.
|
|
213
|
+
*/
|
|
214
|
+
function createPipelineRequest$1(options) {
|
|
215
|
+
return new PipelineRequestImpl(options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region ../../node_modules/.pnpm/@azure+core-rest-pipeline@1.21.0/node_modules/@azure/core-rest-pipeline/dist/browser/httpHeaders.js
|
|
220
|
+
/**
|
|
221
|
+
* Creates an object that satisfies the `HttpHeaders` interface.
|
|
222
|
+
* @param rawHeaders - A simple object representing initial headers
|
|
223
|
+
*/
|
|
224
|
+
function createHttpHeaders(rawHeaders) {
|
|
225
|
+
return createHttpHeaders$1(rawHeaders);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region ../../node_modules/.pnpm/@azure+core-rest-pipeline@1.21.0/node_modules/@azure/core-rest-pipeline/dist/browser/pipelineRequest.js
|
|
230
|
+
/**
|
|
231
|
+
* Creates a new pipeline request with the given options.
|
|
232
|
+
* This method is to allow for the easy setting of default values and not required.
|
|
233
|
+
* @param options - The options to create the request with.
|
|
234
|
+
*/
|
|
235
|
+
function createPipelineRequest(options) {
|
|
236
|
+
return createPipelineRequest$1(options);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region ../../node_modules/.pnpm/@azure+core-http-compat@2.3.0/node_modules/@azure/core-http-compat/dist/browser/util.js
|
|
241
|
+
const originalRequestSymbol = Symbol("Original PipelineRequest");
|
|
242
|
+
const originalClientRequestSymbol = Symbol.for("@azure/core-client original request");
|
|
243
|
+
/**
|
|
244
|
+
* Converts HttpHeaders from core-rest-pipeline to look like
|
|
245
|
+
* HttpHeaders from core-http.
|
|
246
|
+
* @param headers - HttpHeaders from core-rest-pipeline
|
|
247
|
+
* @returns HttpHeaders as they looked in core-http
|
|
248
|
+
*/
|
|
249
|
+
function toHttpHeadersLike(headers) {
|
|
250
|
+
return new HttpHeaders(headers.toJSON({ preserveCase: true }));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* A collection of HttpHeaders that can be sent with a HTTP request.
|
|
254
|
+
*/
|
|
255
|
+
function getHeaderKey(headerName) {
|
|
256
|
+
return headerName.toLowerCase();
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* A collection of HTTP header key/value pairs.
|
|
260
|
+
*/
|
|
261
|
+
var HttpHeaders = class HttpHeaders {
|
|
262
|
+
constructor(rawHeaders) {
|
|
263
|
+
this._headersMap = {};
|
|
264
|
+
if (rawHeaders) for (const headerName in rawHeaders) this.set(headerName, rawHeaders[headerName]);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Set a header in this collection with the provided name and value. The name is
|
|
268
|
+
* case-insensitive.
|
|
269
|
+
* @param headerName - The name of the header to set. This value is case-insensitive.
|
|
270
|
+
* @param headerValue - The value of the header to set.
|
|
271
|
+
*/
|
|
272
|
+
set(headerName, headerValue) {
|
|
273
|
+
this._headersMap[getHeaderKey(headerName)] = {
|
|
274
|
+
name: headerName,
|
|
275
|
+
value: headerValue.toString()
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get the header value for the provided header name, or undefined if no header exists in this
|
|
280
|
+
* collection with the provided name.
|
|
281
|
+
* @param headerName - The name of the header.
|
|
282
|
+
*/
|
|
283
|
+
get(headerName) {
|
|
284
|
+
const header = this._headersMap[getHeaderKey(headerName)];
|
|
285
|
+
return !header ? void 0 : header.value;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get whether or not this header collection contains a header entry for the provided header name.
|
|
289
|
+
*/
|
|
290
|
+
contains(headerName) {
|
|
291
|
+
return !!this._headersMap[getHeaderKey(headerName)];
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Remove the header with the provided headerName. Return whether or not the header existed and
|
|
295
|
+
* was removed.
|
|
296
|
+
* @param headerName - The name of the header to remove.
|
|
297
|
+
*/
|
|
298
|
+
remove(headerName) {
|
|
299
|
+
const result = this.contains(headerName);
|
|
300
|
+
delete this._headersMap[getHeaderKey(headerName)];
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get the headers that are contained this collection as an object.
|
|
305
|
+
*/
|
|
306
|
+
rawHeaders() {
|
|
307
|
+
return this.toJson({ preserveCase: true });
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get the headers that are contained in this collection as an array.
|
|
311
|
+
*/
|
|
312
|
+
headersArray() {
|
|
313
|
+
const headers = [];
|
|
314
|
+
for (const headerKey in this._headersMap) headers.push(this._headersMap[headerKey]);
|
|
315
|
+
return headers;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Get the header names that are contained in this collection.
|
|
319
|
+
*/
|
|
320
|
+
headerNames() {
|
|
321
|
+
const headerNames = [];
|
|
322
|
+
const headers = this.headersArray();
|
|
323
|
+
for (let i = 0; i < headers.length; ++i) headerNames.push(headers[i].name);
|
|
324
|
+
return headerNames;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get the header values that are contained in this collection.
|
|
328
|
+
*/
|
|
329
|
+
headerValues() {
|
|
330
|
+
const headerValues = [];
|
|
331
|
+
const headers = this.headersArray();
|
|
332
|
+
for (let i = 0; i < headers.length; ++i) headerValues.push(headers[i].value);
|
|
333
|
+
return headerValues;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Get the JSON object representation of this HTTP header collection.
|
|
337
|
+
*/
|
|
338
|
+
toJson(options = {}) {
|
|
339
|
+
const result = {};
|
|
340
|
+
if (options.preserveCase) for (const headerKey in this._headersMap) {
|
|
341
|
+
const header = this._headersMap[headerKey];
|
|
342
|
+
result[header.name] = header.value;
|
|
343
|
+
}
|
|
344
|
+
else for (const headerKey in this._headersMap) {
|
|
345
|
+
const header = this._headersMap[headerKey];
|
|
346
|
+
result[getHeaderKey(header.name)] = header.value;
|
|
347
|
+
}
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get the string representation of this HTTP header collection.
|
|
352
|
+
*/
|
|
353
|
+
toString() {
|
|
354
|
+
return JSON.stringify(this.toJson({ preserveCase: true }));
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Create a deep clone/copy of this HttpHeaders collection.
|
|
358
|
+
*/
|
|
359
|
+
clone() {
|
|
360
|
+
const resultPreservingCasing = {};
|
|
361
|
+
for (const headerKey in this._headersMap) {
|
|
362
|
+
const header = this._headersMap[headerKey];
|
|
363
|
+
resultPreservingCasing[header.name] = header.value;
|
|
364
|
+
}
|
|
365
|
+
return new HttpHeaders(resultPreservingCasing);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/util/toWebResourceLike.ts
|
|
371
|
+
const toWebResourceLike = (request) => ({
|
|
372
|
+
abortSignal: request.abortSignal,
|
|
373
|
+
agent: request.agent,
|
|
374
|
+
body: request.body,
|
|
375
|
+
clone: () => {
|
|
376
|
+
throw new Error("Cannot clone a non-proxied WebResourceLike");
|
|
377
|
+
},
|
|
378
|
+
formData: request.formData,
|
|
379
|
+
headers: toHttpHeadersLike(request.headers),
|
|
380
|
+
keepAlive: request.disableKeepAlive,
|
|
381
|
+
method: request.method,
|
|
382
|
+
onDownloadProgress: request.onDownloadProgress,
|
|
383
|
+
onUploadProgress: request.onUploadProgress,
|
|
384
|
+
prepare: () => {
|
|
385
|
+
throw new Error("WebResourceLike.prepare() is not supported by @azure/core-http-compat");
|
|
386
|
+
},
|
|
387
|
+
proxySettings: request.proxySettings,
|
|
388
|
+
requestId: request.headers.get("x-ms-client-request-id") ?? request.requestId,
|
|
389
|
+
requestOverrides: request.requestOverrides,
|
|
390
|
+
streamResponseStatusCodes: request.streamResponseStatusCodes,
|
|
391
|
+
timeout: request.timeout,
|
|
392
|
+
url: request.url,
|
|
393
|
+
validateRequestProperties: () => {},
|
|
394
|
+
withCredentials: request.withCredentials
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
//#endregion
|
|
398
|
+
//#region ../../node_modules/.pnpm/@azure+storage-blob@12.27.0/node_modules/@azure/storage-blob/dist-esm/storage-blob/src/policies/RequestPolicy.js
|
|
399
|
+
/**
|
|
400
|
+
* The base class from which all request policies derive.
|
|
401
|
+
*/
|
|
402
|
+
var BaseRequestPolicy = class {
|
|
403
|
+
/**
|
|
404
|
+
* The main method to implement that manipulates a request/response.
|
|
405
|
+
*/
|
|
406
|
+
constructor(_nextPolicy, _options) {
|
|
407
|
+
this._nextPolicy = _nextPolicy;
|
|
408
|
+
this._options = _options;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get whether or not a log with the provided log level should be logged.
|
|
412
|
+
* @param logLevel - The log level of the log that will be logged.
|
|
413
|
+
* @returns Whether or not a log with the provided log level should be logged.
|
|
414
|
+
*/
|
|
415
|
+
shouldLog(logLevel) {
|
|
416
|
+
return this._options.shouldLog(logLevel);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Attempt to log the provided message to the provided logger. If no logger was provided or if
|
|
420
|
+
* the log level does not meat the logger's threshold, then nothing will be logged.
|
|
421
|
+
* @param logLevel - The log level of this log.
|
|
422
|
+
* @param message - The message of this log.
|
|
423
|
+
*/
|
|
424
|
+
log(logLevel, message) {
|
|
425
|
+
this._options.log(logLevel, message);
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region ../../node_modules/.pnpm/@azure+storage-blob@12.27.0/node_modules/@azure/storage-blob/dist-esm/storage-blob/src/policies/CredentialPolicy.js
|
|
431
|
+
/**
|
|
432
|
+
* Credential policy used to sign HTTP(S) requests before sending. This is an
|
|
433
|
+
* abstract class.
|
|
434
|
+
*/
|
|
435
|
+
var CredentialPolicy = class extends BaseRequestPolicy {
|
|
436
|
+
/**
|
|
437
|
+
* Sends out request.
|
|
438
|
+
*
|
|
439
|
+
* @param request -
|
|
440
|
+
*/
|
|
441
|
+
sendRequest(request) {
|
|
442
|
+
return this._nextPolicy.sendRequest(this.signRequest(request));
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Child classes must implement this method with request signing. This method
|
|
446
|
+
* will be executed in {@link sendRequest}.
|
|
447
|
+
*
|
|
448
|
+
* @param request -
|
|
449
|
+
*/
|
|
450
|
+
signRequest(request) {
|
|
451
|
+
return request;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region ../../node_modules/.pnpm/@azure+storage-blob@12.27.0/node_modules/@azure/storage-blob/dist-esm/storage-blob/src/policies/AnonymousCredentialPolicy.js
|
|
457
|
+
/**
|
|
458
|
+
* AnonymousCredentialPolicy is used with HTTP(S) requests that read public resources
|
|
459
|
+
* or for use with Shared Access Signatures (SAS).
|
|
460
|
+
*/
|
|
461
|
+
var AnonymousCredentialPolicy = class extends CredentialPolicy {
|
|
462
|
+
/**
|
|
463
|
+
* Creates an instance of AnonymousCredentialPolicy.
|
|
464
|
+
* @param nextPolicy -
|
|
465
|
+
* @param options -
|
|
466
|
+
*/
|
|
467
|
+
constructor(nextPolicy, options) {
|
|
468
|
+
super(nextPolicy, options);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region ../../node_modules/.pnpm/@azure+storage-blob@12.27.0/node_modules/@azure/storage-blob/dist-esm/storage-blob/src/credentials/Credential.js
|
|
474
|
+
/**
|
|
475
|
+
* Credential is an abstract class for Azure Storage HTTP requests signing. This
|
|
476
|
+
* class will host an credentialPolicyCreator factory which generates CredentialPolicy.
|
|
477
|
+
*/
|
|
478
|
+
var Credential = class {
|
|
479
|
+
/**
|
|
480
|
+
* Creates a RequestPolicy object.
|
|
481
|
+
*
|
|
482
|
+
* @param _nextPolicy -
|
|
483
|
+
* @param _options -
|
|
484
|
+
*/
|
|
485
|
+
create(_nextPolicy, _options) {
|
|
486
|
+
throw new Error("Method should be implemented in children classes.");
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region ../../node_modules/.pnpm/@azure+storage-blob@12.27.0/node_modules/@azure/storage-blob/dist-esm/storage-blob/src/credentials/AnonymousCredential.js
|
|
492
|
+
/**
|
|
493
|
+
* AnonymousCredential provides a credentialPolicyCreator member used to create
|
|
494
|
+
* AnonymousCredentialPolicy objects. AnonymousCredentialPolicy is used with
|
|
495
|
+
* HTTP(S) requests that read public resources or for use with Shared Access
|
|
496
|
+
* Signatures (SAS).
|
|
497
|
+
*/
|
|
498
|
+
var AnonymousCredential = class extends Credential {
|
|
499
|
+
/**
|
|
500
|
+
* Creates an {@link AnonymousCredentialPolicy} object.
|
|
501
|
+
*
|
|
502
|
+
* @param nextPolicy -
|
|
503
|
+
* @param options -
|
|
504
|
+
*/
|
|
505
|
+
create(nextPolicy, options) {
|
|
506
|
+
return new AnonymousCredentialPolicy(nextPolicy, options);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/models/MockBlockBlobClient.ts
|
|
512
|
+
var MockBlockBlobClient = class {
|
|
513
|
+
containerClient;
|
|
514
|
+
credential = new AnonymousCredential();
|
|
515
|
+
name;
|
|
516
|
+
url;
|
|
517
|
+
get containerName() {
|
|
518
|
+
return this.containerClient.containerName;
|
|
519
|
+
}
|
|
520
|
+
constructor(_connectionString, containerClient, blobName) {
|
|
521
|
+
this.containerClient = containerClient;
|
|
522
|
+
this.name = blobName;
|
|
523
|
+
this.url = `https://mockaccount.blob.core.windows.net/${this.containerName}/${this.name}`;
|
|
524
|
+
}
|
|
525
|
+
abortCopyFromURL() {
|
|
526
|
+
throw new Error("Method not implemented.");
|
|
527
|
+
}
|
|
528
|
+
beginCopyFromURL() {
|
|
529
|
+
throw new Error("Method not implemented.");
|
|
530
|
+
}
|
|
531
|
+
commitBlockList() {
|
|
532
|
+
throw new Error("Method not implemented.");
|
|
533
|
+
}
|
|
534
|
+
createSnapshot() {
|
|
535
|
+
throw new Error("Method not implemented.");
|
|
536
|
+
}
|
|
537
|
+
delete() {
|
|
538
|
+
if (!this.containerClient.blobs.has(this.name)) throw new MockRestError("The specified blob does not exist.", 404);
|
|
539
|
+
this.containerClient.blobs.delete(this.name);
|
|
540
|
+
return new Promise((resolve) => resolve({ _response: {
|
|
541
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
542
|
+
parsedHeaders: {},
|
|
543
|
+
request: toWebResourceLike(createPipelineRequest({ url: "" })),
|
|
544
|
+
status: 200
|
|
545
|
+
} }));
|
|
546
|
+
}
|
|
547
|
+
deleteIfExists() {
|
|
548
|
+
throw new Error("Method not implemented.");
|
|
549
|
+
}
|
|
550
|
+
deleteImmutabilityPolicy() {
|
|
551
|
+
throw new Error("Method not implemented.");
|
|
552
|
+
}
|
|
553
|
+
download() {
|
|
554
|
+
const buffer = this.containerClient.blobs.get(this.name);
|
|
555
|
+
return new Promise((resolve) => resolve({
|
|
556
|
+
_response: {
|
|
557
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
558
|
+
parsedHeaders: {},
|
|
559
|
+
request: toWebResourceLike(createPipelineRequest({ url: "" })),
|
|
560
|
+
status: buffer ? 200 : 404
|
|
561
|
+
},
|
|
562
|
+
readableStreamBody: buffer ? Readable.from(buffer) : void 0
|
|
563
|
+
}));
|
|
564
|
+
}
|
|
565
|
+
downloadToBuffer() {
|
|
566
|
+
const data = this.containerClient.blobs.get(this.name);
|
|
567
|
+
if (!data) throw new MockRestError("The specified blob does not exist.", 404);
|
|
568
|
+
return new Promise((resolve) => resolve(Buffer.from(data)));
|
|
569
|
+
}
|
|
570
|
+
downloadToFile() {
|
|
571
|
+
throw new Error("Method not implemented.");
|
|
572
|
+
}
|
|
573
|
+
exists() {
|
|
574
|
+
throw new Error("Method not implemented.");
|
|
575
|
+
}
|
|
576
|
+
generateSasStringToSign() {
|
|
577
|
+
throw new Error("Method not implemented.");
|
|
578
|
+
}
|
|
579
|
+
generateSasUrl() {
|
|
580
|
+
throw new Error("Method not implemented.");
|
|
581
|
+
}
|
|
582
|
+
generateUserDelegationSasStringToSign() {
|
|
583
|
+
throw new Error("Method not implemented.");
|
|
584
|
+
}
|
|
585
|
+
generateUserDelegationSasUrl() {
|
|
586
|
+
throw new Error("Method not implemented.");
|
|
587
|
+
}
|
|
588
|
+
getAccountInfo() {
|
|
589
|
+
throw new Error("Method not implemented.");
|
|
590
|
+
}
|
|
591
|
+
getAppendBlobClient() {
|
|
592
|
+
throw new Error("Method not implemented.");
|
|
593
|
+
}
|
|
594
|
+
getBlobLeaseClient() {
|
|
595
|
+
throw new Error("Method not implemented.");
|
|
596
|
+
}
|
|
597
|
+
getBlockBlobClient() {
|
|
598
|
+
throw new Error("Method not implemented.");
|
|
599
|
+
}
|
|
600
|
+
getBlockList() {
|
|
601
|
+
throw new Error("Method not implemented.");
|
|
602
|
+
}
|
|
603
|
+
getPageBlobClient() {
|
|
604
|
+
throw new Error("Method not implemented.");
|
|
605
|
+
}
|
|
606
|
+
getProperties() {
|
|
607
|
+
throw new Error("Method not implemented.");
|
|
608
|
+
}
|
|
609
|
+
getTags() {
|
|
610
|
+
throw new Error("Method not implemented.");
|
|
611
|
+
}
|
|
612
|
+
query() {
|
|
613
|
+
throw new Error("Method not implemented.");
|
|
614
|
+
}
|
|
615
|
+
setAccessTier() {
|
|
616
|
+
throw new Error("Method not implemented.");
|
|
617
|
+
}
|
|
618
|
+
setHTTPHeaders() {
|
|
619
|
+
throw new Error("Method not implemented.");
|
|
620
|
+
}
|
|
621
|
+
setImmutabilityPolicy() {
|
|
622
|
+
throw new Error("Method not implemented.");
|
|
623
|
+
}
|
|
624
|
+
setLegalHold() {
|
|
625
|
+
throw new Error("Method not implemented.");
|
|
626
|
+
}
|
|
627
|
+
setMetadata() {
|
|
628
|
+
throw new Error("Method not implemented.");
|
|
629
|
+
}
|
|
630
|
+
setTags() {
|
|
631
|
+
throw new Error("Method not implemented.");
|
|
632
|
+
}
|
|
633
|
+
stageBlock() {
|
|
634
|
+
throw new Error("Method not implemented.");
|
|
635
|
+
}
|
|
636
|
+
stageBlockFromURL() {
|
|
637
|
+
throw new Error("Method not implemented.");
|
|
638
|
+
}
|
|
639
|
+
syncCopyFromURL() {
|
|
640
|
+
throw new Error("Method not implemented.");
|
|
641
|
+
}
|
|
642
|
+
syncUploadFromURL() {
|
|
643
|
+
throw new Error("Method not implemented.");
|
|
644
|
+
}
|
|
645
|
+
undelete() {
|
|
646
|
+
throw new Error("Method not implemented.");
|
|
647
|
+
}
|
|
648
|
+
async upload(body, _contentLength) {
|
|
649
|
+
this.containerClient.blobs.set(this.name, await bodyToBuffer(body));
|
|
650
|
+
return { _response: {
|
|
651
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
652
|
+
parsedHeaders: {},
|
|
653
|
+
request: toWebResourceLike(createPipelineRequest({ url: "" })),
|
|
654
|
+
status: 201
|
|
655
|
+
} };
|
|
656
|
+
}
|
|
657
|
+
uploadBrowserData() {
|
|
658
|
+
throw new Error("Method not implemented.");
|
|
659
|
+
}
|
|
660
|
+
uploadData() {
|
|
661
|
+
throw new Error("Method not implemented.");
|
|
662
|
+
}
|
|
663
|
+
uploadFile() {
|
|
664
|
+
throw new Error("Method not implemented.");
|
|
665
|
+
}
|
|
666
|
+
uploadStream() {
|
|
667
|
+
throw new Error("Method not implemented.");
|
|
668
|
+
}
|
|
669
|
+
withSnapshot() {
|
|
670
|
+
throw new Error("Method not implemented.");
|
|
671
|
+
}
|
|
672
|
+
withVersion() {
|
|
673
|
+
throw new Error("Method not implemented.");
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
//#endregion
|
|
678
|
+
//#region src/util/getBlobItemXml.ts
|
|
679
|
+
const getBlobItemXml = ({ name, properties }) => html`<Blob>
|
|
680
|
+
<Name>${name}</Name>
|
|
681
|
+
<Properties>
|
|
682
|
+
<Last-Modified>${properties.lastModified.toUTCString()}</Last-Modified>
|
|
683
|
+
<Etag>${properties.etag}</Etag>
|
|
684
|
+
<Content-Length>${properties.contentLength}</Content-Length>
|
|
685
|
+
<Content-Type>${properties.contentType}</Content-Type>
|
|
686
|
+
<BlobType>BlockBlob</BlobType>
|
|
687
|
+
<LeaseStatus>unlocked</LeaseStatus>
|
|
688
|
+
<LeaseState>available</LeaseState>
|
|
689
|
+
</Properties>
|
|
690
|
+
</Blob>`;
|
|
691
|
+
|
|
692
|
+
//#endregion
|
|
693
|
+
//#region src/util/getBlobPrefixXml.ts
|
|
694
|
+
const getBlobPrefixXml = (name) => html`<BlobPrefix><Name>${name}</Name></BlobPrefix>`;
|
|
695
|
+
|
|
696
|
+
//#endregion
|
|
697
|
+
//#region src/models/MockContainerClient.ts
|
|
698
|
+
/**
|
|
699
|
+
* An in-memory mock of the Azure ContainerClient.
|
|
700
|
+
* It uses a Map to simulate blob storage.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* const mockContainerClient = new MockContainerClient("", "hello world");
|
|
704
|
+
* const blockBlobClient = mockContainerClient.getBlockBlobClient("hello world.txt");
|
|
705
|
+
* await blockBlobClient.upload("hello world", 11);
|
|
706
|
+
* const content = await blockBlobClient.downloadToBuffer();
|
|
707
|
+
*/
|
|
708
|
+
var MockContainerClient = class {
|
|
709
|
+
blobs = /* @__PURE__ */ new Map();
|
|
710
|
+
containerName;
|
|
711
|
+
credential = new AnonymousCredential();
|
|
712
|
+
url;
|
|
713
|
+
constructor(_connectionString, containerName) {
|
|
714
|
+
this.containerName = containerName;
|
|
715
|
+
this.url = `https://mockaccount.blob.core.windows.net/${this.containerName}`;
|
|
716
|
+
}
|
|
717
|
+
create() {
|
|
718
|
+
throw new Error("Method not implemented.");
|
|
719
|
+
}
|
|
720
|
+
createIfNotExists() {
|
|
721
|
+
throw new Error("Method not implemented.");
|
|
722
|
+
}
|
|
723
|
+
delete() {
|
|
724
|
+
throw new Error("Method not implemented.");
|
|
725
|
+
}
|
|
726
|
+
deleteBlob() {
|
|
727
|
+
throw new Error("Method not implemented.");
|
|
728
|
+
}
|
|
729
|
+
deleteIfExists() {
|
|
730
|
+
throw new Error("Method not implemented.");
|
|
731
|
+
}
|
|
732
|
+
exists() {
|
|
733
|
+
throw new Error("Method not implemented.");
|
|
734
|
+
}
|
|
735
|
+
findBlobsByTags() {
|
|
736
|
+
throw new Error("Method not implemented.");
|
|
737
|
+
}
|
|
738
|
+
generateSasStringToSign() {
|
|
739
|
+
throw new Error("Method not implemented.");
|
|
740
|
+
}
|
|
741
|
+
generateSasUrl() {
|
|
742
|
+
throw new Error("Method not implemented.");
|
|
743
|
+
}
|
|
744
|
+
generateUserDelegationSasStringToSign() {
|
|
745
|
+
throw new Error("Method not implemented.");
|
|
746
|
+
}
|
|
747
|
+
generateUserDelegationSasUrl() {
|
|
748
|
+
throw new Error("Method not implemented.");
|
|
749
|
+
}
|
|
750
|
+
getAccessPolicy() {
|
|
751
|
+
throw new Error("Method not implemented.");
|
|
752
|
+
}
|
|
753
|
+
getAccountInfo() {
|
|
754
|
+
throw new Error("Method not implemented.");
|
|
755
|
+
}
|
|
756
|
+
getAppendBlobClient() {
|
|
757
|
+
throw new Error("Method not implemented.");
|
|
758
|
+
}
|
|
759
|
+
getBlobBatchClient() {
|
|
760
|
+
throw new Error("Method not implemented.");
|
|
761
|
+
}
|
|
762
|
+
getBlobClient() {
|
|
763
|
+
throw new Error("Method not implemented.");
|
|
764
|
+
}
|
|
765
|
+
getBlobLeaseClient() {
|
|
766
|
+
throw new Error("Method not implemented.");
|
|
767
|
+
}
|
|
768
|
+
getBlockBlobClient(blobName) {
|
|
769
|
+
return new MockBlockBlobClient("", this, blobName);
|
|
770
|
+
}
|
|
771
|
+
getPageBlobClient() {
|
|
772
|
+
throw new Error("Method not implemented.");
|
|
773
|
+
}
|
|
774
|
+
getProperties() {
|
|
775
|
+
throw new Error("Method not implemented.");
|
|
776
|
+
}
|
|
777
|
+
listBlobsByHierarchy(delimiter, options) {
|
|
778
|
+
const blobHierarchyItemIterator = this.getBlobHierarchyItemIterator(delimiter, options);
|
|
779
|
+
return {
|
|
780
|
+
byPage: () => async function* () {
|
|
781
|
+
const allBlobItems = [];
|
|
782
|
+
const allBlobItemXml = [];
|
|
783
|
+
const allBlobPrefixes = [];
|
|
784
|
+
const allBlobPrefixXml = [];
|
|
785
|
+
for await (const blobHierarchyItem of blobHierarchyItemIterator) if (blobHierarchyItem.kind === "blob") {
|
|
786
|
+
allBlobItems.push(blobHierarchyItem);
|
|
787
|
+
allBlobItemXml.push(getBlobItemXml(blobHierarchyItem));
|
|
788
|
+
} else {
|
|
789
|
+
allBlobPrefixes.push({ name: blobHierarchyItem.name });
|
|
790
|
+
allBlobPrefixXml.push(getBlobPrefixXml(blobHierarchyItem.name));
|
|
791
|
+
}
|
|
792
|
+
if (allBlobItems.length > 0 || allBlobPrefixes.length > 0) yield await new Promise((resolve) => resolve({
|
|
793
|
+
_response: {
|
|
794
|
+
bodyAsText: html`<?xml version="1.0" encoding="utf8"?>
|
|
795
|
+
<EnumerationResults ServiceEndpoint="" ContainerName="${this.containerName}">
|
|
796
|
+
<Blobs>${allBlobItemXml.join("")}${allBlobPrefixXml.join("")}</Blobs>
|
|
797
|
+
<NextMarker />
|
|
798
|
+
</EnumerationResults>`,
|
|
799
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
800
|
+
parsedBody: {
|
|
801
|
+
containerName: this.containerName,
|
|
802
|
+
marker: "",
|
|
803
|
+
prefix: options?.prefix ?? "",
|
|
804
|
+
segment: { blobItems: allBlobItems },
|
|
805
|
+
serviceEndpoint: ""
|
|
806
|
+
},
|
|
807
|
+
parsedHeaders: {},
|
|
808
|
+
request: toWebResourceLike(createPipelineRequest({ url: "" })),
|
|
809
|
+
status: 200
|
|
810
|
+
},
|
|
811
|
+
containerName: this.containerName,
|
|
812
|
+
marker: "",
|
|
813
|
+
prefix: options?.prefix ?? "",
|
|
814
|
+
segment: { blobItems: allBlobItems },
|
|
815
|
+
serviceEndpoint: ""
|
|
816
|
+
}));
|
|
817
|
+
}.bind(this)(),
|
|
818
|
+
next: blobHierarchyItemIterator.next.bind(blobHierarchyItemIterator),
|
|
819
|
+
[Symbol.asyncIterator]() {
|
|
820
|
+
return this;
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
listBlobsFlat() {
|
|
825
|
+
const blobItemIterator = this.getBlobItemIterator();
|
|
826
|
+
return {
|
|
827
|
+
byPage: () => async function* () {
|
|
828
|
+
const allBlobItems = [];
|
|
829
|
+
const allBlobItemXml = [];
|
|
830
|
+
for await (const blobItem of blobItemIterator) {
|
|
831
|
+
allBlobItems.push(blobItem);
|
|
832
|
+
allBlobItemXml.push(getBlobItemXml(blobItem));
|
|
833
|
+
}
|
|
834
|
+
if (allBlobItems.length > 0) yield await new Promise((resolve) => resolve({
|
|
835
|
+
_response: {
|
|
836
|
+
bodyAsText: html`<?xml version="1.0" encoding="utf8"?>
|
|
837
|
+
<EnumerationResults ServiceEndpoint="" ContainerName="${this.containerName}">
|
|
838
|
+
<Blobs>${allBlobItemXml.join("")}</Blobs>
|
|
839
|
+
<NextMarker />
|
|
840
|
+
</EnumerationResults>`,
|
|
841
|
+
headers: toHttpHeadersLike(createHttpHeaders()),
|
|
842
|
+
parsedBody: {
|
|
843
|
+
containerName: this.containerName,
|
|
844
|
+
marker: "",
|
|
845
|
+
prefix: "",
|
|
846
|
+
segment: { blobItems: allBlobItems },
|
|
847
|
+
serviceEndpoint: ""
|
|
848
|
+
},
|
|
849
|
+
parsedHeaders: {},
|
|
850
|
+
request: toWebResourceLike(createPipelineRequest({ url: "" })),
|
|
851
|
+
status: 200
|
|
852
|
+
},
|
|
853
|
+
containerName: this.containerName,
|
|
854
|
+
marker: "",
|
|
855
|
+
prefix: "",
|
|
856
|
+
segment: { blobItems: allBlobItems },
|
|
857
|
+
serviceEndpoint: ""
|
|
858
|
+
}));
|
|
859
|
+
}.bind(this)(),
|
|
860
|
+
next: blobItemIterator.next.bind(blobItemIterator),
|
|
861
|
+
[Symbol.asyncIterator]() {
|
|
862
|
+
return this;
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
setAccessPolicy() {
|
|
867
|
+
throw new Error("Method not implemented.");
|
|
868
|
+
}
|
|
869
|
+
setMetadata() {
|
|
870
|
+
throw new Error("Method not implemented.");
|
|
871
|
+
}
|
|
872
|
+
async uploadBlockBlob(blobName, body, contentLength) {
|
|
873
|
+
const blockBlobClient = this.getBlockBlobClient(blobName);
|
|
874
|
+
return {
|
|
875
|
+
blockBlobClient,
|
|
876
|
+
response: await blockBlobClient.upload(body, contentLength)
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
async *getBlobHierarchyItemIterator(delimiter, options) {
|
|
880
|
+
const prefix = options?.prefix ?? "";
|
|
881
|
+
const uniqueSubprefixes = /* @__PURE__ */ new Set();
|
|
882
|
+
const blobsInCurrentLevel = [];
|
|
883
|
+
for (const [name, buffer] of this.blobs.entries()) {
|
|
884
|
+
if (!name.startsWith(prefix)) continue;
|
|
885
|
+
const nameAfterPrefix = name.slice(prefix.length);
|
|
886
|
+
const delimiterIndex = nameAfterPrefix.indexOf(delimiter);
|
|
887
|
+
if (delimiterIndex === -1) blobsInCurrentLevel.push({
|
|
888
|
+
deleted: false,
|
|
889
|
+
name,
|
|
890
|
+
properties: {
|
|
891
|
+
blobType: "BlockBlob",
|
|
892
|
+
contentLength: buffer.length,
|
|
893
|
+
contentType: "application/octet-stream",
|
|
894
|
+
etag: `"${crypto.randomUUID()}"`,
|
|
895
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
896
|
+
leaseState: "available",
|
|
897
|
+
leaseStatus: "unlocked"
|
|
898
|
+
},
|
|
899
|
+
snapshot: ""
|
|
900
|
+
});
|
|
901
|
+
else {
|
|
902
|
+
const subprefix = `${prefix}${nameAfterPrefix.slice(0, delimiterIndex + delimiter.length)}`;
|
|
903
|
+
uniqueSubprefixes.add(subprefix);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
for (const prefixName of [...uniqueSubprefixes].sort()) yield await new Promise((resolve) => resolve({
|
|
907
|
+
kind: "prefix",
|
|
908
|
+
name: prefixName
|
|
909
|
+
}));
|
|
910
|
+
for (const blobItem of blobsInCurrentLevel) yield await new Promise((resolve) => resolve({
|
|
911
|
+
kind: "blob",
|
|
912
|
+
...blobItem
|
|
913
|
+
}));
|
|
914
|
+
}
|
|
915
|
+
async *getBlobItemIterator() {
|
|
916
|
+
for (const [name, buffer] of this.blobs.entries()) yield await new Promise((resolve) => resolve({
|
|
917
|
+
deleted: false,
|
|
918
|
+
name,
|
|
919
|
+
properties: {
|
|
920
|
+
blobType: "BlockBlob",
|
|
921
|
+
contentLength: buffer.length,
|
|
922
|
+
contentType: "application/octet-stream",
|
|
923
|
+
etag: `"${crypto.randomUUID()}"`,
|
|
924
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
925
|
+
leaseState: "available",
|
|
926
|
+
leaseStatus: "unlocked"
|
|
927
|
+
},
|
|
928
|
+
snapshot: ""
|
|
929
|
+
}));
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
//#endregion
|
|
934
|
+
//#region src/models/MockTableClient.ts
|
|
935
|
+
/**
|
|
936
|
+
* An in-memory mock of the Azure TableClient.
|
|
937
|
+
* It uses a Map to simulate table storage and correctly implements the TableClient interface.
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* const mockTableClient = new MockTableClient("", "hello world");
|
|
941
|
+
* await mockTableClient.createEntity({ partitionKey: "partitionKey", rowKey: "rowKey" });
|
|
942
|
+
* const entity = await mockTableClient.getEntity("partitionKey", "rowKey");
|
|
943
|
+
*/
|
|
944
|
+
var MockTableClient = class {
|
|
945
|
+
entities = /* @__PURE__ */ new Map();
|
|
946
|
+
tableName;
|
|
947
|
+
url;
|
|
948
|
+
constructor(_url, tableName) {
|
|
949
|
+
this.tableName = tableName;
|
|
950
|
+
this.url = `https://mockaccount.table.core.windows.net/${this.tableName}`;
|
|
951
|
+
}
|
|
952
|
+
createEntity(entity) {
|
|
953
|
+
const key = this.getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
954
|
+
if (this.entities.has(key)) throw new MockRestError("The specified entity already exists.", 409);
|
|
955
|
+
const storedEntity = this.withMetadata(entity);
|
|
956
|
+
this.entities.set(key, storedEntity);
|
|
957
|
+
return new Promise((resolve) => resolve({
|
|
958
|
+
date: /* @__PURE__ */ new Date(),
|
|
959
|
+
etag: storedEntity.etag
|
|
960
|
+
}));
|
|
961
|
+
}
|
|
962
|
+
createTable() {
|
|
963
|
+
throw new Error("Method not implemented.");
|
|
964
|
+
}
|
|
965
|
+
deleteEntity(partitionKey, rowKey) {
|
|
966
|
+
const key = this.getCompositeKey(partitionKey, rowKey);
|
|
967
|
+
if (!this.entities.has(key)) throw new MockRestError("The specified resource does not exist.", 404);
|
|
968
|
+
this.entities.delete(key);
|
|
969
|
+
return new Promise((resolve) => resolve({}));
|
|
970
|
+
}
|
|
971
|
+
deleteTable() {
|
|
972
|
+
throw new Error("Method not implemented.");
|
|
973
|
+
}
|
|
974
|
+
getAccessPolicy() {
|
|
975
|
+
throw new Error("Method not implemented.");
|
|
976
|
+
}
|
|
977
|
+
getEntity(partitionKey, rowKey) {
|
|
978
|
+
const key = this.getCompositeKey(partitionKey, rowKey);
|
|
979
|
+
const entity = this.entities.get(key);
|
|
980
|
+
if (!entity) throw new MockRestError("The specified resource does not exist.", 404);
|
|
981
|
+
const entityWithMetadata = this.withMetadata(entity);
|
|
982
|
+
return new Promise((resolve) => resolve(entityWithMetadata));
|
|
983
|
+
}
|
|
984
|
+
listEntities() {
|
|
985
|
+
const withMetadata = this.withMetadata.bind(this);
|
|
986
|
+
return {
|
|
987
|
+
byPage: () => async function* (entities) {
|
|
988
|
+
const allEntitiesWithMetadata = [...entities.values()].map(withMetadata);
|
|
989
|
+
if (allEntitiesWithMetadata.length > 0) yield await new Promise((resolve) => resolve(allEntitiesWithMetadata));
|
|
990
|
+
}(this.entities),
|
|
991
|
+
next: () => async function* (entities) {
|
|
992
|
+
for (const entity of entities.values()) {
|
|
993
|
+
const entityWithMetadata = withMetadata(entity);
|
|
994
|
+
yield await new Promise((resolve) => resolve(entityWithMetadata));
|
|
995
|
+
}
|
|
996
|
+
}(this.entities).next(),
|
|
997
|
+
[Symbol.asyncIterator]() {
|
|
998
|
+
return this;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
setAccessPolicy() {
|
|
1003
|
+
throw new Error("Method not implemented.");
|
|
1004
|
+
}
|
|
1005
|
+
submitTransaction() {
|
|
1006
|
+
throw new Error("Method not implemented.");
|
|
1007
|
+
}
|
|
1008
|
+
updateEntity(entity, mode = "Merge") {
|
|
1009
|
+
const key = this.getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1010
|
+
const existingEntity = this.entities.get(key);
|
|
1011
|
+
if (!existingEntity) throw new MockRestError("The specified resource does not exist.", 404);
|
|
1012
|
+
else if (mode === "Merge") return this.mergeEntity(key, existingEntity, entity);
|
|
1013
|
+
const newEntityWithMetadata = this.withMetadata(entity);
|
|
1014
|
+
this.entities.set(key, newEntityWithMetadata);
|
|
1015
|
+
return new Promise((resolve) => resolve({
|
|
1016
|
+
date: /* @__PURE__ */ new Date(),
|
|
1017
|
+
etag: newEntityWithMetadata.etag
|
|
1018
|
+
}));
|
|
1019
|
+
}
|
|
1020
|
+
upsertEntity(entity, mode = "Merge") {
|
|
1021
|
+
const key = this.getCompositeKey(entity.partitionKey, entity.rowKey);
|
|
1022
|
+
const existingEntity = this.entities.get(key);
|
|
1023
|
+
if (existingEntity && mode === "Merge") return this.mergeEntity(key, existingEntity, entity);
|
|
1024
|
+
const newEntity = this.withMetadata(entity);
|
|
1025
|
+
this.entities.set(key, newEntity);
|
|
1026
|
+
return new Promise((resolve) => resolve({
|
|
1027
|
+
date: /* @__PURE__ */ new Date(),
|
|
1028
|
+
etag: newEntity.etag
|
|
1029
|
+
}));
|
|
1030
|
+
}
|
|
1031
|
+
getCompositeKey(partitionKey, rowKey) {
|
|
1032
|
+
return `${partitionKey}${ID_SEPARATOR}${rowKey}`;
|
|
1033
|
+
}
|
|
1034
|
+
mergeEntity(key, entity, entityToMerge) {
|
|
1035
|
+
const mergedEntityWithMetadata = this.withMetadata({
|
|
1036
|
+
...entity,
|
|
1037
|
+
...entityToMerge
|
|
1038
|
+
});
|
|
1039
|
+
this.entities.set(key, mergedEntityWithMetadata);
|
|
1040
|
+
return new Promise((resolve) => resolve({
|
|
1041
|
+
date: /* @__PURE__ */ new Date(),
|
|
1042
|
+
etag: mergedEntityWithMetadata.etag
|
|
1043
|
+
}));
|
|
1044
|
+
}
|
|
1045
|
+
withMetadata(entity) {
|
|
1046
|
+
return {
|
|
1047
|
+
...entity,
|
|
1048
|
+
etag: `W/"datetime'${(/* @__PURE__ */ new Date()).toISOString()}'"`
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
//#endregion
|
|
1054
|
+
export { MockBlockBlobClient, MockContainerClient, MockRestError, MockTableClient, bodyToBuffer, getBlobItemXml, getBlobPrefixXml, isReadableStream, toWebResourceLike };
|