[ts-http-runtime] Update ts-http-runtime with recent Core changes (#31487)

### Packages impacted by this PR

- `@typespec/ts-http-runtime`

### Describe the problem that is addressed by this PR

Updating the unbranded Core package with some recent changes in Core
that didn't make it over.
This commit is contained in:
Timo van Veenendaal 2024-10-22 08:33:04 -07:00 коммит произвёл GitHub
Родитель 5d53a80f0f
Коммит 7c51b1e579
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
20 изменённых файлов: 199 добавлений и 541 удалений

Просмотреть файл

@ -300,7 +300,7 @@ index 9db25cf..df8291c 100644
/**
* Represents a credential defined by a static API key.
diff --git a/src/auth/tokenCredential.ts b/src/auth/tokenCredential.ts
index ff71b14..73ee5c0 100644
index ff71b14..a8903bb 100644
--- a/src/auth/tokenCredential.ts
+++ b/src/auth/tokenCredential.ts
@@ -1,9 +1,8 @@
@ -344,16 +344,10 @@ index ff71b14..73ee5c0 100644
}
/**
@@ -97,32 +74,6 @@ export interface AccessToken {
* The access token's expiration timestamp in milliseconds, UNIX epoch time.
@@ -103,26 +80,7 @@ export interface AccessToken {
*/
expiresOnTimestamp: number;
-
- /**
- * The timestamp when the access token should be refreshed, in milliseconds, UNIX epoch time.
- */
- refreshAfterTimestamp?: number;
-
refreshAfterTimestamp?: number;
- /** Type of token - `Bearer` or `pop` */
- tokenType?: "Bearer" | "pop";
-}
@ -374,6 +368,7 @@ index ff71b14..73ee5c0 100644
- */
-export function isPopToken(accessToken: AccessToken): boolean {
- return accessToken.tokenType === "pop";
+ // UNBRANDED DIFFERENCE: Unbranded Core does not support PoP ("Proof-of-Presence") tokens.
}
/**
@ -467,10 +462,10 @@ index b7a7a6d..56553a5 100644
if (!cachedHttpClient) {
cachedHttpClient = createDefaultHttpClient();
diff --git a/src/client/common.ts b/src/client/common.ts
index 916c4d5..a8fd8aa 100644
index 916c4d5..a5f6d91 100644
--- a/src/client/common.ts
+++ b/src/client/common.ts
@@ -3,22 +3,21 @@
@@ -3,19 +3,18 @@
import {
HttpClient,
@ -496,12 +491,8 @@ index 916c4d5..a8fd8aa 100644
+import { LogPolicyOptions } from "../policies/logPolicy.js";
/**
- * Shape of the default request parameters, this may be overridden by the specific
+ * Shape of the default request parameters, this may be overriden by the specific
* request types to provide strong types
*/
export type RequestParameters = {
@@ -91,16 +90,8 @@ export type RequestParameters = {
* Shape of the default request parameters, this may be overridden by the specific
@@ -91,16 +90,9 @@ export type RequestParameters = {
* A function to be called each time a response is received from the server
* while performing the requested operation.
* May be called multiple times.
@ -515,16 +506,13 @@ index 916c4d5..a8fd8aa 100644
- error?: unknown,
- __legacyError?: unknown,
-) => void;
+// UNBRANDED DIFFERENCE: onResponse callback does not have a second __legacyError parameter which was provided for backwards compatibility
+export type RawResponseCallback = (rawResponse: FullOperationResponse, error?: unknown) => void;
/**
* Wrapper object for http request and response. Deserialized object is stored in
@@ -199,10 +190,10 @@ export interface Client {
pipeline: Pipeline;
/**
* This method will be used to send request that would check the path to provide
- * strong types. When used by the codegen this type gets overridden with the generated
+ * strong types. When used by the codegen this type gets overriden wit the generated
@@ -202,7 +194,7 @@ export interface Client {
* strong types. When used by the codegen this type gets overridden with the generated
* types. For example:
* ```typescript snippet:path_example
- * import { Client, Routes } from "@azure-rest/core-client";
@ -532,27 +520,21 @@ index 916c4d5..a8fd8aa 100644
*
* export type MyClient = Client & {
* path: Routes;
@@ -398,10 +389,7 @@ export type PathParameters<
// additional parameters we can call RouteParameters recursively on the Tail to match the remaining parts,
// in case the Tail has more parameters, it will return a tuple with the parameters found in tail.
// We spread the second path params to end up with a single dimension tuple at the end.
- [
- pathParameter: string | number | PathParameterWithOptions,
- ...pathParameters: PathParameters<Tail>,
- ]
+ [pathParameter: string | PathParameterWithOptions, ...pathParameters: PathParameters<Tail>]
: // When the path doesn't match the template, it means that we have no path parameters so we return
// an empty tuple.
[];
@@ -441,7 +429,7 @@ export interface PathParameterWithOptions {
@@ -326,11 +318,9 @@ export type ClientOptions = PipelineOptions & {
*/
apiKeyHeaderName?: string;
};
- /**
- * Base url for the client
- * @deprecated This property is deprecated and will be removed soon, please use endpoint instead
- */
- baseUrl?: string;
+
+ // UNBRANDED DIFFERENCE: The deprecated baseUrl property is removed in favor of the endpoint property in the unbranded Core package
+
/**
* The value of the parameter.
* Endpoint for the client
*/
- value: string | number;
+ value: string;
/**
* Whether to allow for reserved characters in the value. If set to true, special characters such as '/' in the parameter's value will not be URL encoded.
diff --git a/src/client/dom.d.ts b/src/client/dom.d.ts
deleted file mode 100644
index eabe718..0000000
@ -564,14 +546,14 @@ index eabe718..0000000
-
-/// <reference lib="dom" />
diff --git a/src/client/getClient.ts b/src/client/getClient.ts
index 1eefed4..95c2416 100644
index 549d26f..4029937 100644
--- a/src/client/getClient.ts
+++ b/src/client/getClient.ts
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { KeyCredential, TokenCredential, isTokenCredential } from "@azure/core-auth";
-import { KeyCredential, TokenCredential, isKeyCredential, isTokenCredential } from "@azure/core-auth";
-import { HttpClient, HttpMethods, Pipeline, PipelineOptions } from "@azure/core-rest-pipeline";
+import { TokenCredential, isTokenCredential } from "../auth/tokenCredential.js";
+import { KeyCredential, isKeyCredential } from "../auth/keyCredential.js";
@ -593,31 +575,17 @@ index 1eefed4..95c2416 100644
/**
* Creates a client with a default pipeline
@@ -59,10 +63,9 @@ export function getClient(
}
@@ -60,8 +64,8 @@ export function getClient(
const { allowInsecureConnection, httpClient } = clientOptions;
- const endpointUrl = clientOptions.endpoint ?? endpoint;
const endpointUrl = clientOptions.endpoint ?? endpoint;
- const client = (path: string, ...args: Array<any>) => {
- const getUrl = (requestOptions: RequestParameters) =>
- buildRequestUrl(endpointUrl, path, args, { allowInsecureConnection, ...requestOptions });
+ const client = (path: string, ...args: Array<any>): ResourceMethods<StreamableMethod> => {
+ const getUrl = (requestOptions: RequestParameters): string =>
+ buildRequestUrl(endpoint, path, args, { allowInsecureConnection, ...requestOptions });
buildRequestUrl(endpointUrl, path, args, { allowInsecureConnection, ...requestOptions });
return {
get: (requestOptions: RequestParameters = {}): StreamableMethod => {
@@ -198,9 +201,5 @@ function buildOperation(
function isCredential(
param: (TokenCredential | KeyCredential) | PipelineOptions,
): param is TokenCredential | KeyCredential {
- if ((param as KeyCredential).key !== undefined || isTokenCredential(param)) {
- return true;
- }
-
- return false;
+ return isKeyCredential(param) || isTokenCredential(param);
}
diff --git a/src/client/helpers/isBinaryBody.ts b/src/client/helpers/isBinaryBody.ts
deleted file mode 100644
index ef06c77..0000000
@ -766,7 +734,7 @@ index b85a503..9d98299 100644
/**
diff --git a/src/client/sendRequest.ts b/src/client/sendRequest.ts
index 9a96a4a..e884392 100644
index 9a96a4a..de08109 100644
--- a/src/client/sendRequest.ts
+++ b/src/client/sendRequest.ts
@@ -5,17 +5,16 @@ import {
@ -783,7 +751,7 @@ index 9a96a4a..e884392 100644
- isRestError,
-} from "@azure/core-rest-pipeline";
+} from "../interfaces.js";
+import { RestError } from "../restError.js";
+import { isRestError, RestError } from "../restError.js";
+import { Pipeline } from "../pipeline.js";
+import { createHttpHeaders } from "../httpHeaders.js";
+import { createPipelineRequest } from "../pipelineRequest.js";
@ -793,99 +761,16 @@ index 9a96a4a..e884392 100644
import { HttpResponse, RequestParameters } from "./common.js";
import { PartDescriptor, buildMultipartBody } from "./multipart.js";
@@ -37,8 +36,6 @@ export async function sendRequest(
): Promise<HttpResponse> {
const httpClient = customHttpClient ?? getCachedDefaultHttpsClient();
const request = buildPipelineRequest(method, url, options);
-
- try {
const response = await pipeline.sendRequest(httpClient, request);
const headers = response.headers.toJSON();
const stream = response.readableStreamBody ?? response.browserStreamBody;
@@ -56,15 +53,6 @@ export async function sendRequest(
status: `${response.status}`,
body,
};
- } catch (e: unknown) {
- if (isRestError(e) && e.response && options.onResponse) {
- const { response } = e;
- const rawHeaders = response.headers.toJSON();
@@ -60,7 +59,8 @@ export async function sendRequest(
if (isRestError(e) && e.response && options.onResponse) {
const { response } = e;
const rawHeaders = response.headers.toJSON();
- options?.onResponse({ ...response, request, rawHeaders }, e, e);
- }
-
- throw e;
- }
}
/**
@@ -166,15 +154,17 @@ function getRequestBody(body?: unknown, contentType: string = ""): RequestBody {
return { body };
}
+ const firstType = contentType.split(";")[0];
+
+ if (firstType === "application/json") {
+ return { body: JSON.stringify(body) };
+ }
+
if (ArrayBuffer.isView(body)) {
return { body: body instanceof Uint8Array ? body : JSON.stringify(body) };
}
- const firstType = contentType.split(";")[0];
-
switch (firstType) {
- case "application/json":
- return { body: JSON.stringify(body) };
case "multipart/form-data":
if (Array.isArray(body)) {
return { multipartBody: buildMultipartBody(body as PartDescriptor[]) };
@@ -197,7 +187,7 @@ function getResponseBody(response: PipelineResponse): RequestBodyType | undefine
// Set the default response type
const contentType = response.headers.get("content-type") ?? "";
const firstType = contentType.split(";")[0];
- const bodyToParse = response.bodyAsText ?? "";
+ const bodyToParse: string = response.bodyAsText ?? "";
if (firstType === "text/plain") {
return String(bodyToParse);
diff --git a/src/client/urlHelpers.ts b/src/client/urlHelpers.ts
index e052e7e..56f98d0 100644
--- a/src/client/urlHelpers.ts
+++ b/src/client/urlHelpers.ts
@@ -54,7 +54,7 @@ function isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions
export function buildRequestUrl(
endpoint: string,
routePath: string,
- pathParameters: (string | number | PathParameterWithOptions)[],
+ pathParameters: (string | PathParameterWithOptions)[],
options: RequestParameters = {},
): string {
if (routePath.startsWith("https://") || routePath.startsWith("http://")) {
@@ -187,18 +187,19 @@ export function buildBaseUrl(endpoint: string, options: RequestParameters): stri
function buildRoutePath(
routePath: string,
- pathParameters: (string | number | PathParameterWithOptions)[],
+ pathParameters: (string | PathParameterWithOptions)[],
options: RequestParameters = {},
): string {
for (const pathParam of pathParameters) {
- const allowReserved = typeof pathParam === "object" && (pathParam.allowReserved ?? false);
- let value = typeof pathParam === "object" ? pathParam.value : pathParam;
+ const allowReserved =
+ typeof pathParam === "string" ? false : (pathParam?.allowReserved ?? false);
+ let value = typeof pathParam === "string" ? pathParam : pathParam?.value;
if (!options.skipUrlEncoding && !allowReserved) {
value = encodeURIComponent(value);
+ // UNBRANDED DIFFERENCE: onResponse callback does not have a second __legacyError property
+ options?.onResponse({ ...response, request, rawHeaders }, e);
}
- routePath = routePath.replace(/\{\w+\}/, String(value));
+ routePath = routePath.replace(/\{\w+\}/, value);
}
return routePath;
}
throw e;
diff --git a/src/constants.ts b/src/constants.ts
index 8e49c6b..60da499 100644
--- a/src/constants.ts
@ -947,7 +832,7 @@ index 7da85d9..5baca04 100644
/**
diff --git a/src/fetchHttpClient.ts b/src/fetchHttpClient.ts
index e9751e2..69a1f1f 100644
index e9751e2..794a398 100644
--- a/src/fetchHttpClient.ts
+++ b/src/fetchHttpClient.ts
@@ -1,8 +1,8 @@
@ -961,59 +846,6 @@ index e9751e2..69a1f1f 100644
HttpClient,
HttpHeaders as PipelineHeaders,
PipelineRequest,
@@ -11,7 +11,7 @@ import type {
} from "./interfaces.js";
import { RestError } from "./restError.js";
import { createHttpHeaders } from "./httpHeaders.js";
-import { isNodeReadableStream, isWebReadableStream } from "./util/typeGuards.js";
+import { isNodeReadableStream, isReadableStream } from "./util/typeGuards.js";
/**
* Checks if the body is a Blob or Blob-like
@@ -111,7 +111,7 @@ async function buildPipelineResponse(
status: httpResponse.status,
};
- const bodyStream = isWebReadableStream(httpResponse.body)
+ const bodyStream = isReadableStream(httpResponse.body)
? buildBodyStream(httpResponse.body, {
onProgress: request.onDownloadProgress,
onEnd: abortControllerCleanup,
@@ -217,26 +217,21 @@ function buildPipelineHeaders(httpResponse: Response): PipelineHeaders {
return responseHeaders;
}
-interface BuildRequestBodyResponse {
- body:
- | string
- | Blob
- | ReadableStream<Uint8Array>
- | ArrayBuffer
- | ArrayBufferView
- | FormData
- | null
- | undefined;
+function buildRequestBody(request: PipelineRequest):
+ | {
streaming: boolean;
+ body: ReadableStream<Uint8Array>;
}
-
-function buildRequestBody(request: PipelineRequest): BuildRequestBodyResponse {
+ | {
+ streaming: boolean;
+ body: string | Blob | ArrayBuffer | ArrayBufferView | FormData | null | undefined;
+ } {
const body = typeof request.body === "function" ? request.body() : request.body;
if (isNodeReadableStream(body)) {
throw new Error("Node streams are not supported in browser environment.");
}
- return isWebReadableStream(body)
+ return isReadableStream(body)
? { streaming: true, body: buildBodyStream(body, { onProgress: request.onUploadProgress }) }
: { streaming: false, body };
}
diff --git a/src/httpHeaders.ts b/src/httpHeaders.ts
index 9e2914b..0bdb7be 100644
--- a/src/httpHeaders.ts
@ -1231,7 +1063,7 @@ index 688a7ea..76ca028 100644
+export * from "./client/getClient.js";
+export * from "./client/common.js";
diff --git a/src/interfaces.ts b/src/interfaces.ts
index 26b806d..6c4e425 100644
index 26b806d..6ef7c4b 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -1,9 +1,8 @@
@ -1246,10 +1078,12 @@ index 26b806d..6c4e425 100644
/**
* A HttpHeaders collection represented as a simple JSON object.
@@ -315,6 +314,19 @@ export type TransferProgressEvent = {
@@ -315,6 +314,21 @@ export type TransferProgressEvent = {
loadedBytes: number;
};
+// UNBRANDED DIFFERENCE: HttpMethods are defined at the top level in unbranded instead of core-util since we don't
+// need to worry about creating a cyclic dependency
+/**
+ * Supported HTTP methods to use when making requests.
+ */
@ -1463,7 +1297,7 @@ index 3e33a3b..dd3965c 100644
+ return TYPESPEC_RUNTIME_LOG_LEVELS.includes(logLevel as any);
}
diff --git a/src/nodeHttpClient.ts b/src/nodeHttpClient.ts
index 1ac007a..501b03e 100644
index 1ac007a..76796b2 100644
--- a/src/nodeHttpClient.ts
+++ b/src/nodeHttpClient.ts
@@ -5,8 +5,8 @@ import * as http from "node:http";
@ -1486,34 +1320,6 @@ index 1ac007a..501b03e 100644
import { logger } from "./log.js";
const DEFAULT_TLS_SETTINGS = {};
@@ -32,16 +32,9 @@ function isStreamComplete(stream: NodeJS.ReadableStream): Promise<void> {
}
return new Promise((resolve) => {
- const handler = (): void => {
- resolve();
- stream.removeListener("close", handler);
- stream.removeListener("end", handler);
- stream.removeListener("error", handler);
- };
-
- stream.on("close", handler);
- stream.on("end", handler);
- stream.on("error", handler);
+ stream.on("close", resolve);
+ stream.on("end", resolve);
+ stream.on("error", resolve);
});
}
@@ -188,6 +181,7 @@ class NodeHttpClient implements HttpClient {
if (isReadableStream(responseStream)) {
downloadStreamDone = isStreamComplete(responseStream);
}
+
Promise.all([uploadStreamDone, downloadStreamDone])
.then(() => {
// eslint-disable-next-line promise/always-return
diff --git a/src/pipeline.ts b/src/pipeline.ts
index f5612f8..13fc101 100644
--- a/src/pipeline.ts
@ -1759,7 +1565,7 @@ index 24f6e16..914f506 100644
import { retryPolicy } from "./retryPolicy.js";
import { DEFAULT_RETRY_POLICY_COUNT } from "../constants.js";
diff --git a/src/policies/formDataPolicy.ts b/src/policies/formDataPolicy.ts
index 86d7e12..9f149af 100644
index 86d7e12..31fc06e 100644
--- a/src/policies/formDataPolicy.ts
+++ b/src/policies/formDataPolicy.ts
@@ -1,9 +1,10 @@
@ -1784,21 +1590,6 @@ index 86d7e12..9f149af 100644
/**
* The programmatic identifier of the formDataPolicy.
@@ -102,7 +103,6 @@ async function prepareFormData(formData: FormDataMap, request: PipelineRequest):
"Content-Disposition",
`form-data; name="${fieldName}"; filename="${fileName}"`,
);
-
// again, || is used since an empty value.type means the content type is unset
headers.set("Content-Type", value.type || "application/octet-stream");
@@ -113,5 +113,6 @@ async function prepareFormData(formData: FormDataMap, request: PipelineRequest):
}
}
}
+
request.multipartBody = { parts };
}
diff --git a/src/policies/logPolicy.ts b/src/policies/logPolicy.ts
index a8383c6..e8b9724 100644
--- a/src/policies/logPolicy.ts
@ -1817,7 +1608,7 @@ index a8383c6..e8b9724 100644
import { Sanitizer } from "../util/sanitizer.js";
diff --git a/src/policies/multipartPolicy.ts b/src/policies/multipartPolicy.ts
index 2b70494..083b761 100644
index 2b70494..2353450 100644
--- a/src/policies/multipartPolicy.ts
+++ b/src/policies/multipartPolicy.ts
@@ -1,11 +1,12 @@
@ -1825,10 +1616,9 @@ index 2b70494..083b761 100644
// Licensed under the MIT License.
-import { randomUUID, stringToUint8Array } from "@azure/core-util";
-import type { BodyPart, HttpHeaders, PipelineRequest, PipelineResponse } from "../interfaces.js";
import type { BodyPart, HttpHeaders, PipelineRequest, PipelineResponse } from "../interfaces.js";
-import type { PipelinePolicy } from "../pipeline.js";
-import { concat } from "../util/concat.js";
+import type { BodyPart, HttpHeaders, PipelineRequest } from "../interfaces.js";
+import { PipelinePolicy } from "../pipeline.js";
+import { stringToUint8Array } from "../util/bytesEncoding.js";
import { isBlob } from "../util/typeGuards.js";
@ -1837,15 +1627,6 @@ index 2b70494..083b761 100644
function generateBoundary(): string {
return `----AzSDKFormBoundary${randomUUID()}`;
@@ -111,7 +112,7 @@ function assertValidBoundary(boundary: string): void {
export function multipartPolicy(): PipelinePolicy {
return {
name: multipartPolicyName,
- async sendRequest(request, next): Promise<PipelineResponse> {
+ async sendRequest(request, next) {
if (!request.multipartBody) {
return next(request);
}
diff --git a/src/policies/ndJsonPolicy.ts b/src/policies/ndJsonPolicy.ts
deleted file mode 100644
index deeee45..0000000
@ -1881,19 +1662,6 @@ index deeee45..0000000
- },
- };
-}
diff --git a/src/policies/proxyPolicy.ts b/src/policies/proxyPolicy.ts
index 22b8c0f..3ca0bfa 100644
--- a/src/policies/proxyPolicy.ts
+++ b/src/policies/proxyPolicy.ts
@@ -145,7 +145,7 @@ function getUrlFromProxySettings(settings: ProxySettings): URL {
let parsedProxyUrl: URL;
try {
parsedProxyUrl = new URL(settings.host);
- } catch {
+ } catch (_error) {
throw new Error(
`Expecting a valid host string in proxy settings, but found "${settings.host}".`,
);
diff --git a/src/policies/redirectPolicy.ts b/src/policies/redirectPolicy.ts
index 1b8bf2c..3bbeb17 100644
--- a/src/policies/redirectPolicy.ts
@ -2020,7 +1788,7 @@ index 0e78872..79f19f1 100644
/**
* Name of the TLS Policy
diff --git a/src/policies/tracingPolicy.ts b/src/policies/tracingPolicy.ts
index 5e69548..ee915bc 100644
index 5e69548..1d824c0 100644
--- a/src/policies/tracingPolicy.ts
+++ b/src/policies/tracingPolicy.ts
@@ -1,18 +1,14 @@
@ -2047,24 +1815,6 @@ index 5e69548..ee915bc 100644
import { isRestError } from "../restError.js";
import { Sanitizer } from "../util/sanitizer.js";
@@ -45,7 +41,7 @@ export interface TracingPolicyOptions {
* @param options - Options to configure the telemetry logged by the tracing policy.
*/
export function tracingPolicy(options: TracingPolicyOptions = {}): PipelinePolicy {
- const userAgentPromise = getUserAgentValue(options.userAgentPrefix);
+ const userAgentValue = getUserAgentValue(options.userAgentPrefix);
const sanitizer = new Sanitizer({
additionalAllowedQueryParameters: options.additionalAllowedQueryParameters,
});
@@ -58,7 +54,7 @@ export function tracingPolicy(options: TracingPolicyOptions = {}): PipelinePolic
return next(request);
}
- const userAgent = await userAgentPromise;
+ const userAgent = await userAgentValue;
const spanAttributes = {
"http.url": sanitizer.sanitizeUrl(request.url),
@@ -92,7 +88,7 @@ function tryCreateTracingClient(): TracingClient | undefined {
try {
return createTracingClient({
@ -2150,7 +1900,7 @@ index a8b94fc..332b8b8 100644
* Function that determines how to proceed with the subsequent requests.
* @param state - Retry state
diff --git a/src/retryStrategies/throttlingRetryStrategy.ts b/src/retryStrategies/throttlingRetryStrategy.ts
index 2d4f87f..99bee0f 100644
index 2d4f87f..b729714 100644
--- a/src/retryStrategies/throttlingRetryStrategy.ts
+++ b/src/retryStrategies/throttlingRetryStrategy.ts
@@ -1,17 +1,17 @@
@ -2175,15 +1925,6 @@ index 2d4f87f..99bee0f 100644
* the amount of time (minimum) to wait to retry.
*
* "retry-after-ms", "x-ms-retry-after-ms" : milliseconds
@@ -50,7 +50,7 @@ function getRetryAfterInMs(response?: PipelineResponse): number | undefined {
const diff = date - Date.now();
// negative diff would mean a date in the past, so retry asap with 0 milliseconds
return Number.isFinite(diff) ? Math.max(0, diff) : undefined;
- } catch {
+ } catch (e: any) {
return undefined;
}
}
diff --git a/src/tracing/index.ts b/src/tracing/index.ts
deleted file mode 100644
index 8992d7a..0000000
@ -2267,80 +2008,6 @@ index ce29be9..82e102a 100644
/**
* Options related to abort controller.
diff --git a/src/util/checkEnvironment.ts b/src/util/checkEnvironment.ts
index 153edf6..b2ad78c 100644
--- a/src/util/checkEnvironment.ts
+++ b/src/util/checkEnvironment.ts
@@ -1,22 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-interface Window {
- document: unknown;
-}
-
-interface DedicatedWorkerGlobalScope {
- constructor: {
- name: string;
- };
-
- importScripts: (...paths: string[]) => void;
-}
-
-interface Navigator {
- product: string;
-}
-
+declare global {
interface DenoGlobal {
version: {
deno: string;
@@ -27,12 +12,9 @@ interface BunGlobal {
version: string;
}
-// eslint-disable-next-line @azure/azure-sdk/ts-no-window
-declare const window: Window;
-declare const self: DedicatedWorkerGlobalScope;
-declare const Deno: DenoGlobal;
-declare const Bun: BunGlobal;
-declare const navigator: Navigator;
+ const Deno: DenoGlobal;
+ const Bun: BunGlobal;
+}
/**
* A constant that indicates whether the environment the code is running is a Web Browser.
@@ -45,11 +27,16 @@ export const isBrowser = typeof window !== "undefined" && typeof window.document
*/
export const isWebWorker =
typeof self === "object" &&
- typeof self?.importScripts === "function" &&
+ typeof (self as any)?.importScripts === "function" &&
(self.constructor?.name === "DedicatedWorkerGlobalScope" ||
self.constructor?.name === "ServiceWorkerGlobalScope" ||
self.constructor?.name === "SharedWorkerGlobalScope");
+/**
+ * A constant that indicates whether the environment the code is running is Bun.sh.
+ */
+export const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
+
/**
* A constant that indicates whether the environment the code is running is Deno.
*/
@@ -58,11 +45,6 @@ export const isDeno =
typeof Deno.version !== "undefined" &&
typeof Deno.version.deno !== "undefined";
-/**
- * A constant that indicates whether the environment the code is running is Bun.sh.
- */
-export const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
-
/**
* A constant that indicates whether the environment the code is running is a Node.js compatible environment.
*/
diff --git a/src/util/concat.ts b/src/util/concat.ts
index 457bc22..cbadccf 100644
--- a/src/util/concat.ts
@ -2460,7 +2127,7 @@ index e0af55f..0000000
-} from "./checkEnvironment.js";
-export { uint8ArrayToString, stringToUint8Array, type EncodingType } from "./bytesEncoding.js";
diff --git a/src/util/sanitizer.ts b/src/util/sanitizer.ts
index 46654b9..dd6a138 100644
index 46654b9..be4f21e 100644
--- a/src/util/sanitizer.ts
+++ b/src/util/sanitizer.ts
@@ -1,7 +1,7 @@
@ -2468,7 +2135,7 @@ index 46654b9..dd6a138 100644
// Licensed under the MIT License.
-import { type UnknownObject, isObject } from "@azure/core-util";
+import { UnknownObject, isObject } from "./object.js";
+import { type UnknownObject, isObject } from "./object.js";
/**
* @internal
@ -2486,7 +2153,7 @@ index 80a1a23..794d26a 100644
/**
* Generates a SHA-256 HMAC signature.
diff --git a/src/util/tokenCycler.ts b/src/util/tokenCycler.ts
index 32e2343..213a59e 100644
index 32e2343..034c7b0 100644
--- a/src/util/tokenCycler.ts
+++ b/src/util/tokenCycler.ts
@@ -1,7 +1,7 @@
@ -2498,25 +2165,6 @@ index 32e2343..213a59e 100644
import { delay } from "./helpers.js";
/**
@@ -133,14 +133,10 @@ export function createTokenCycler(
* window and not already refreshing)
*/
get shouldRefresh(): boolean {
- if (cycler.isRefreshing) {
- return false;
- }
- if (token?.refreshAfterTimestamp && token.refreshAfterTimestamp < Date.now()) {
- return true;
- }
-
- return (token?.expiresOnTimestamp ?? 0) - options.refreshWindowInMs < Date.now();
+ return (
+ !cycler.isRefreshing &&
+ (token?.expiresOnTimestamp ?? 0) - options.refreshWindowInMs < Date.now()
+ );
},
/**
* Produces true if the cycler MUST refresh (null or nearly-expired
diff --git a/src/util/typeGuards.ts b/src/util/typeGuards.ts
index 22a9cac..2b3f295 100644
--- a/src/util/typeGuards.ts
@ -2576,53 +2224,19 @@ index b8950b5..3ef33c8 100644
await setPlatformSpecificData(runtimeInfo);
const defaultAgent = getUserAgentString(runtimeInfo);
const userAgentValue = prefix ? `${prefix} ${defaultAgent}` : defaultAgent;
diff --git a/src/util/uuidUtils.common.ts b/src/util/uuidUtils.common.ts
index 1fa8b8f..6741831 100644
--- a/src/util/uuidUtils.common.ts
+++ b/src/util/uuidUtils.common.ts
@@ -1,6 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+/*
+ * NOTE: When moving this file, please update "react-native" section in package.json.
+ */
+
/**
* Generated Universally Unique Identifier
*
diff --git a/src/util/uuidUtils.ts b/src/util/uuidUtils.ts
index bd11d61..4fc4808 100644
index bd11d61..3f6a12b 100644
--- a/src/util/uuidUtils.ts
+++ b/src/util/uuidUtils.ts
@@ -1,7 +1,8 @@
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { randomUUID as v4RandomUUID } from "crypto";
+import { randomUUID as v4RandomUUID } from "node:crypto";
+import { generateUUID } from "./uuidUtils.common.js";
interface Crypto {
randomUUID(): string;
@@ -12,11 +13,16 @@ declare const globalThis: {
};
// NOTE: This is a workaround until we can use `globalThis.crypto.randomUUID` in Node.js 19+.
-const uuidFunction =
+let uuidFunction =
typeof globalThis?.crypto?.randomUUID === "function"
? globalThis.crypto.randomUUID.bind(globalThis.crypto)
: v4RandomUUID;
+// Not defined in earlier versions of Node.js 14
+if (!uuidFunction) {
+ uuidFunction = generateUUID;
+}
+
/**
* Generated Universally Unique Identifier
*
diff --git a/src/xhrHttpClient.ts b/src/xhrHttpClient.ts
index 71bc439..20040f8 100644
--- a/src/xhrHttpClient.ts

Просмотреть файл

@ -30,6 +30,7 @@ export interface AbortSignalLike {
// @public
export interface AccessToken {
expiresOnTimestamp: number;
refreshAfterTimestamp?: number;
token: string;
}
@ -140,7 +141,6 @@ export type ClientOptions = PipelineOptions & {
scopes?: string[];
apiKeyHeaderName?: string;
};
baseUrl?: string;
endpoint?: string;
apiVersion?: string;
allowInsecureConnection?: boolean;
@ -487,7 +487,7 @@ export type OptionsWithTracingContext<Options extends {
// @public
export type PathParameters<TRoute extends string> = TRoute extends `${infer _Head}/{${infer _Param}}${infer Tail}` ? [
pathParameter: string | PathParameterWithOptions,
pathParameter: string | number | PathParameterWithOptions,
...pathParameters: PathParameters<Tail>
] : [
];
@ -495,7 +495,7 @@ pathParameter: string | PathParameterWithOptions,
// @public
export interface PathParameterWithOptions {
allowReserved?: boolean;
value: string;
value: string | number;
}
// @public

Просмотреть файл

@ -74,6 +74,13 @@ export interface AccessToken {
* The access token's expiration timestamp in milliseconds, UNIX epoch time.
*/
expiresOnTimestamp: number;
/**
* The timestamp when the access token should be refreshed, in milliseconds, UNIX epoch time.
*/
refreshAfterTimestamp?: number;
// UNBRANDED DIFFERENCE: Unbranded Core does not support PoP ("Proof-of-Presence") tokens.
}
/**

Просмотреть файл

@ -17,7 +17,7 @@ import { PipelineOptions } from "../createPipelineFromOptions.js";
import { LogPolicyOptions } from "../policies/logPolicy.js";
/**
* Shape of the default request parameters, this may be overriden by the specific
* Shape of the default request parameters, this may be overridden by the specific
* request types to provide strong types
*/
export type RequestParameters = {
@ -91,6 +91,7 @@ export type RequestParameters = {
* while performing the requested operation.
* May be called multiple times.
*/
// UNBRANDED DIFFERENCE: onResponse callback does not have a second __legacyError parameter which was provided for backwards compatibility
export type RawResponseCallback = (rawResponse: FullOperationResponse, error?: unknown) => void;
/**
@ -190,7 +191,7 @@ export interface Client {
pipeline: Pipeline;
/**
* This method will be used to send request that would check the path to provide
* strong types. When used by the codegen this type gets overriden wit the generated
* strong types. When used by the codegen this type gets overridden with the generated
* types. For example:
* ```typescript snippet:path_example
* import { Client, Routes } from "@typespec/ts-http-runtime";
@ -317,11 +318,9 @@ export type ClientOptions = PipelineOptions & {
*/
apiKeyHeaderName?: string;
};
/**
* Base url for the client
* @deprecated This property is deprecated and will be removed soon, please use endpoint instead
*/
baseUrl?: string;
// UNBRANDED DIFFERENCE: The deprecated baseUrl property is removed in favor of the endpoint property in the unbranded Core package
/**
* Endpoint for the client
*/
@ -389,7 +388,10 @@ export type PathParameters<
// additional parameters we can call RouteParameters recursively on the Tail to match the remaining parts,
// in case the Tail has more parameters, it will return a tuple with the parameters found in tail.
// We spread the second path params to end up with a single dimension tuple at the end.
[pathParameter: string | PathParameterWithOptions, ...pathParameters: PathParameters<Tail>]
[
pathParameter: string | number | PathParameterWithOptions,
...pathParameters: PathParameters<Tail>,
]
: // When the path doesn't match the template, it means that we have no path parameters so we return
// an empty tuple.
[];
@ -429,7 +431,7 @@ export interface PathParameterWithOptions {
/**
* The value of the parameter.
*/
value: string;
value: string | number;
/**
* Whether to allow for reserved characters in the value. If set to true, special characters such as '/' in the parameter's value will not be URL encoded.

Просмотреть файл

@ -63,9 +63,10 @@ export function getClient(
}
const { allowInsecureConnection, httpClient } = clientOptions;
const endpointUrl = clientOptions.endpoint ?? endpoint;
const client = (path: string, ...args: Array<any>): ResourceMethods<StreamableMethod> => {
const getUrl = (requestOptions: RequestParameters): string =>
buildRequestUrl(endpoint, path, args, { allowInsecureConnection, ...requestOptions });
buildRequestUrl(endpointUrl, path, args, { allowInsecureConnection, ...requestOptions });
return {
get: (requestOptions: RequestParameters = {}): StreamableMethod => {

Просмотреть файл

@ -9,7 +9,7 @@ import {
PipelineResponse,
RequestBodyType,
} from "../interfaces.js";
import { RestError } from "../restError.js";
import { isRestError, RestError } from "../restError.js";
import { Pipeline } from "../pipeline.js";
import { createHttpHeaders } from "../httpHeaders.js";
import { createPipelineRequest } from "../pipelineRequest.js";
@ -36,23 +36,35 @@ export async function sendRequest(
): Promise<HttpResponse> {
const httpClient = customHttpClient ?? getCachedDefaultHttpsClient();
const request = buildPipelineRequest(method, url, options);
const response = await pipeline.sendRequest(httpClient, request);
const headers = response.headers.toJSON();
const stream = response.readableStreamBody ?? response.browserStreamBody;
const parsedBody =
options.responseAsStream || stream !== undefined ? undefined : getResponseBody(response);
const body = stream ?? parsedBody;
if (options?.onResponse) {
options.onResponse({ ...response, request, rawHeaders: headers, parsedBody });
try {
const response = await pipeline.sendRequest(httpClient, request);
const headers = response.headers.toJSON();
const stream = response.readableStreamBody ?? response.browserStreamBody;
const parsedBody =
options.responseAsStream || stream !== undefined ? undefined : getResponseBody(response);
const body = stream ?? parsedBody;
if (options?.onResponse) {
options.onResponse({ ...response, request, rawHeaders: headers, parsedBody });
}
return {
request,
headers,
status: `${response.status}`,
body,
};
} catch (e: unknown) {
if (isRestError(e) && e.response && options.onResponse) {
const { response } = e;
const rawHeaders = response.headers.toJSON();
// UNBRANDED DIFFERENCE: onResponse callback does not have a second __legacyError property
options?.onResponse({ ...response, request, rawHeaders }, e);
}
throw e;
}
return {
request,
headers,
status: `${response.status}`,
body,
};
}
/**
@ -154,17 +166,15 @@ function getRequestBody(body?: unknown, contentType: string = ""): RequestBody {
return { body };
}
const firstType = contentType.split(";")[0];
if (firstType === "application/json") {
return { body: JSON.stringify(body) };
}
if (ArrayBuffer.isView(body)) {
return { body: body instanceof Uint8Array ? body : JSON.stringify(body) };
}
const firstType = contentType.split(";")[0];
switch (firstType) {
case "application/json":
return { body: JSON.stringify(body) };
case "multipart/form-data":
if (Array.isArray(body)) {
return { multipartBody: buildMultipartBody(body as PartDescriptor[]) };
@ -187,7 +197,7 @@ function getResponseBody(response: PipelineResponse): RequestBodyType | undefine
// Set the default response type
const contentType = response.headers.get("content-type") ?? "";
const firstType = contentType.split(";")[0];
const bodyToParse: string = response.bodyAsText ?? "";
const bodyToParse = response.bodyAsText ?? "";
if (firstType === "text/plain") {
return String(bodyToParse);

Просмотреть файл

@ -54,7 +54,7 @@ function isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions
export function buildRequestUrl(
endpoint: string,
routePath: string,
pathParameters: (string | PathParameterWithOptions)[],
pathParameters: (string | number | PathParameterWithOptions)[],
options: RequestParameters = {},
): string {
if (routePath.startsWith("https://") || routePath.startsWith("http://")) {
@ -187,19 +187,18 @@ export function buildBaseUrl(endpoint: string, options: RequestParameters): stri
function buildRoutePath(
routePath: string,
pathParameters: (string | PathParameterWithOptions)[],
pathParameters: (string | number | PathParameterWithOptions)[],
options: RequestParameters = {},
): string {
for (const pathParam of pathParameters) {
const allowReserved =
typeof pathParam === "string" ? false : (pathParam?.allowReserved ?? false);
let value = typeof pathParam === "string" ? pathParam : pathParam?.value;
const allowReserved = typeof pathParam === "object" && (pathParam.allowReserved ?? false);
let value = typeof pathParam === "object" ? pathParam.value : pathParam;
if (!options.skipUrlEncoding && !allowReserved) {
value = encodeURIComponent(value);
}
routePath = routePath.replace(/\{\w+\}/, value);
routePath = routePath.replace(/\{\w+\}/, String(value));
}
return routePath;
}

Просмотреть файл

@ -11,7 +11,7 @@ import {
} from "./interfaces.js";
import { RestError } from "./restError.js";
import { createHttpHeaders } from "./httpHeaders.js";
import { isNodeReadableStream, isReadableStream } from "./util/typeGuards.js";
import { isNodeReadableStream, isWebReadableStream } from "./util/typeGuards.js";
/**
* Checks if the body is a Blob or Blob-like
@ -111,7 +111,7 @@ async function buildPipelineResponse(
status: httpResponse.status,
};
const bodyStream = isReadableStream(httpResponse.body)
const bodyStream = isWebReadableStream(httpResponse.body)
? buildBodyStream(httpResponse.body, {
onProgress: request.onDownloadProgress,
onEnd: abortControllerCleanup,
@ -217,21 +217,26 @@ function buildPipelineHeaders(httpResponse: Response): PipelineHeaders {
return responseHeaders;
}
function buildRequestBody(request: PipelineRequest):
| {
streaming: boolean;
body: ReadableStream<Uint8Array>;
}
| {
streaming: boolean;
body: string | Blob | ArrayBuffer | ArrayBufferView | FormData | null | undefined;
} {
interface BuildRequestBodyResponse {
body:
| string
| Blob
| ReadableStream<Uint8Array>
| ArrayBuffer
| ArrayBufferView
| FormData
| null
| undefined;
streaming: boolean;
}
function buildRequestBody(request: PipelineRequest): BuildRequestBodyResponse {
const body = typeof request.body === "function" ? request.body() : request.body;
if (isNodeReadableStream(body)) {
throw new Error("Node streams are not supported in browser environment.");
}
return isReadableStream(body)
return isWebReadableStream(body)
? { streaming: true, body: buildBodyStream(body, { onProgress: request.onUploadProgress }) }
: { streaming: false, body };
}

Просмотреть файл

@ -314,6 +314,8 @@ export type TransferProgressEvent = {
loadedBytes: number;
};
// UNBRANDED DIFFERENCE: HttpMethods are defined at the top level in unbranded instead of core-util since we don't
// need to worry about creating a cyclic dependency
/**
* Supported HTTP methods to use when making requests.
*/

Просмотреть файл

@ -32,9 +32,16 @@ function isStreamComplete(stream: NodeJS.ReadableStream): Promise<void> {
}
return new Promise((resolve) => {
stream.on("close", resolve);
stream.on("end", resolve);
stream.on("error", resolve);
const handler = (): void => {
resolve();
stream.removeListener("close", handler);
stream.removeListener("end", handler);
stream.removeListener("error", handler);
};
stream.on("close", handler);
stream.on("end", handler);
stream.on("error", handler);
});
}
@ -181,7 +188,6 @@ class NodeHttpClient implements HttpClient {
if (isReadableStream(responseStream)) {
downloadStreamDone = isStreamComplete(responseStream);
}
Promise.all([uploadStreamDone, downloadStreamDone])
.then(() => {
// eslint-disable-next-line promise/always-return

Просмотреть файл

@ -103,6 +103,7 @@ async function prepareFormData(formData: FormDataMap, request: PipelineRequest):
"Content-Disposition",
`form-data; name="${fieldName}"; filename="${fileName}"`,
);
// again, || is used since an empty value.type means the content type is unset
headers.set("Content-Type", value.type || "application/octet-stream");
@ -113,6 +114,5 @@ async function prepareFormData(formData: FormDataMap, request: PipelineRequest):
}
}
}
request.multipartBody = { parts };
}

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import type { BodyPart, HttpHeaders, PipelineRequest } from "../interfaces.js";
import type { BodyPart, HttpHeaders, PipelineRequest, PipelineResponse } from "../interfaces.js";
import { PipelinePolicy } from "../pipeline.js";
import { stringToUint8Array } from "../util/bytesEncoding.js";
import { isBlob } from "../util/typeGuards.js";
@ -112,7 +112,7 @@ function assertValidBoundary(boundary: string): void {
export function multipartPolicy(): PipelinePolicy {
return {
name: multipartPolicyName,
async sendRequest(request, next) {
async sendRequest(request, next): Promise<PipelineResponse> {
if (!request.multipartBody) {
return next(request);
}

Просмотреть файл

@ -145,7 +145,7 @@ function getUrlFromProxySettings(settings: ProxySettings): URL {
let parsedProxyUrl: URL;
try {
parsedProxyUrl = new URL(settings.host);
} catch (_error) {
} catch {
throw new Error(
`Expecting a valid host string in proxy settings, but found "${settings.host}".`,
);

Просмотреть файл

@ -41,7 +41,7 @@ export interface TracingPolicyOptions {
* @param options - Options to configure the telemetry logged by the tracing policy.
*/
export function tracingPolicy(options: TracingPolicyOptions = {}): PipelinePolicy {
const userAgentValue = getUserAgentValue(options.userAgentPrefix);
const userAgentPromise = getUserAgentValue(options.userAgentPrefix);
const sanitizer = new Sanitizer({
additionalAllowedQueryParameters: options.additionalAllowedQueryParameters,
});
@ -54,7 +54,7 @@ export function tracingPolicy(options: TracingPolicyOptions = {}): PipelinePolic
return next(request);
}
const userAgent = await userAgentValue;
const userAgent = await userAgentPromise;
const spanAttributes = {
"http.url": sanitizer.sanitizeUrl(request.url),

Просмотреть файл

@ -50,7 +50,7 @@ function getRetryAfterInMs(response?: PipelineResponse): number | undefined {
const diff = date - Date.now();
// negative diff would mean a date in the past, so retry asap with 0 milliseconds
return Number.isFinite(diff) ? Math.max(0, diff) : undefined;
} catch (e: any) {
} catch {
return undefined;
}
}

Просмотреть файл

@ -1,21 +1,39 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
declare global {
interface DenoGlobal {
version: {
deno: string;
};
}
interface BunGlobal {
version: string;
}
const Deno: DenoGlobal;
const Bun: BunGlobal;
interface Window {
document: unknown;
}
interface DedicatedWorkerGlobalScope {
constructor: {
name: string;
};
importScripts: (...paths: string[]) => void;
}
interface Navigator {
product: string;
}
interface DenoGlobal {
version: {
deno: string;
};
}
interface BunGlobal {
version: string;
}
// eslint-disable-next-line @azure/azure-sdk/ts-no-window
declare const window: Window;
declare const self: DedicatedWorkerGlobalScope;
declare const Deno: DenoGlobal;
declare const Bun: BunGlobal;
declare const navigator: Navigator;
/**
* A constant that indicates whether the environment the code is running is a Web Browser.
*/
@ -27,16 +45,11 @@ export const isBrowser = typeof window !== "undefined" && typeof window.document
*/
export const isWebWorker =
typeof self === "object" &&
typeof (self as any)?.importScripts === "function" &&
typeof self?.importScripts === "function" &&
(self.constructor?.name === "DedicatedWorkerGlobalScope" ||
self.constructor?.name === "ServiceWorkerGlobalScope" ||
self.constructor?.name === "SharedWorkerGlobalScope");
/**
* A constant that indicates whether the environment the code is running is Bun.sh.
*/
export const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
/**
* A constant that indicates whether the environment the code is running is Deno.
*/
@ -45,6 +58,11 @@ export const isDeno =
typeof Deno.version !== "undefined" &&
typeof Deno.version.deno !== "undefined";
/**
* A constant that indicates whether the environment the code is running is Bun.sh.
*/
export const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
/**
* A constant that indicates whether the environment the code is running is a Node.js compatible environment.
*/

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { UnknownObject, isObject } from "./object.js";
import { type UnknownObject, isObject } from "./object.js";
/**
* @internal

Просмотреть файл

@ -133,10 +133,14 @@ export function createTokenCycler(
* window and not already refreshing)
*/
get shouldRefresh(): boolean {
return (
!cycler.isRefreshing &&
(token?.expiresOnTimestamp ?? 0) - options.refreshWindowInMs < Date.now()
);
if (cycler.isRefreshing) {
return false;
}
if (token?.refreshAfterTimestamp && token.refreshAfterTimestamp < Date.now()) {
return true;
}
return (token?.expiresOnTimestamp ?? 0) - options.refreshWindowInMs < Date.now();
},
/**
* Produces true if the cycler MUST refresh (null or nearly-expired

Просмотреть файл

@ -1,10 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/*
* NOTE: When moving this file, please update "react-native" section in package.json.
*/
/**
* Generated Universally Unique Identifier
*

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the MIT License.
import { randomUUID as v4RandomUUID } from "node:crypto";
import { generateUUID } from "./uuidUtils.common.js";
interface Crypto {
randomUUID(): string;
@ -13,16 +12,11 @@ declare const globalThis: {
};
// NOTE: This is a workaround until we can use `globalThis.crypto.randomUUID` in Node.js 19+.
let uuidFunction =
const uuidFunction =
typeof globalThis?.crypto?.randomUUID === "function"
? globalThis.crypto.randomUUID.bind(globalThis.crypto)
: v4RandomUUID;
// Not defined in earlier versions of Node.js 14
if (!uuidFunction) {
uuidFunction = generateUUID;
}
/**
* Generated Universally Unique Identifier
*