From 31b76c94f5bb633dfa73fe9c20d1ba88a0e9228e Mon Sep 17 00:00:00 2001 From: Timo van Veenendaal Date: Mon, 21 Oct 2024 14:44:06 -0700 Subject: [PATCH] [ts-http-runtime] add azure diff check tool (#31285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Packages impacted by this PR - `@typespec/ts-http-runtime` ### Describe the problem that is addressed by this PR We have had issues with the unbranded Core package becoming out of sync with the Azure packages. This PR adds a report which is a diff between the Azure Core packages and the unbranded package and causes the lint step to fail if there are any differences between Azure and unbranded that do not appear in the report. Running the `lint:fix` script will update the diff report. This will mean that: - Making an Azure Core change without a corresponding change to unbranded package, either in the source code or in the diff report, will result in a CI failure - Changes to the diff report can be reviewed so that any differences between Azure and unbranded implementations of a feature can be easily compared Why use the lint script (and lint:fix)? This is already run by CI, so by using it we don't need to make any changes to pipeline steps to get this working. This script is a one-off and so I just want to do the bare minimum to get things working 😄 --- common/config/rush/pnpm-lock.yaml | 3 +- sdk/core/ts-http-runtime/package.json | 7 +- .../review/azure-core-comparison.diff | 2640 +++++++++++++++++ .../ts-http-runtime/scripts/azure-diff.ts | 156 + 4 files changed, 2802 insertions(+), 4 deletions(-) create mode 100644 sdk/core/ts-http-runtime/review/azure-core-comparison.diff create mode 100644 sdk/core/ts-http-runtime/scripts/azure-diff.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 85b7a8567e8..c1aa47916a9 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -25104,7 +25104,7 @@ packages: dev: false file:projects/ts-http-runtime.tgz: - resolution: {integrity: sha512-MD9tMIfpTC9zx97D7IF1ZXzk/qijL6n58lc0C8cfeQ7y8DQHUx4TGBLW43aDOABJrMO9Oo3M3PCVGS2yVfkOpA==, tarball: file:projects/ts-http-runtime.tgz} + resolution: {integrity: sha512-wtRhN//7rN8fYN7MR3Gm1g2YY0+GxVwAGSx4aLNkxM7zSNggwYOBwqmT8fDlDSkiewqYbW5jHNWOtwMd4mRecA==, tarball: file:projects/ts-http-runtime.tgz} name: '@rush-temp/ts-http-runtime' version: 0.0.0 dependencies: @@ -25119,6 +25119,7 @@ packages: playwright: 1.48.1 rimraf: 5.0.10 tslib: 2.8.0 + tsx: 4.19.1 typescript: 5.6.3 vitest: 2.1.3(@types/node@18.19.57)(@vitest/browser@2.1.3) transitivePeerDependencies: diff --git a/sdk/core/ts-http-runtime/package.json b/sdk/core/ts-http-runtime/package.json index d7977da9c35..3bb6f9b4a09 100644 --- a/sdk/core/ts-http-runtime/package.json +++ b/sdk/core/ts-http-runtime/package.json @@ -62,8 +62,8 @@ "integration-test": "npm run integration-test:node && npm run integration-test:browser", "integration-test:browser": "echo skipped", "integration-test:node": "echo skipped", - "lint": "eslint package.json api-extractor.json src test", - "lint:fix": "eslint package.json api-extractor.json src test --fix --fix-type [problem,suggestion]", + "lint": "tsx scripts/azure-diff.ts; eslint package.json api-extractor.json src test", + "lint:fix": "tsx scripts/azure-diff.ts --update && eslint package.json api-extractor.json src test --fix --fix-type [problem,suggestion]", "pack": "npm pack 2>&1", "test": "npm run clean && dev-tool run build-package && npm run unit-test:node && dev-tool run bundle && npm run unit-test:browser && npm run integration-test", "test:browser": "npm run clean && npm run unit-test:browser && npm run integration-test:browser", @@ -108,7 +108,8 @@ "playwright": "^1.41.2", "rimraf": "^5.0.5", "typescript": "~5.6.2", - "vitest": "^2.0.5" + "vitest": "^2.0.5", + "tsx": "^4.19.1" }, "tshy": { "exports": { diff --git a/sdk/core/ts-http-runtime/review/azure-core-comparison.diff b/sdk/core/ts-http-runtime/review/azure-core-comparison.diff new file mode 100644 index 00000000000..9dccc462e75 --- /dev/null +++ b/sdk/core/ts-http-runtime/review/azure-core-comparison.diff @@ -0,0 +1,2640 @@ +diff --git a/src/abort-controller/AbortError.ts b/src/abort-controller/AbortError.ts +index 053733c..31dd275 100644 +--- a/src/abort-controller/AbortError.ts ++++ b/src/abort-controller/AbortError.ts +@@ -8,7 +8,7 @@ + * + * @example + * ```ts snippet:abort_error +- * import { AbortError } from "@azure/abort-controller"; ++ * import { AbortError } from "@typespec/ts-http-runtime"; + * + * async function doAsyncWork(options: { abortSignal: AbortSignal }): Promise { + * if (options.abortSignal.aborted) { +diff --git a/src/abort-controller/index.ts b/src/abort-controller/index.ts +deleted file mode 100644 +index 7f2adc4..0000000 +--- a/src/abort-controller/index.ts ++++ /dev/null +@@ -1,9 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-declare global { +- interface Event {} +-} +- +-export { AbortError } from "./AbortError.js"; +-export { AbortSignalLike } from "./AbortSignalLike.js"; +diff --git a/src/accessTokenCache.ts b/src/accessTokenCache.ts +index f8d603b..cca6d34 100644 +--- a/src/accessTokenCache.ts ++++ b/src/accessTokenCache.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AccessToken } from "@azure/core-auth"; ++import { AccessToken } from "./auth/tokenCredential.js"; + + /** + * Defines the default token refresh buffer duration. +diff --git a/src/auth/azureKeyCredential.ts b/src/auth/azureKeyCredential.ts +deleted file mode 100644 +index 6bdadc3..0000000 +--- a/src/auth/azureKeyCredential.ts ++++ /dev/null +@@ -1,45 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import { KeyCredential } from "./keyCredential.js"; +- +-/** +- * A static-key-based credential that supports updating +- * the underlying key value. +- */ +-export class AzureKeyCredential implements KeyCredential { +- private _key: string; +- +- /** +- * The value of the key to be used in authentication +- */ +- public get key(): string { +- return this._key; +- } +- +- /** +- * Create an instance of an AzureKeyCredential for use +- * with a service client. +- * +- * @param key - The initial value of the key to use in authentication +- */ +- constructor(key: string) { +- if (!key) { +- throw new Error("key must be a non-empty string"); +- } +- +- this._key = key; +- } +- +- /** +- * Change the value of the key. +- * +- * Updates will take effect upon the next request after +- * updating the key value. +- * +- * @param newKey - The new key value to be used +- */ +- public update(newKey: string): void { +- this._key = newKey; +- } +-} +diff --git a/src/auth/azureNamedKeyCredential.ts b/src/auth/azureNamedKeyCredential.ts +deleted file mode 100644 +index 544c3c0..0000000 +--- a/src/auth/azureNamedKeyCredential.ts ++++ /dev/null +@@ -1,88 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import { isObjectWithProperties } from "@azure/core-util"; +- +-/** +- * Represents a credential defined by a static API name and key. +- */ +-export interface NamedKeyCredential { +- /** +- * The value of the API key represented as a string +- */ +- readonly key: string; +- /** +- * The value of the API name represented as a string. +- */ +- readonly name: string; +-} +- +-/** +- * A static name/key-based credential that supports updating +- * the underlying name and key values. +- */ +-export class AzureNamedKeyCredential implements NamedKeyCredential { +- private _key: string; +- private _name: string; +- +- /** +- * The value of the key to be used in authentication. +- */ +- public get key(): string { +- return this._key; +- } +- +- /** +- * The value of the name to be used in authentication. +- */ +- public get name(): string { +- return this._name; +- } +- +- /** +- * Create an instance of an AzureNamedKeyCredential for use +- * with a service client. +- * +- * @param name - The initial value of the name to use in authentication. +- * @param key - The initial value of the key to use in authentication. +- */ +- constructor(name: string, key: string) { +- if (!name || !key) { +- throw new TypeError("name and key must be non-empty strings"); +- } +- +- this._name = name; +- this._key = key; +- } +- +- /** +- * Change the value of the key. +- * +- * Updates will take effect upon the next request after +- * updating the key value. +- * +- * @param newName - The new name value to be used. +- * @param newKey - The new key value to be used. +- */ +- public update(newName: string, newKey: string): void { +- if (!newName || !newKey) { +- throw new TypeError("newName and newKey must be non-empty strings"); +- } +- +- this._name = newName; +- this._key = newKey; +- } +-} +- +-/** +- * Tests an object to determine whether it implements NamedKeyCredential. +- * +- * @param credential - The assumed NamedKeyCredential to be tested. +- */ +-export function isNamedKeyCredential(credential: unknown): credential is NamedKeyCredential { +- return ( +- isObjectWithProperties(credential, ["name", "key"]) && +- typeof credential.key === "string" && +- typeof credential.name === "string" +- ); +-} +diff --git a/src/auth/azureSASCredential.ts b/src/auth/azureSASCredential.ts +deleted file mode 100644 +index 045c639..0000000 +--- a/src/auth/azureSASCredential.ts ++++ /dev/null +@@ -1,70 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import { isObjectWithProperties } from "@azure/core-util"; +- +-/** +- * Represents a credential defined by a static shared access signature. +- */ +-export interface SASCredential { +- /** +- * The value of the shared access signature represented as a string +- */ +- readonly signature: string; +-} +- +-/** +- * A static-signature-based credential that supports updating +- * the underlying signature value. +- */ +-export class AzureSASCredential implements SASCredential { +- private _signature: string; +- +- /** +- * The value of the shared access signature to be used in authentication +- */ +- public get signature(): string { +- return this._signature; +- } +- +- /** +- * Create an instance of an AzureSASCredential for use +- * with a service client. +- * +- * @param signature - The initial value of the shared access signature to use in authentication +- */ +- constructor(signature: string) { +- if (!signature) { +- throw new Error("shared access signature must be a non-empty string"); +- } +- +- this._signature = signature; +- } +- +- /** +- * Change the value of the signature. +- * +- * Updates will take effect upon the next request after +- * updating the signature value. +- * +- * @param newSignature - The new shared access signature value to be used +- */ +- public update(newSignature: string): void { +- if (!newSignature) { +- throw new Error("shared access signature must be a non-empty string"); +- } +- +- this._signature = newSignature; +- } +-} +- +-/** +- * Tests an object to determine whether it implements SASCredential. +- * +- * @param credential - The assumed SASCredential to be tested. +- */ +-export function isSASCredential(credential: unknown): credential is SASCredential { +- return ( +- isObjectWithProperties(credential, ["signature"]) && typeof credential.signature === "string" +- ); +-} +diff --git a/src/auth/index.ts b/src/auth/index.ts +deleted file mode 100644 +index 446268b..0000000 +--- a/src/auth/index.ts ++++ /dev/null +@@ -1,20 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +-export { HttpMethods } from "@azure/core-util"; +-export { AzureKeyCredential } from "./azureKeyCredential.js"; +-export { KeyCredential, isKeyCredential } from "./keyCredential.js"; +-export { +- AzureNamedKeyCredential, +- NamedKeyCredential, +- isNamedKeyCredential, +-} from "./azureNamedKeyCredential.js"; +-export { AzureSASCredential, SASCredential, isSASCredential } from "./azureSASCredential.js"; +- +-export { +- TokenCredential, +- GetTokenOptions, +- AccessToken, +- isTokenCredential, +-} from "./tokenCredential.js"; +- +-export { TracingContext } from "./tracing.js"; +diff --git a/src/auth/keyCredential.ts b/src/auth/keyCredential.ts +index 9db25cf..df8291c 100644 +--- a/src/auth/keyCredential.ts ++++ b/src/auth/keyCredential.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { isObjectWithProperties } from "@azure/core-util"; ++import { isObjectWithProperties } from "../util/typeGuards.js"; + + /** + * 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 +--- a/src/auth/tokenCredential.ts ++++ b/src/auth/tokenCredential.ts +@@ -1,9 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { AbortSignalLike } from "@azure/abort-controller"; +-import { TracingContext } from "./tracing.js"; +-import { HttpMethods } from "@azure/core-util"; ++import { AbortSignalLike } from "../abort-controller/AbortSignalLike.js"; ++import { TracingContext } from "../tracing/interfaces.js"; + + /** + * Represents a credential capable of providing an authentication token. +@@ -60,28 +59,6 @@ export interface GetTokenOptions { + * Allows specifying a tenantId. Useful to handle challenges that provide tenant Id hints. + */ + tenantId?: string; +- +- /** +- * Options for Proof of Possession token requests +- */ +- proofOfPossessionOptions?: { +- /** +- * The nonce value required for PoP token requests. +- * This is typically retrieved from the WWW-Authenticate header of a 401 challenge response. +- * This is used in combination with {@link resourceRequestUrl} and {@link resourceRequestMethod} to generate the PoP token. +- */ +- nonce: string; +- /** +- * The HTTP method of the request. +- * This is used in combination with {@link resourceRequestUrl} and {@link nonce} to generate the PoP token. +- */ +- resourceRequestMethod: HttpMethods; +- /** +- * The URL of the request. +- * This is used in combination with {@link resourceRequestMethod} and {@link nonce} to generate the PoP token. +- */ +- resourceRequestUrl: string; +- }; + } + + /** +@@ -97,32 +74,6 @@ 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; +- +- /** Type of token - `Bearer` or `pop` */ +- tokenType?: "Bearer" | "pop"; +-} +- +-/** +- * @internal +- * @param accessToken - Access token +- * @returns Whether a token is bearer type or not +- */ +-export function isBearerToken(accessToken: AccessToken): boolean { +- return !accessToken.tokenType || accessToken.tokenType === "Bearer"; +-} +- +-/** +- * @internal +- * @param accessToken - Access token +- * @returns Whether a token is Pop token or not +- */ +-export function isPopToken(accessToken: AccessToken): boolean { +- return accessToken.tokenType === "pop"; + } + + /** +diff --git a/src/auth/tracing.ts b/src/auth/tracing.ts +deleted file mode 100644 +index 8e846bb..0000000 +--- a/src/auth/tracing.ts ++++ /dev/null +@@ -1,32 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-// The interfaces in this file should be kept in sync with those +-// found in the `@azure/core-tracing` package. +- +-/** +- * An interface structurally compatible with OpenTelemetry. +- */ +-export interface TracingContext { +- /** +- * Get a value from the context. +- * +- * @param key - key which identifies a context value +- */ +- getValue(key: symbol): unknown; +- /** +- * Create a new context which inherits from this context and has +- * the given key set to the given value. +- * +- * @param key - context key for which to set the value +- * @param value - value to set for the given key +- */ +- setValue(key: symbol, value: unknown): TracingContext; +- /** +- * Return a new context which inherits from this context but does +- * not contain a value for the given key. +- * +- * @param key - context key for which to clear a value +- */ +- deleteValue(key: symbol): TracingContext; +-} +diff --git a/src/client/apiVersionPolicy.ts b/src/client/apiVersionPolicy.ts +index a4e1c22..aedf8e2 100644 +--- a/src/client/apiVersionPolicy.ts ++++ b/src/client/apiVersionPolicy.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { PipelinePolicy } from "@azure/core-rest-pipeline"; ++import { PipelinePolicy } from "../pipeline.js"; + import { ClientOptions } from "./common.js"; + + export const apiVersionPolicyName = "ApiVersionPolicy"; +diff --git a/src/client/clientHelpers.ts b/src/client/clientHelpers.ts +index b7a7a6d..56553a5 100644 +--- a/src/client/clientHelpers.ts ++++ b/src/client/clientHelpers.ts +@@ -1,15 +1,13 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { +- HttpClient, +- Pipeline, +- bearerTokenAuthenticationPolicy, +- createDefaultHttpClient, +- createPipelineFromOptions, +-} from "@azure/core-rest-pipeline"; +-import { KeyCredential, TokenCredential, isTokenCredential } from "@azure/core-auth"; +- ++import { HttpClient } from "../interfaces.js"; ++import { Pipeline } from "../pipeline.js"; ++import { bearerTokenAuthenticationPolicy } from "../policies/bearerTokenAuthenticationPolicy.js"; ++import { createDefaultHttpClient } from "../defaultHttpClient.js"; ++import { createPipelineFromOptions } from "../createPipelineFromOptions.js"; ++import { TokenCredential, isTokenCredential } from "../auth/tokenCredential.js"; ++import { KeyCredential, isKeyCredential } from "../auth/keyCredential.js"; + import { ClientOptions } from "./common.js"; + import { apiVersionPolicy } from "./apiVersionPolicy.js"; + import { keyCredentialAuthenticationPolicy } from "./keyCredentialAuthenticationPolicy.js"; +@@ -77,10 +75,6 @@ export function createDefaultPipeline( + return pipeline; + } + +-function isKeyCredential(credential: any): credential is KeyCredential { +- return (credential as KeyCredential).key !== undefined; +-} +- + export function getCachedDefaultHttpsClient(): HttpClient { + if (!cachedHttpClient) { + cachedHttpClient = createDefaultHttpClient(); +diff --git a/src/client/common.ts b/src/client/common.ts +index 916c4d5..a8fd8aa 100644 +--- a/src/client/common.ts ++++ b/src/client/common.ts +@@ -3,22 +3,21 @@ + + import { + HttpClient, +- LogPolicyOptions, +- Pipeline, +- PipelineOptions, +- PipelinePolicy, + PipelineRequest, + PipelineResponse, + RawHttpHeaders, + RequestBodyType, + TransferProgressEvent, +-} from "@azure/core-rest-pipeline"; +-import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +-import { AbortSignalLike } from "@azure/abort-controller"; +-import { OperationTracingOptions } from "@azure/core-tracing"; ++ RawHttpHeadersInput, ++} from "../interfaces.js"; ++import { Pipeline, PipelinePolicy } from "../pipeline.js"; ++import { AbortSignalLike } from "../abort-controller/AbortSignalLike.js"; ++import { OperationTracingOptions } from "../tracing/interfaces.js"; ++import { PipelineOptions } from "../createPipelineFromOptions.js"; ++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 = { + * A function to be called each time a response is received from the server + * while performing the requested operation. + * May be called multiple times. +- * +- * This callback will be called with two parameters: the raw response, including headers and response body; and an error +- * object which will be provided if an error was thrown while processing the request. +- * The third __legacyError parameter is provided for backwards compatability only and will have an identical value to the `error` parameter. + */ +-export type RawResponseCallback = ( +- rawResponse: FullOperationResponse, +- error?: unknown, +- __legacyError?: unknown, +-) => void; ++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 + * types. For example: + * ```typescript snippet:path_example +- * import { Client, Routes } from "@azure-rest/core-client"; ++ * import { Client, Routes } from "@typespec/ts-http-runtime"; + * + * 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, +- ] ++ [pathParameter: string | PathParameterWithOptions, ...pathParameters: PathParameters] + : // 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 { + /** + * The value of the parameter. + */ +- 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 +--- a/src/client/dom.d.ts ++++ /dev/null +@@ -1,4 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-/// +diff --git a/src/client/getClient.ts b/src/client/getClient.ts +index 1eefed4..95c2416 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 { HttpClient, HttpMethods, Pipeline, PipelineOptions } from "@azure/core-rest-pipeline"; ++import { TokenCredential, isTokenCredential } from "../auth/tokenCredential.js"; ++import { KeyCredential, isKeyCredential } from "../auth/keyCredential.js"; ++import { HttpClient, HttpMethods } from "../interfaces.js"; ++import { Pipeline } from "../pipeline.js"; + import { createDefaultPipeline } from "./clientHelpers.js"; + import { + Client, +@@ -10,10 +12,12 @@ import { + HttpBrowserStreamResponse, + HttpNodeStreamResponse, + RequestParameters, ++ ResourceMethods, + StreamableMethod, + } from "./common.js"; + import { sendRequest } from "./sendRequest.js"; + import { buildRequestUrl } from "./urlHelpers.js"; ++import { PipelineOptions } from "../createPipelineFromOptions.js"; + + /** + * Creates a client with a default pipeline +@@ -59,10 +63,9 @@ export function getClient( + } + + const { allowInsecureConnection, httpClient } = clientOptions; +- const endpointUrl = clientOptions.endpoint ?? endpoint; +- const client = (path: string, ...args: Array) => { +- const getUrl = (requestOptions: RequestParameters) => +- buildRequestUrl(endpointUrl, path, args, { allowInsecureConnection, ...requestOptions }); ++ const client = (path: string, ...args: Array): ResourceMethods => { ++ const getUrl = (requestOptions: RequestParameters): string => ++ buildRequestUrl(endpoint, 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 +--- a/src/client/helpers/isBinaryBody.ts ++++ /dev/null +@@ -1,22 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import { isReadableStream } from "./isReadableStream.js"; +- +-export function isBinaryBody( +- body: unknown, +-): body is +- | Uint8Array +- | NodeJS.ReadableStream +- | ReadableStream +- | (() => NodeJS.ReadableStream) +- | (() => ReadableStream) +- | Blob { +- return ( +- body !== undefined && +- (body instanceof Uint8Array || +- isReadableStream(body) || +- typeof body === "function" || +- body instanceof Blob) +- ); +-} +diff --git a/src/client/helpers/isReadableStream-browser.mts b/src/client/helpers/isReadableStream-browser.mts +deleted file mode 100644 +index 9d792bd..0000000 +--- a/src/client/helpers/isReadableStream-browser.mts ++++ /dev/null +@@ -1,14 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-/** +- * Checks if the body is a ReadableStream supported by browsers +- * @internal +- */ +-export function isReadableStream(body: unknown): body is ReadableStream { +- return Boolean( +- body && +- typeof (body as ReadableStream).getReader === "function" && +- typeof (body as ReadableStream).tee === "function", +- ); +-} +diff --git a/src/client/helpers/isReadableStream.ts b/src/client/helpers/isReadableStream.ts +deleted file mode 100644 +index 5963319..0000000 +--- a/src/client/helpers/isReadableStream.ts ++++ /dev/null +@@ -1,10 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-/** +- * Checks if the body is a ReadableStream supported by Node +- * @internal +- */ +-export function isReadableStream(body: unknown): body is NodeJS.ReadableStream { +- return Boolean(body) && typeof (body as any).pipe === "function"; +-} +diff --git a/src/client/index.ts b/src/client/index.ts +deleted file mode 100644 +index 1cd7d94..0000000 +--- a/src/client/index.ts ++++ /dev/null +@@ -1,16 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-/** +- * Azure Rest Core Client library for JavaScript +- * @packageDocumentation +- */ +- +-export { createRestError } from "./restError.js"; +-export { +- addCredentialPipelinePolicy, +- AddCredentialPipelinePolicyOptions, +-} from "./clientHelpers.js"; +-export { operationOptionsToRequestParameters } from "./operationOptionHelpers.js"; +-export * from "./getClient.js"; +-export * from "./common.js"; +diff --git a/src/client/keyCredentialAuthenticationPolicy.ts b/src/client/keyCredentialAuthenticationPolicy.ts +index effa2d0..ea5783e 100644 +--- a/src/client/keyCredentialAuthenticationPolicy.ts ++++ b/src/client/keyCredentialAuthenticationPolicy.ts +@@ -1,13 +1,9 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { KeyCredential } from "@azure/core-auth"; +-import { +- PipelinePolicy, +- PipelineRequest, +- PipelineResponse, +- SendRequest, +-} from "@azure/core-rest-pipeline"; ++import { KeyCredential } from "../auth/keyCredential.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + + /** + * The programmatic identifier of the bearerTokenAuthenticationPolicy. +diff --git a/src/client/multipart.ts b/src/client/multipart.ts +index b36fa7a..1d66e36 100644 +--- a/src/client/multipart.ts ++++ b/src/client/multipart.ts +@@ -1,15 +1,11 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { +- BodyPart, +- MultipartRequestBody, +- RawHttpHeadersInput, +- RestError, +- createHttpHeaders, +-} from "@azure/core-rest-pipeline"; +-import { stringToUint8Array } from "@azure/core-util"; +-import { isBinaryBody } from "./helpers/isBinaryBody.js"; ++import { BodyPart, MultipartRequestBody, RawHttpHeadersInput } from "../interfaces.js"; ++import { RestError } from "../restError.js"; ++import { createHttpHeaders } from "../httpHeaders.js"; ++import { stringToUint8Array } from "../util/bytesEncoding.js"; ++import { isBinaryBody } from "../util/typeGuards.js"; + + /** + * Describes a single part in a multipart body. +diff --git a/src/client/restError.ts b/src/client/restError.ts +index b85a503..9d98299 100644 +--- a/src/client/restError.ts ++++ b/src/client/restError.ts +@@ -1,7 +1,9 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { PipelineResponse, RestError, createHttpHeaders } from "@azure/core-rest-pipeline"; ++import { PipelineResponse } from "../interfaces.js"; ++import { RestError } from "../restError.js"; ++import { createHttpHeaders } from "../httpHeaders.js"; + import { PathUncheckedResponse } from "./common.js"; + + /** +diff --git a/src/client/sendRequest.ts b/src/client/sendRequest.ts +index 9a96a4a..e884392 100644 +--- a/src/client/sendRequest.ts ++++ b/src/client/sendRequest.ts +@@ -5,17 +5,16 @@ import { + HttpClient, + HttpMethods, + MultipartRequestBody, +- Pipeline, + PipelineRequest, + PipelineResponse, + RequestBodyType, +- RestError, +- createHttpHeaders, +- createPipelineRequest, +- isRestError, +-} from "@azure/core-rest-pipeline"; ++} from "../interfaces.js"; ++import { RestError } from "../restError.js"; ++import { Pipeline } from "../pipeline.js"; ++import { createHttpHeaders } from "../httpHeaders.js"; ++import { createPipelineRequest } from "../pipelineRequest.js"; + import { getCachedDefaultHttpsClient } from "./clientHelpers.js"; +-import { isReadableStream } from "./helpers/isReadableStream.js"; ++import { isReadableStream } from "../util/typeGuards.js"; + import { HttpResponse, RequestParameters } from "./common.js"; + import { PartDescriptor, buildMultipartBody } from "./multipart.js"; + +@@ -37,8 +36,6 @@ export async function sendRequest( + ): Promise { + 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(); +- 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); + } + +- routePath = routePath.replace(/\{\w+\}/, String(value)); ++ routePath = routePath.replace(/\{\w+\}/, value); + } + return routePath; + } +diff --git a/src/constants.ts b/src/constants.ts +index 8e49c6b..60da499 100644 +--- a/src/constants.ts ++++ b/src/constants.ts +@@ -1,6 +1,6 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-export const SDK_VERSION: string = "1.17.1"; ++export const SDK_VERSION: string = "1.0.0-beta.1"; + + export const DEFAULT_RETRY_POLICY_COUNT = 3; +diff --git a/src/createPipelineFromOptions.ts b/src/createPipelineFromOptions.ts +index 2a2bd41..ede8855 100644 +--- a/src/createPipelineFromOptions.ts ++++ b/src/createPipelineFromOptions.ts +@@ -3,18 +3,18 @@ + + import { type LogPolicyOptions, logPolicy } from "./policies/logPolicy.js"; + import { type Pipeline, createEmptyPipeline } from "./pipeline.js"; +-import type { PipelineRetryOptions, TlsSettings, ProxySettings } from "./interfaces.js"; ++import type { PipelineRetryOptions, TlsSettings } from "./interfaces.js"; + import { type RedirectPolicyOptions, redirectPolicy } from "./policies/redirectPolicy.js"; + import { type UserAgentPolicyOptions, userAgentPolicy } from "./policies/userAgentPolicy.js"; +-import { multipartPolicy, multipartPolicyName } from "./policies/multipartPolicy.js"; ++import type { ProxySettings } from "./index.js"; + import { decompressResponsePolicy } from "./policies/decompressResponsePolicy.js"; + import { defaultRetryPolicy } from "./policies/defaultRetryPolicy.js"; + import { formDataPolicy } from "./policies/formDataPolicy.js"; +-import { isNodeLike } from "@azure/core-util"; ++import { isNodeLike } from "./util/checkEnvironment.js"; + import { proxyPolicy } from "./policies/proxyPolicy.js"; +-import { setClientRequestIdPolicy } from "./policies/setClientRequestIdPolicy.js"; + import { tlsPolicy } from "./policies/tlsPolicy.js"; + import { tracingPolicy } from "./policies/tracingPolicy.js"; ++import { multipartPolicy, multipartPolicyName } from "./policies/multipartPolicy.js"; + + /** + * Defines options that are used to configure the HTTP pipeline for +@@ -88,7 +88,6 @@ export function createPipelineFromOptions(options: InternalPipelineOptions): Pip + + pipeline.addPolicy(formDataPolicy(), { beforePolicies: [multipartPolicyName] }); + pipeline.addPolicy(userAgentPolicy(options.userAgentOptions)); +- pipeline.addPolicy(setClientRequestIdPolicy(options.telemetryOptions?.clientRequestIdHeaderName)); + // The multipart policy is added after policies with no phase, so that + // policies can be added between it and formDataPolicy to modify + // properties (e.g., making the boundary constant in recorded tests). +diff --git a/src/defaultHttpClient.ts b/src/defaultHttpClient.ts +index 7da85d9..5baca04 100644 +--- a/src/defaultHttpClient.ts ++++ b/src/defaultHttpClient.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { HttpClient } from "./interfaces.js"; ++import { HttpClient } from "./interfaces.js"; + import { createNodeHttpClient } from "./nodeHttpClient.js"; + + /** +diff --git a/src/fetchHttpClient.ts b/src/fetchHttpClient.ts +index e9751e2..69a1f1f 100644 +--- a/src/fetchHttpClient.ts ++++ b/src/fetchHttpClient.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { AbortError } from "@azure/abort-controller"; +-import type { ++import { AbortError } from "./abort-controller/AbortError.js"; ++import { + 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 +- | ArrayBuffer +- | ArrayBufferView +- | FormData +- | null +- | undefined; ++function buildRequestBody(request: PipelineRequest): ++ | { + streaming: boolean; ++ body: ReadableStream; + } +- +-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 ++++ b/src/httpHeaders.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { HttpHeaders, RawHttpHeaders, RawHttpHeadersInput } from "./interfaces.js"; ++import { HttpHeaders, RawHttpHeaders, RawHttpHeadersInput } from "./interfaces.js"; + + interface HeaderEntry { + name: string; +diff --git a/src/index.ts b/src/index.ts +index 688a7ea..76ca028 100644 +--- a/src/index.ts ++++ b/src/index.ts +@@ -9,16 +9,16 @@ declare global { + interface ReadableStream {} + interface TransformStream {} + } +- + /* eslint-enable @typescript-eslint/no-unused-vars */ +-export type { HttpMethods } from "@azure/core-util"; +-export type { ++ ++export { + Agent, + BodyPart, + FormDataMap, + FormDataValue, + HttpClient, + HttpHeaders, ++ HttpMethods, + KeyObject, + MultipartRequestBody, + PipelineRequest, +@@ -34,92 +34,125 @@ export type { + TransferProgressEvent, + } from "./interfaces.js"; + export { +- type AddPolicyOptions as AddPipelineOptions, +- type PipelinePhase, +- type PipelinePolicy, +- type Pipeline, ++ AddPolicyOptions as AddPipelineOptions, ++ PipelinePhase, ++ PipelinePolicy, ++ Pipeline, + createEmptyPipeline, + } from "./pipeline.js"; + export { + createPipelineFromOptions, +- type TelemetryOptions, +- type InternalPipelineOptions, +- type PipelineOptions, ++ TelemetryOptions, ++ InternalPipelineOptions, ++ PipelineOptions, + } from "./createPipelineFromOptions.js"; + export { createDefaultHttpClient } from "./defaultHttpClient.js"; + export { createHttpHeaders } from "./httpHeaders.js"; +-export { createPipelineRequest, type PipelineRequestOptions } from "./pipelineRequest.js"; +-export { RestError, type RestErrorOptions, isRestError } from "./restError.js"; ++export { createPipelineRequest, PipelineRequestOptions } from "./pipelineRequest.js"; ++export { RestError, RestErrorOptions, isRestError } from "./restError.js"; + export { + decompressResponsePolicy, + decompressResponsePolicyName, + } from "./policies/decompressResponsePolicy.js"; +-export { +- exponentialRetryPolicy, +- type ExponentialRetryPolicyOptions, +- exponentialRetryPolicyName, +-} from "./policies/exponentialRetryPolicy.js"; +-export { +- setClientRequestIdPolicy, +- setClientRequestIdPolicyName, +-} from "./policies/setClientRequestIdPolicy.js"; +-export { logPolicy, logPolicyName, type LogPolicyOptions } from "./policies/logPolicy.js"; ++export { logPolicy, logPolicyName, LogPolicyOptions } from "./policies/logPolicy.js"; + export { multipartPolicy, multipartPolicyName } from "./policies/multipartPolicy.js"; + export { proxyPolicy, proxyPolicyName, getDefaultProxySettings } from "./policies/proxyPolicy.js"; + export { + redirectPolicy, + redirectPolicyName, +- type RedirectPolicyOptions, ++ RedirectPolicyOptions, + } from "./policies/redirectPolicy.js"; +-export { +- systemErrorRetryPolicy, +- type SystemErrorRetryPolicyOptions, +- systemErrorRetryPolicyName, +-} from "./policies/systemErrorRetryPolicy.js"; +-export { +- throttlingRetryPolicy, +- throttlingRetryPolicyName, +- type ThrottlingRetryPolicyOptions, +-} from "./policies/throttlingRetryPolicy.js"; +-export { retryPolicy, type RetryPolicyOptions } from "./policies/retryPolicy.js"; +-export type { +- RetryStrategy, +- RetryInformation, +- RetryModifiers, +-} from "./retryStrategies/retryStrategy.js"; + export { + tracingPolicy, + tracingPolicyName, +- type TracingPolicyOptions, ++ TracingPolicyOptions, + } from "./policies/tracingPolicy.js"; +-export { +- defaultRetryPolicy, +- type DefaultRetryPolicyOptions, +-} from "./policies/defaultRetryPolicy.js"; ++export { defaultRetryPolicy, DefaultRetryPolicyOptions } from "./policies/defaultRetryPolicy.js"; + export { + userAgentPolicy, + userAgentPolicyName, +- type UserAgentPolicyOptions, ++ UserAgentPolicyOptions, + } from "./policies/userAgentPolicy.js"; + export { tlsPolicy, tlsPolicyName } from "./policies/tlsPolicy.js"; + export { formDataPolicy, formDataPolicyName } from "./policies/formDataPolicy.js"; + export { + bearerTokenAuthenticationPolicy, +- type BearerTokenAuthenticationPolicyOptions, ++ BearerTokenAuthenticationPolicyOptions, + bearerTokenAuthenticationPolicyName, +- type ChallengeCallbacks, +- type AuthorizeRequestOptions, +- type AuthorizeRequestOnChallengeOptions, ++ ChallengeCallbacks, ++ AuthorizeRequestOptions, ++ AuthorizeRequestOnChallengeOptions, + } from "./policies/bearerTokenAuthenticationPolicy.js"; +-export { ndJsonPolicy, ndJsonPolicyName } from "./policies/ndJsonPolicy.js"; ++export { AbortSignalLike } from "./abort-controller/AbortSignalLike.js"; ++export { AbortError } from "./abort-controller/AbortError.js"; ++export { AccessToken, GetTokenOptions, TokenCredential } from "./auth/tokenCredential.js"; ++export { KeyCredential, isKeyCredential } from "./auth/keyCredential.js"; ++export { ++ AddEventOptions, ++ Instrumenter, ++ InstrumenterSpanOptions, ++ OperationTracingOptions, ++ OptionsWithTracingContext, ++ Resolved, ++ SpanStatus, ++ SpanStatusError, ++ SpanStatusSuccess, ++ TracingClient, ++ TracingClientOptions, ++ TracingContext, ++ TracingSpan, ++ TracingSpanKind, ++ TracingSpanLink, ++ TracingSpanOptions, ++} from "./tracing/interfaces.js"; ++export { useInstrumenter } from "./tracing/instrumenter.js"; ++export { createTracingClient } from "./tracing/tracingClient.js"; ++// from core-util ++export { delay, DelayOptions, calculateRetryDelay } from "./util/delay.js"; ++export { ++ AbortOptions, ++ cancelablePromiseRace, ++ AbortablePromiseBuilder, ++} from "./util/aborterUtils.js"; + export { +- auxiliaryAuthenticationHeaderPolicy, +- type AuxiliaryAuthenticationHeaderPolicyOptions, +- auxiliaryAuthenticationHeaderPolicyName, +-} from "./policies/auxiliaryAuthenticationHeaderPolicy.js"; ++ createAbortablePromise, ++ CreateAbortablePromiseOptions, ++} from "./util/createAbortablePromise.js"; ++export { getRandomIntegerInclusive } from "./util/random.js"; ++export { isObject, UnknownObject } from "./util/object.js"; ++export { isError, getErrorMessage } from "./util/error.js"; + export { + createFile, + createFileFromStream, +- type CreateFileOptions, +- type CreateFileFromStreamOptions, ++ CreateFileOptions, ++ CreateFileFromStreamOptions, + } from "./util/file.js"; ++export { computeSha256Hash, computeSha256Hmac } from "./util/sha256.js"; ++export { isDefined, isObjectWithProperties, objectHasProperty } from "./util/typeGuards.js"; ++export { randomUUID } from "./util/uuidUtils.js"; ++export { ++ isBrowser, ++ isBun, ++ isNode, ++ isNodeLike, ++ isNodeRuntime, ++ isDeno, ++ isReactNative, ++ isWebWorker, ++} from "./util/checkEnvironment.js"; ++export { uint8ArrayToString, stringToUint8Array, EncodingType } from "./util/bytesEncoding.js"; ++export { ++ Debugger, ++ TypeSpecRuntimeLogger, ++ TypeSpecRuntimeLogLevel, ++ TypeSpecRuntimeClientLogger, ++} from "./logger/logger.js"; ++// client ++export { createRestError } from "./client/restError.js"; ++export { ++ addCredentialPipelinePolicy, ++ AddCredentialPipelinePolicyOptions, ++} from "./client/clientHelpers.js"; ++export { operationOptionsToRequestParameters } from "./client/operationOptionHelpers.js"; ++export * from "./client/getClient.js"; ++export * from "./client/common.js"; +diff --git a/src/interfaces.ts b/src/interfaces.ts +index 26b806d..6c4e425 100644 +--- a/src/interfaces.ts ++++ b/src/interfaces.ts +@@ -1,9 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AbortSignalLike } from "@azure/abort-controller"; +-import type { OperationTracingOptions } from "@azure/core-tracing"; +-import type { HttpMethods } from "@azure/core-util"; ++import { AbortSignalLike } from "./abort-controller/AbortSignalLike.js"; ++import { OperationTracingOptions } from "./tracing/interfaces.js"; + + /** + * A HttpHeaders collection represented as a simple JSON object. +@@ -315,6 +314,19 @@ export type TransferProgressEvent = { + loadedBytes: number; + }; + ++/** ++ * Supported HTTP methods to use when making requests. ++ */ ++export type HttpMethods = ++ | "GET" ++ | "PUT" ++ | "POST" ++ | "DELETE" ++ | "PATCH" ++ | "HEAD" ++ | "OPTIONS" ++ | "TRACE"; ++ + /** + * Options to configure a proxy for outgoing requests (Node.js only). + */ +diff --git a/src/log.ts b/src/log.ts +index db967c2..32452a9 100644 +--- a/src/log.ts ++++ b/src/log.ts +@@ -1,5 +1,5 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { createClientLogger } from "@azure/logger"; +-export const logger = createClientLogger("core-rest-pipeline"); ++import { createClientLogger } from "./logger/logger.js"; ++export const logger = createClientLogger("ts-http-runtime"); +diff --git a/src/logger/debug.ts b/src/logger/debug.ts +index d29ccec..3ba9f34 100644 +--- a/src/logger/debug.ts ++++ b/src/logger/debug.ts +@@ -19,9 +19,9 @@ export interface Debug { + /** + * Enables a particular set of namespaces. + * To enable multiple separate them with commas, e.g. "info,debug". +- * Supports wildcards, e.g. "azure:*" +- * Supports skip syntax, e.g. "azure:*,-azure:storage:*" will enable +- * everything under azure except for things under azure:storage. ++ * Supports wildcards, e.g. "typeSpecRuntime:*" ++ * Supports skip syntax, e.g. "typeSpecRuntime:*,-typeSpecRuntime:storage:*" will enable ++ * everything under typeSpecRuntime except for things under typeSpecRuntime:storage. + */ + enable: (namespaces: string) => void; + /** +diff --git a/src/logger/index.ts b/src/logger/logger.ts +similarity index 52% +rename from src/logger/index.ts +rename to src/logger/logger.ts +index 3e33a3b..dd3965c 100644 +--- a/src/logger/index.ts ++++ b/src/logger/logger.ts +@@ -1,22 +1,23 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import debug, { type Debugger } from "./debug.js"; +-export type { Debugger } from "./debug.js"; ++import debug, { Debugger } from "./debug.js"; ++export { Debugger } from "./debug.js"; + +-const registeredLoggers = new Set(); ++const registeredLoggers = new Set(); + const logLevelFromEnv = +- (typeof process !== "undefined" && process.env && process.env.AZURE_LOG_LEVEL) || undefined; ++ (typeof process !== "undefined" && process.env && process.env.TYPESPEC_RUNTIME_LOG_LEVEL) || ++ undefined; + +-let azureLogLevel: AzureLogLevel | undefined; ++let typeSpecRuntimeLogLevel: TypeSpecRuntimeLogLevel | undefined; + + /** +- * The AzureLogger provides a mechanism for overriding where logs are output to. ++ * The TypeSpecRuntimeLogger provides a mechanism for overriding where logs are output to. + * By default, logs are sent to stderr. + * Override the `log` method to redirect logs to another location. + */ +-export const AzureLogger: AzureClientLogger = debug("azure"); +-AzureLogger.log = (...args) => { ++export const TypeSpecRuntimeLogger: TypeSpecRuntimeClientLogger = debug("typeSpecRuntime"); ++TypeSpecRuntimeLogger.log = (...args) => { + debug.log(...args); + }; + +@@ -28,23 +29,23 @@ AzureLogger.log = (...args) => { + * - warning + * - error + */ +-export type AzureLogLevel = "verbose" | "info" | "warning" | "error"; +-const AZURE_LOG_LEVELS = ["verbose", "info", "warning", "error"]; ++export type TypeSpecRuntimeLogLevel = "verbose" | "info" | "warning" | "error"; ++const TYPESPEC_RUNTIME_LOG_LEVELS = ["verbose", "info", "warning", "error"]; + +-type AzureDebugger = Debugger & { level: AzureLogLevel }; ++type TypeSpecRuntimeDebugger = Debugger & { level: TypeSpecRuntimeLogLevel }; + + /** +- * An AzureClientLogger is a function that can log to an appropriate severity level. ++ * An TypeSpecRuntimeClientLogger is a function that can log to an appropriate severity level. + */ +-export type AzureClientLogger = Debugger; ++export type TypeSpecRuntimeClientLogger = Debugger; + + if (logLevelFromEnv) { + // avoid calling setLogLevel because we don't want a mis-set environment variable to crash +- if (isAzureLogLevel(logLevelFromEnv)) { ++ if (isTypeSpecRuntimeLogLevel(logLevelFromEnv)) { + setLogLevel(logLevelFromEnv); + } else { + console.error( +- `AZURE_LOG_LEVEL set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${AZURE_LOG_LEVELS.join( ++ `TYPESPEC_RUNTIME_LOG_LEVEL set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join( + ", ", + )}.`, + ); +@@ -60,13 +61,13 @@ if (logLevelFromEnv) { + * - warning + * - error + */ +-export function setLogLevel(level?: AzureLogLevel): void { +- if (level && !isAzureLogLevel(level)) { ++export function setLogLevel(level?: TypeSpecRuntimeLogLevel): void { ++ if (level && !isTypeSpecRuntimeLogLevel(level)) { + throw new Error( +- `Unknown log level '${level}'. Acceptable values: ${AZURE_LOG_LEVELS.join(",")}`, ++ `Unknown log level '${level}'. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(",")}`, + ); + } +- azureLogLevel = level; ++ typeSpecRuntimeLogLevel = level; + + const enabledNamespaces = []; + for (const logger of registeredLoggers) { +@@ -81,8 +82,8 @@ export function setLogLevel(level?: AzureLogLevel): void { + /** + * Retrieves the currently specified log level. + */ +-export function getLogLevel(): AzureLogLevel | undefined { +- return azureLogLevel; ++export function getLogLevel(): TypeSpecRuntimeLogLevel | undefined { ++ return typeSpecRuntimeLogLevel; + } + + const levelMap = { +@@ -96,7 +97,7 @@ const levelMap = { + * Defines the methods available on the SDK-facing logger. + */ + // eslint-disable-next-line @typescript-eslint/no-redeclare +-export interface AzureLogger { ++export interface TypeSpecRuntimeLogger { + /** + * Used for failures the program is unlikely to recover from, + * such as Out of Memory. +@@ -121,13 +122,13 @@ export interface AzureLogger { + } + + /** +- * Creates a logger for use by the Azure SDKs that inherits from `AzureLogger`. ++ * Creates a logger for use by the SDKs that inherits from `TypeSpecRuntimeLogger`. + * @param namespace - The name of the SDK package. + * @hidden + */ +-export function createClientLogger(namespace: string): AzureLogger { +- const clientRootLogger: AzureClientLogger = AzureLogger.extend(namespace); +- patchLogMethod(AzureLogger, clientRootLogger); ++export function createClientLogger(namespace: string): TypeSpecRuntimeLogger { ++ const clientRootLogger: TypeSpecRuntimeClientLogger = TypeSpecRuntimeLogger.extend(namespace); ++ patchLogMethod(TypeSpecRuntimeLogger, clientRootLogger); + return { + error: createLogger(clientRootLogger, "error"), + warning: createLogger(clientRootLogger, "warning"), +@@ -136,14 +137,20 @@ export function createClientLogger(namespace: string): AzureLogger { + }; + } + +-function patchLogMethod(parent: AzureClientLogger, child: AzureClientLogger | AzureDebugger): void { ++function patchLogMethod( ++ parent: TypeSpecRuntimeClientLogger, ++ child: TypeSpecRuntimeClientLogger | TypeSpecRuntimeDebugger, ++): void { + child.log = (...args) => { + parent.log(...args); + }; + } + +-function createLogger(parent: AzureClientLogger, level: AzureLogLevel): AzureDebugger { +- const logger: AzureDebugger = Object.assign(parent.extend(level), { ++function createLogger( ++ parent: TypeSpecRuntimeClientLogger, ++ level: TypeSpecRuntimeLogLevel, ++): TypeSpecRuntimeDebugger { ++ const logger: TypeSpecRuntimeDebugger = Object.assign(parent.extend(level), { + level, + }); + +@@ -159,10 +166,12 @@ function createLogger(parent: AzureClientLogger, level: AzureLogLevel): AzureDeb + return logger; + } + +-function shouldEnable(logger: AzureDebugger): boolean { +- return Boolean(azureLogLevel && levelMap[logger.level] <= levelMap[azureLogLevel]); ++function shouldEnable(logger: TypeSpecRuntimeDebugger): boolean { ++ return Boolean( ++ typeSpecRuntimeLogLevel && levelMap[logger.level] <= levelMap[typeSpecRuntimeLogLevel], ++ ); + } + +-function isAzureLogLevel(logLevel: string): logLevel is AzureLogLevel { +- return AZURE_LOG_LEVELS.includes(logLevel as any); ++function isTypeSpecRuntimeLogLevel(logLevel: string): logLevel is TypeSpecRuntimeLogLevel { ++ return TYPESPEC_RUNTIME_LOG_LEVELS.includes(logLevel as any); + } +diff --git a/src/nodeHttpClient.ts b/src/nodeHttpClient.ts +index 1ac007a..501b03e 100644 +--- a/src/nodeHttpClient.ts ++++ b/src/nodeHttpClient.ts +@@ -5,8 +5,8 @@ import * as http from "node:http"; + import * as https from "node:https"; + import * as zlib from "node:zlib"; + import { Transform } from "node:stream"; +-import { AbortError } from "@azure/abort-controller"; +-import type { ++import { AbortError } from "./abort-controller/AbortError.js"; ++import { + HttpClient, + HttpHeaders, + PipelineRequest, +@@ -17,7 +17,7 @@ import type { + } from "./interfaces.js"; + import { createHttpHeaders } from "./httpHeaders.js"; + import { RestError } from "./restError.js"; +-import type { IncomingMessage } from "node:http"; ++import { IncomingMessage } from "node:http"; + import { logger } from "./log.js"; + + const DEFAULT_TLS_SETTINGS = {}; +@@ -32,16 +32,9 @@ function isStreamComplete(stream: NodeJS.ReadableStream): Promise { + } + + 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 ++++ b/src/pipeline.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { HttpClient, PipelineRequest, PipelineResponse, SendRequest } from "./interfaces.js"; ++import { HttpClient, PipelineRequest, PipelineResponse, SendRequest } from "./interfaces.js"; + + /** + * Policies are executed in phases. +diff --git a/src/pipelineRequest.ts b/src/pipelineRequest.ts +index 8d1648d..b28ae0c 100644 +--- a/src/pipelineRequest.ts ++++ b/src/pipelineRequest.ts +@@ -1,9 +1,10 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { ++import { + FormDataMap, + HttpHeaders, ++ HttpMethods, + MultipartRequestBody, + PipelineRequest, + ProxySettings, +@@ -11,10 +12,9 @@ import type { + TransferProgressEvent, + } from "./interfaces.js"; + import { createHttpHeaders } from "./httpHeaders.js"; +-import type { AbortSignalLike } from "@azure/abort-controller"; +-import { randomUUID } from "@azure/core-util"; +-import type { OperationTracingOptions } from "@azure/core-tracing"; +-import type { HttpMethods } from "@azure/core-util"; ++import { AbortSignalLike } from "./abort-controller/AbortSignalLike.js"; ++import { randomUUID } from "./util/uuidUtils.js"; ++import { OperationTracingOptions } from "./tracing/interfaces.js"; + + /** + * Settings to initialize a request. +diff --git a/src/policies/auxiliaryAuthenticationHeaderPolicy.ts b/src/policies/auxiliaryAuthenticationHeaderPolicy.ts +deleted file mode 100644 +index 55110a0..0000000 +--- a/src/policies/auxiliaryAuthenticationHeaderPolicy.ts ++++ /dev/null +@@ -1,106 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import type { GetTokenOptions, TokenCredential } from "@azure/core-auth"; +-import type { AzureLogger } from "@azure/logger"; +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; +-import { type AccessTokenGetter, createTokenCycler } from "../util/tokenCycler.js"; +-import { logger as coreLogger } from "../log.js"; +-import type { AuthorizeRequestOptions } from "./bearerTokenAuthenticationPolicy.js"; +- +-/** +- * The programmatic identifier of the auxiliaryAuthenticationHeaderPolicy. +- */ +-export const auxiliaryAuthenticationHeaderPolicyName = "auxiliaryAuthenticationHeaderPolicy"; +-const AUTHORIZATION_AUXILIARY_HEADER = "x-ms-authorization-auxiliary"; +- +-/** +- * Options to configure the auxiliaryAuthenticationHeaderPolicy +- */ +-export interface AuxiliaryAuthenticationHeaderPolicyOptions { +- /** +- * TokenCredential list used to get token from auxiliary tenants and +- * one credential for each tenant the client may need to access +- */ +- credentials?: TokenCredential[]; +- /** +- * Scopes depend on the cloud your application runs in +- */ +- scopes: string | string[]; +- /** +- * A logger can be sent for debugging purposes. +- */ +- logger?: AzureLogger; +-} +- +-async function sendAuthorizeRequest(options: AuthorizeRequestOptions): Promise { +- const { scopes, getAccessToken, request } = options; +- const getTokenOptions: GetTokenOptions = { +- abortSignal: request.abortSignal, +- tracingOptions: request.tracingOptions, +- }; +- +- return (await getAccessToken(scopes, getTokenOptions))?.token ?? ""; +-} +- +-/** +- * A policy for external tokens to `x-ms-authorization-auxiliary` header. +- * This header will be used when creating a cross-tenant application we may need to handle authentication requests +- * for resources that are in different tenants. +- * You could see [ARM docs](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/authenticate-multi-tenant) for a rundown of how this feature works +- */ +-export function auxiliaryAuthenticationHeaderPolicy( +- options: AuxiliaryAuthenticationHeaderPolicyOptions, +-): PipelinePolicy { +- const { credentials, scopes } = options; +- const logger = options.logger || coreLogger; +- const tokenCyclerMap = new WeakMap(); +- +- return { +- name: auxiliaryAuthenticationHeaderPolicyName, +- async sendRequest(request: PipelineRequest, next: SendRequest): Promise { +- if (!request.url.toLowerCase().startsWith("https://")) { +- throw new Error( +- "Bearer token authentication for auxiliary header is not permitted for non-TLS protected (non-https) URLs.", +- ); +- } +- if (!credentials || credentials.length === 0) { +- logger.info( +- `${auxiliaryAuthenticationHeaderPolicyName} header will not be set due to empty credentials.`, +- ); +- return next(request); +- } +- +- const tokenPromises: Promise[] = []; +- for (const credential of credentials) { +- let getAccessToken = tokenCyclerMap.get(credential); +- if (!getAccessToken) { +- getAccessToken = createTokenCycler(credential); +- tokenCyclerMap.set(credential, getAccessToken); +- } +- tokenPromises.push( +- sendAuthorizeRequest({ +- scopes: Array.isArray(scopes) ? scopes : [scopes], +- request, +- getAccessToken, +- logger, +- }), +- ); +- } +- const auxiliaryTokens = (await Promise.all(tokenPromises)).filter((token) => Boolean(token)); +- if (auxiliaryTokens.length === 0) { +- logger.warning( +- `None of the auxiliary tokens are valid. ${AUTHORIZATION_AUXILIARY_HEADER} header will not be set.`, +- ); +- return next(request); +- } +- request.headers.set( +- AUTHORIZATION_AUXILIARY_HEADER, +- auxiliaryTokens.map((token) => `Bearer ${token}`).join(", "), +- ); +- +- return next(request); +- }, +- }; +-} +diff --git a/src/policies/bearerTokenAuthenticationPolicy.ts b/src/policies/bearerTokenAuthenticationPolicy.ts +index 8398172..d4b2706 100644 +--- a/src/policies/bearerTokenAuthenticationPolicy.ts ++++ b/src/policies/bearerTokenAuthenticationPolicy.ts +@@ -1,10 +1,10 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; +-import type { AzureLogger } from "@azure/logger"; +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { AccessToken, GetTokenOptions, TokenCredential } from "../auth/tokenCredential.js"; ++import { TypeSpecRuntimeLogger } from "../logger/logger.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { createTokenCycler } from "../util/tokenCycler.js"; + import { logger as coreLogger } from "../log.js"; + +@@ -32,7 +32,7 @@ export interface AuthorizeRequestOptions { + /** + * A logger, if one was sent through the HTTP pipeline. + */ +- logger?: AzureLogger; ++ logger?: TypeSpecRuntimeLogger; + } + + /** +@@ -58,7 +58,7 @@ export interface AuthorizeRequestOnChallengeOptions { + /** + * A logger, if one was sent through the HTTP pipeline. + */ +- logger?: AzureLogger; ++ logger?: TypeSpecRuntimeLogger; + } + + /** +@@ -99,7 +99,7 @@ export interface BearerTokenAuthenticationPolicyOptions { + /** + * A logger can be sent for debugging purposes. + */ +- logger?: AzureLogger; ++ logger?: TypeSpecRuntimeLogger; + } + + /** +diff --git a/src/policies/decompressResponsePolicy.ts b/src/policies/decompressResponsePolicy.ts +index 252e2ad..e365833 100644 +--- a/src/policies/decompressResponsePolicy.ts ++++ b/src/policies/decompressResponsePolicy.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + + /** + * The programmatic identifier of the decompressResponsePolicy. +diff --git a/src/policies/defaultRetryPolicy.ts b/src/policies/defaultRetryPolicy.ts +index 169a7ca..d4ca014 100644 +--- a/src/policies/defaultRetryPolicy.ts ++++ b/src/policies/defaultRetryPolicy.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineRetryOptions } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRetryOptions } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { exponentialRetryStrategy } from "../retryStrategies/exponentialRetryStrategy.js"; + import { throttlingRetryStrategy } from "../retryStrategies/throttlingRetryStrategy.js"; + import { retryPolicy } from "./retryPolicy.js"; +diff --git a/src/policies/exponentialRetryPolicy.ts b/src/policies/exponentialRetryPolicy.ts +index 24f6e16..914f506 100644 +--- a/src/policies/exponentialRetryPolicy.ts ++++ b/src/policies/exponentialRetryPolicy.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { exponentialRetryStrategy } from "../retryStrategies/exponentialRetryStrategy.js"; + 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 +--- a/src/policies/formDataPolicy.ts ++++ b/src/policies/formDataPolicy.ts +@@ -1,9 +1,10 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { isNodeLike, stringToUint8Array } from "@azure/core-util"; ++import { stringToUint8Array } from "../util/bytesEncoding.js"; ++import { isNodeLike } from "../util/checkEnvironment.js"; + import { createHttpHeaders } from "../httpHeaders.js"; +-import type { ++import { + BodyPart, + FormDataMap, + FormDataValue, +@@ -11,7 +12,7 @@ import type { + PipelineResponse, + SendRequest, + } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelinePolicy } from "../pipeline.js"; + + /** + * 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 ++++ b/src/policies/logPolicy.ts +@@ -1,9 +1,9 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { Debugger } from "@azure/logger"; +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { Debugger } from "../logger/logger.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { logger as coreLogger } from "../log.js"; + import { Sanitizer } from "../util/sanitizer.js"; + +diff --git a/src/policies/multipartPolicy.ts b/src/policies/multipartPolicy.ts +index 2b70494..083b761 100644 +--- a/src/policies/multipartPolicy.ts ++++ b/src/policies/multipartPolicy.ts +@@ -1,11 +1,12 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { randomUUID, stringToUint8Array } from "@azure/core-util"; +-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"; ++import { randomUUID } from "../util/uuidUtils.js"; ++import { concat } from "../util/concat.js"; + + 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 { ++ 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 +--- a/src/policies/ndJsonPolicy.ts ++++ /dev/null +@@ -1,29 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; +- +-/** +- * The programmatic identifier of the ndJsonPolicy. +- */ +-export const ndJsonPolicyName = "ndJsonPolicy"; +- +-/** +- * ndJsonPolicy is a policy used to control keep alive settings for every request. +- */ +-export function ndJsonPolicy(): PipelinePolicy { +- return { +- name: ndJsonPolicyName, +- async sendRequest(request: PipelineRequest, next: SendRequest): Promise { +- // There currently isn't a good way to bypass the serializer +- if (typeof request.body === "string" && request.body.startsWith("[")) { +- const body = JSON.parse(request.body); +- if (Array.isArray(body)) { +- request.body = body.map((item) => JSON.stringify(item) + "\n").join(""); +- } +- } +- return next(request); +- }, +- }; +-} +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 ++++ b/src/policies/redirectPolicy.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + + /** + * The programmatic identifier of the redirectPolicy. +diff --git a/src/policies/retryPolicy.ts b/src/policies/retryPolicy.ts +index f937b36..1071226 100644 +--- a/src/policies/retryPolicy.ts ++++ b/src/policies/retryPolicy.ts +@@ -1,13 +1,13 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { delay } from "../util/helpers.js"; +-import { type AzureLogger, createClientLogger } from "@azure/logger"; +-import type { RetryStrategy } from "../retryStrategies/retryStrategy.js"; +-import type { RestError } from "../restError.js"; +-import { AbortError } from "@azure/abort-controller"; ++import { RetryStrategy } from "../retryStrategies/retryStrategy.js"; ++import { RestError } from "../restError.js"; ++import { AbortError } from "../abort-controller/AbortError.js"; ++import { TypeSpecRuntimeLogger, createClientLogger } from "../logger/logger.js"; + import { DEFAULT_RETRY_POLICY_COUNT } from "../constants.js"; + + const retryPolicyLogger = createClientLogger("core-rest-pipeline retryPolicy"); +@@ -28,7 +28,7 @@ export interface RetryPolicyOptions { + /** + * Logger. If it's not provided, a default logger is used. + */ +- logger?: AzureLogger; ++ logger?: TypeSpecRuntimeLogger; + } + + /** +diff --git a/src/policies/setClientRequestIdPolicy.ts b/src/policies/setClientRequestIdPolicy.ts +deleted file mode 100644 +index a40d4ab..0000000 +--- a/src/policies/setClientRequestIdPolicy.ts ++++ /dev/null +@@ -1,30 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; +- +-/** +- * The programmatic identifier of the setClientRequestIdPolicy. +- */ +-export const setClientRequestIdPolicyName = "setClientRequestIdPolicy"; +- +-/** +- * Each PipelineRequest gets a unique id upon creation. +- * This policy passes that unique id along via an HTTP header to enable better +- * telemetry and tracing. +- * @param requestIdHeaderName - The name of the header to pass the request ID to. +- */ +-export function setClientRequestIdPolicy( +- requestIdHeaderName = "x-ms-client-request-id", +-): PipelinePolicy { +- return { +- name: setClientRequestIdPolicyName, +- async sendRequest(request: PipelineRequest, next: SendRequest): Promise { +- if (!request.headers.has(requestIdHeaderName)) { +- request.headers.set(requestIdHeaderName, request.requestId); +- } +- return next(request); +- }, +- }; +-} +diff --git a/src/policies/systemErrorRetryPolicy.ts b/src/policies/systemErrorRetryPolicy.ts +index 4c8bf62..8622650 100644 +--- a/src/policies/systemErrorRetryPolicy.ts ++++ b/src/policies/systemErrorRetryPolicy.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { exponentialRetryStrategy } from "../retryStrategies/exponentialRetryStrategy.js"; + import { retryPolicy } from "./retryPolicy.js"; + import { DEFAULT_RETRY_POLICY_COUNT } from "../constants.js"; +diff --git a/src/policies/throttlingRetryPolicy.ts b/src/policies/throttlingRetryPolicy.ts +index 07cd51c..168851d 100644 +--- a/src/policies/throttlingRetryPolicy.ts ++++ b/src/policies/throttlingRetryPolicy.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { throttlingRetryStrategy } from "../retryStrategies/throttlingRetryStrategy.js"; + import { retryPolicy } from "./retryPolicy.js"; + import { DEFAULT_RETRY_POLICY_COUNT } from "../constants.js"; +diff --git a/src/policies/tlsPolicy.ts b/src/policies/tlsPolicy.ts +index 0e78872..79f19f1 100644 +--- a/src/policies/tlsPolicy.ts ++++ b/src/policies/tlsPolicy.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelinePolicy } from "../pipeline.js"; +-import type { TlsSettings } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; ++import { TlsSettings } from "../interfaces.js"; + + /** + * Name of the TLS Policy +diff --git a/src/policies/tracingPolicy.ts b/src/policies/tracingPolicy.ts +index 5e69548..ee915bc 100644 +--- a/src/policies/tracingPolicy.ts ++++ b/src/policies/tracingPolicy.ts +@@ -1,18 +1,14 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { +- type TracingClient, +- type TracingContext, +- type TracingSpan, +- createTracingClient, +-} from "@azure/core-tracing"; ++import { TracingClient, TracingContext, TracingSpan } from "../tracing/interfaces.js"; ++import { createTracingClient } from "../tracing/tracingClient.js"; + import { SDK_VERSION } from "../constants.js"; +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { getUserAgentValue } from "../util/userAgent.js"; + import { logger } from "../log.js"; +-import { getErrorMessage, isError } from "@azure/core-util"; ++import { getErrorMessage, isError } from "../util/error.js"; + 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({ + namespace: "", +- packageName: "@azure/core-rest-pipeline", ++ packageName: "@typespec/ts-http-runtime", + packageVersion: SDK_VERSION, + }); + } catch (e: unknown) { +diff --git a/src/policies/userAgentPolicy.ts b/src/policies/userAgentPolicy.ts +index bd5de30..e8a144a 100644 +--- a/src/policies/userAgentPolicy.ts ++++ b/src/policies/userAgentPolicy.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; +-import type { PipelinePolicy } from "../pipeline.js"; ++import { PipelineRequest, PipelineResponse, SendRequest } from "../interfaces.js"; ++import { PipelinePolicy } from "../pipeline.js"; + import { getUserAgentHeaderName, getUserAgentValue } from "../util/userAgent.js"; + + const UserAgentHeaderName = getUserAgentHeaderName(); +diff --git a/src/restError.ts b/src/restError.ts +index 0b2e69f..71472b4 100644 +--- a/src/restError.ts ++++ b/src/restError.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { isError } from "@azure/core-util"; +-import type { PipelineRequest, PipelineResponse } from "./interfaces.js"; ++import { isError } from "./util/error.js"; ++import { PipelineRequest, PipelineResponse } from "./interfaces.js"; + import { custom } from "./util/inspect.js"; + import { Sanitizer } from "./util/sanitizer.js"; + +diff --git a/src/retryStrategies/exponentialRetryStrategy.ts b/src/retryStrategies/exponentialRetryStrategy.ts +index c6943b8..d33e7fe 100644 +--- a/src/retryStrategies/exponentialRetryStrategy.ts ++++ b/src/retryStrategies/exponentialRetryStrategy.ts +@@ -1,10 +1,10 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineResponse } from "../interfaces.js"; +-import type { RestError } from "../restError.js"; +-import { calculateRetryDelay } from "@azure/core-util"; +-import type { RetryStrategy } from "./retryStrategy.js"; ++import { PipelineResponse } from "../interfaces.js"; ++import { RestError } from "../restError.js"; ++import { calculateRetryDelay } from "../util/delay.js"; ++import { RetryStrategy } from "./retryStrategy.js"; + import { isThrottlingRetryResponse } from "./throttlingRetryStrategy.js"; + + // intervals are in milliseconds +diff --git a/src/retryStrategies/retryStrategy.ts b/src/retryStrategies/retryStrategy.ts +index a8b94fc..332b8b8 100644 +--- a/src/retryStrategies/retryStrategy.ts ++++ b/src/retryStrategies/retryStrategy.ts +@@ -1,9 +1,9 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AzureLogger } from "@azure/logger"; +-import type { PipelineResponse } from "../interfaces.js"; +-import type { RestError } from "../restError.js"; ++import { TypeSpecRuntimeLogger } from "../logger/logger.js"; ++import { PipelineResponse } from "../interfaces.js"; ++import { RestError } from "../restError.js"; + + /** + * Information provided to the retry strategy about the current progress of the retry policy. +@@ -57,7 +57,7 @@ export interface RetryStrategy { + /** + * Logger. If it's not provided, a default logger for all retry strategies is used. + */ +- logger?: AzureLogger; ++ logger?: TypeSpecRuntimeLogger; + /** + * 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 +--- a/src/retryStrategies/throttlingRetryStrategy.ts ++++ b/src/retryStrategies/throttlingRetryStrategy.ts +@@ -1,17 +1,17 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { PipelineResponse } from "../index.js"; ++import { PipelineResponse } from "../index.js"; + import { parseHeaderValueAsNumber } from "../util/helpers.js"; +-import type { RetryStrategy } from "./retryStrategy.js"; ++import { RetryStrategy } from "./retryStrategy.js"; + + /** +- * The header that comes back from Azure services representing ++ * The header that comes back from services representing + * the amount of time (minimum) to wait to retry (in seconds or timestamp after which we can retry). + */ + const RetryAfterHeader = "Retry-After"; + /** +- * The headers that come back from Azure services representing ++ * The headers that come back from services representing + * 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 +--- a/src/tracing/index.ts ++++ /dev/null +@@ -1,23 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-export { +- AddEventOptions, +- Instrumenter, +- InstrumenterSpanOptions, +- OperationTracingOptions, +- OptionsWithTracingContext, +- Resolved, +- SpanStatus, +- SpanStatusError, +- SpanStatusSuccess, +- TracingClient, +- TracingClientOptions, +- TracingContext, +- TracingSpan, +- TracingSpanKind, +- TracingSpanLink, +- TracingSpanOptions, +-} from "./interfaces.js"; +-export { useInstrumenter } from "./instrumenter.js"; +-export { createTracingClient } from "./tracingClient.js"; +diff --git a/src/tracing/interfaces.ts b/src/tracing/interfaces.ts +index 04d0785..fe8f87b 100644 +--- a/src/tracing/interfaces.ts ++++ b/src/tracing/interfaces.ts +@@ -27,7 +27,7 @@ export interface TracingClient { + * Example: + * + * ```ts snippet:with_span_example +- * import { createTracingClient } from "@azure/core-tracing"; ++ * import { createTracingClient } from "@typespec/ts-http-runtime"; + * + * const tracingClient = createTracingClient({ + * namespace: "test.namespace", +diff --git a/src/tracing/state.ts b/src/tracing/state.ts +index ae1efaf..852ef3b 100644 +--- a/src/tracing/state.ts ++++ b/src/tracing/state.ts +@@ -4,7 +4,7 @@ + import { Instrumenter } from "./interfaces.js"; + // @ts-expect-error The recommended approach to sharing module state between ESM and CJS. + // See https://github.com/isaacs/tshy/blob/main/README.md#module-local-state for additional information. +-import { state as cjsState } from "../commonjs/state.js"; ++import { state as cjsState } from "../commonjs/tracing/state.js"; + + /** + * Defines the shared state between CJS and ESM by re-exporting the CJS state. +diff --git a/src/tracing/tracingContext.ts b/src/tracing/tracingContext.ts +index 1688905..0d6dc15 100644 +--- a/src/tracing/tracingContext.ts ++++ b/src/tracing/tracingContext.ts +@@ -5,8 +5,8 @@ import { TracingContext, TracingSpan } from "./interfaces.js"; + + /** @internal */ + export const knownContextKeys = { +- span: Symbol.for("@azure/core-tracing span"), +- namespace: Symbol.for("@azure/core-tracing namespace"), ++ span: Symbol.for("@typespec/ts-http-runtime span"), ++ namespace: Symbol.for("@typespec/ts-http-runtime namespace"), + }; + + /** +diff --git a/src/util/aborterUtils.ts b/src/util/aborterUtils.ts +index ce29be9..82e102a 100644 +--- a/src/util/aborterUtils.ts ++++ b/src/util/aborterUtils.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AbortSignalLike } from "@azure/abort-controller"; ++import { AbortSignalLike } from "../abort-controller/AbortSignalLike.js"; + + /** + * 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 ++++ b/src/util/concat.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { Readable } from "node:stream"; +-import type { ReadableStream as AsyncIterableReadableStream } from "node:stream/web"; ++import { Readable } from "stream"; ++import type { ReadableStream as AsyncIterableReadableStream } from "stream/web"; + import { isBlob } from "./typeGuards.js"; + import { getRawContent } from "./file.js"; + +diff --git a/src/util/createAbortablePromise.ts b/src/util/createAbortablePromise.ts +index 25cf55a..5eba77e 100644 +--- a/src/util/createAbortablePromise.ts ++++ b/src/util/createAbortablePromise.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { AbortError } from "@azure/abort-controller"; +-import type { AbortOptions } from "./aborterUtils.js"; ++import { AbortError } from "../abort-controller/AbortError.js"; ++import { AbortOptions } from "./aborterUtils.js"; + + /** + * Options for the createAbortablePromise function. +diff --git a/src/util/file.ts b/src/util/file.ts +index 5b65155..73d19de 100644 +--- a/src/util/file.ts ++++ b/src/util/file.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { isNodeLike } from "@azure/core-util"; ++import { isNodeLike } from "./checkEnvironment.js"; + import { isNodeReadableStream } from "./typeGuards.js"; + + /** +diff --git a/src/util/helpers.ts b/src/util/helpers.ts +index f6819e8..421e298 100644 +--- a/src/util/helpers.ts ++++ b/src/util/helpers.ts +@@ -1,8 +1,9 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { AbortError, type AbortSignalLike } from "@azure/abort-controller"; +-import type { PipelineResponse } from "../interfaces.js"; ++import { AbortError } from "../abort-controller/AbortError.js"; ++import { AbortSignalLike } from "../abort-controller/AbortSignalLike.js"; ++import { PipelineResponse } from "../interfaces.js"; + + const StandardAbortMessage = "The operation was aborted."; + +diff --git a/src/util/httpMethods.ts b/src/util/httpMethods.ts +deleted file mode 100644 +index 2748031..0000000 +--- a/src/util/httpMethods.ts ++++ /dev/null +@@ -1,16 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-/** +- * @public +- * Supported HTTP methods to use when making requests. +- */ +-export type HttpMethods = +- | "GET" +- | "PUT" +- | "POST" +- | "DELETE" +- | "PATCH" +- | "HEAD" +- | "OPTIONS" +- | "TRACE"; +diff --git a/src/util/index.ts b/src/util/index.ts +deleted file mode 100644 +index e0af55f..0000000 +--- a/src/util/index.ts ++++ /dev/null +@@ -1,31 +0,0 @@ +-// Copyright (c) Microsoft Corporation. +-// Licensed under the MIT License. +- +-export { delay, type DelayOptions, calculateRetryDelay } from "./delay.js"; +-export { +- type AbortOptions, +- cancelablePromiseRace, +- type AbortablePromiseBuilder, +-} from "./aborterUtils.js"; +-export { +- createAbortablePromise, +- type CreateAbortablePromiseOptions, +-} from "./createAbortablePromise.js"; +-export { getRandomIntegerInclusive } from "./random.js"; +-export { isObject, type UnknownObject } from "./object.js"; +-export { isError, getErrorMessage } from "./error.js"; +-export { computeSha256Hash, computeSha256Hmac } from "./sha256.js"; +-export { isDefined, isObjectWithProperties, objectHasProperty } from "./typeGuards.js"; +-export { randomUUID } from "./uuidUtils.js"; +-export { HttpMethods } from "./httpMethods.js"; +-export { +- isBrowser, +- isBun, +- isNode, +- isNodeLike, +- isNodeRuntime, +- isDeno, +- isReactNative, +- isWebWorker, +-} 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 +--- a/src/util/sanitizer.ts ++++ b/src/util/sanitizer.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { type UnknownObject, isObject } from "@azure/core-util"; ++import { UnknownObject, isObject } from "./object.js"; + + /** + * @internal +diff --git a/src/util/sha256.ts b/src/util/sha256.ts +index 80a1a23..794d26a 100644 +--- a/src/util/sha256.ts ++++ b/src/util/sha256.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { createHash, createHmac } from "crypto"; ++import { createHash, createHmac } from "node:crypto"; + + /** + * Generates a SHA-256 HMAC signature. +diff --git a/src/util/tokenCycler.ts b/src/util/tokenCycler.ts +index 32e2343..213a59e 100644 +--- a/src/util/tokenCycler.ts ++++ b/src/util/tokenCycler.ts +@@ -1,7 +1,7 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import type { AccessToken, GetTokenOptions, TokenCredential } from "@azure/core-auth"; ++import { AccessToken, GetTokenOptions, TokenCredential } from "../auth/tokenCredential.js"; + 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 ++++ b/src/util/typeGuards.ts +@@ -44,3 +44,41 @@ export function objectHasProperty( + isDefined(thing) && typeof thing === "object" && property in (thing as Record) + ); + } ++ ++export function isNodeReadableStream(x: unknown): x is NodeJS.ReadableStream { ++ return Boolean(x && typeof (x as NodeJS.ReadableStream)["pipe"] === "function"); ++} ++ ++export function isWebReadableStream(x: unknown): x is ReadableStream { ++ return Boolean( ++ x && ++ typeof (x as ReadableStream).getReader === "function" && ++ typeof (x as ReadableStream).tee === "function", ++ ); ++} ++ ++export function isBinaryBody( ++ body: unknown, ++): body is ++ | Uint8Array ++ | NodeJS.ReadableStream ++ | ReadableStream ++ | (() => NodeJS.ReadableStream) ++ | (() => ReadableStream) ++ | Blob { ++ return ( ++ body !== undefined && ++ (body instanceof Uint8Array || ++ isReadableStream(body) || ++ typeof body === "function" || ++ body instanceof Blob) ++ ); ++} ++ ++export function isReadableStream(x: unknown): x is ReadableStream | NodeJS.ReadableStream { ++ return isNodeReadableStream(x) || isWebReadableStream(x); ++} ++ ++export function isBlob(x: unknown): x is Blob { ++ return typeof (x as Blob).stream === "function"; ++} +diff --git a/src/util/userAgent.ts b/src/util/userAgent.ts +index b8950b5..3ef33c8 100644 +--- a/src/util/userAgent.ts ++++ b/src/util/userAgent.ts +@@ -25,7 +25,7 @@ export function getUserAgentHeaderName(): string { + */ + export async function getUserAgentValue(prefix?: string): Promise { + const runtimeInfo = new Map(); +- runtimeInfo.set("core-rest-pipeline", SDK_VERSION); ++ runtimeInfo.set("ts-http-runtime", SDK_VERSION); + 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 +--- a/src/util/uuidUtils.ts ++++ b/src/util/uuidUtils.ts +@@ -1,7 +1,8 @@ + // 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 ++++ b/src/xhrHttpClient.ts +@@ -1,8 +1,8 @@ + // Copyright (c) Microsoft Corporation. + // Licensed under the MIT License. + +-import { AbortError } from "@azure/abort-controller"; +-import type { ++import { AbortError } from "./abort-controller/AbortError.js"; ++import { + HttpClient, + HttpHeaders, + PipelineRequest, diff --git a/sdk/core/ts-http-runtime/scripts/azure-diff.ts b/sdk/core/ts-http-runtime/scripts/azure-diff.ts new file mode 100644 index 00000000000..6952b2f4b08 --- /dev/null +++ b/sdk/core/ts-http-runtime/scripts/azure-diff.ts @@ -0,0 +1,156 @@ +import { parseArgs } from "node:util"; +import fs from "node:fs/promises"; +import { spawn, SpawnOptions } from "node:child_process"; +import { exit } from "node:process"; +import path from "node:path"; + +/** + * Mapping of locations of Azure source files to their location in the unbranded package. + */ +const AZURE_SOURCES = { + // core-rest-pipeline is placed at the root of the unbranded package; this also covers subfolders of + // core-rest-pipeline including policies/ and retryStrategies/. + "../core-rest-pipeline/src/": "./src/", + "../core-util/src/": "./src/util/", + "../core-auth/src/": "./src/auth/", + "../abort-controller/src/": "./src/abort-controller/", + "../core-client-rest/src/": "./src/client/", + "../core-tracing/src/": "./src/tracing/", + "../logger/src/": "./src/logger/", +}; + +const { + values: { + update = false, + "output-path": outputPath = "./review/azure-core-comparison.diff", + verbose = false, + }, +} = parseArgs({ + options: { + update: { + type: "boolean", + }, + "output-path": { + type: "string", + short: "o", + }, + verbose: { + type: "boolean", + short: "v", + }, + }, +}); + +interface RunResult { + exitCode?: number; + signal?: NodeJS.Signals; + stdout: string; +} + +/** + * Runs the given CLI command and captures the output + */ +async function run( + commandAndArgs: [string, ...string[]], + options: SpawnOptions = {}, +): Promise { + let stdout = ""; + const [command, ...args] = commandAndArgs; + + const proc = spawn(command, args, options); + + return new Promise((resolve, reject) => { + proc.on("error", reject); + proc.on("exit", (exitCode, signal) => { + resolve({ + exitCode: exitCode ?? undefined, + signal: signal ?? undefined, + stdout, + }); + }); + proc.stdout?.on("data", (data) => { + stdout += data.toString(); + if (verbose) { + process.stdout.write(data); + } + }); + + if (verbose) { + proc.stderr?.on("data", (data) => process.stderr.write(data)); + } + }); +} + +/** + * Creates a diff representing code changes between the Azure core packages and the unbranded package. + * + * This is done by using a temp folder/git repo. The Azure core files are copied into the temp folder following + * the mappings defined in AZURE_SOURCES. This is then committed, and then the temp folder is cleaned out and the unbranded + * Core is copied in. The diff (as reported by `git diff`) between the committed Azure core files and the unbranded replacement + * is returned. + */ +async function calculatePatchFileContents(): Promise { + const tmpDir = await fs.mkdtemp(".azure-diff-tool"); + + try { + // Initialize temp git repo + await run(["git", "init"], { cwd: tmpDir }); + + // Copy over the Azure Core files to where are expected to be in the unbranded Core package + for (const [azurePath, newLocation] of Object.entries(AZURE_SOURCES)) { + await fs.cp(azurePath, path.join(tmpDir, newLocation), { recursive: true }); + } + + // Commit the Azure files, then remove everything so that they can be replaced by the unbranded files + await run(["git", "add", "."], { cwd: tmpDir }); + await run(["git", "commit", "-m", "Placeholder commit"], { cwd: tmpDir }); + await fs.rm(path.join(tmpDir, "src"), { recursive: true, force: true }); + + // Copy the unbranded files into the temp repo + await fs.cp("./src/", path.join(tmpDir, "src"), { recursive: true }); + + // Staging the unbranded files and using `git diff --staged` means that the diff will also show files + // that have been removed and moved. + await run(["git", "add", "."], { cwd: tmpDir }); + const { stdout } = await run( + ["git", "diff", "--ignore-all-space", "--staged", "--find-renames"], + { cwd: tmpDir }, + ); + return stdout; + } finally { + await fs.rm(tmpDir, { recursive: true, force: true }); + } +} + +async function main(): Promise { + const expectedContent = await calculatePatchFileContents(); + + if (update) { + await fs.writeFile(outputPath, expectedContent, "utf-8"); + } else { + const content = await fs.readFile(outputPath, "utf-8"); + + if (content === expectedContent) { + console.log("✅ No changes to Azure to unbranded diff report"); + } else { + console.error("❌ There have been changes to the Azure-unbranded diff report."); + console.error( + " This happens when you make a change to Azure Core without making the same change in the unbranded Core package.", + ); + console.error(" To fix:"); + console.error( + " - Run `rushx lint:fix` in the ts-http-runtime package to update review/azure-core-comparison.diff, then have a look and see what's changed.", + ); + console.error(" - Apply your Core changes to the ts-http-runtime package as appropriate."); + console.error( + " - Run `rushx lint:fix` again package to update the diff report, and commit the changes.", + ); + exit(1); + } + } +} + +main().catch((err) => { + console.error(err); + process.exit(1); +});