@typespec/ts-http-runtime 0.3.5-alpha.20260306.4 → 0.3.5-alpha.20260310.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,8 @@ import type { PathParameterWithOptions, RequestParameters } from "./common.js";
8
8
  * @returns a full url with path and query parameters
9
9
  */
10
10
  export declare function buildRequestUrl(endpoint: string, routePath: string, pathParameters: (string | number | PathParameterWithOptions)[], options?: RequestParameters): string;
11
+ /** @internal */
12
+ export declare function appendQueryParams(url: string, options?: RequestParameters): string;
11
13
  export declare function buildBaseUrl(endpoint: string, options: RequestParameters): string;
12
14
  /**
13
15
  * Replace all of the instances of searchValue in value with the provided replaceValue.
@@ -17,13 +17,43 @@ export function buildRequestUrl(endpoint, routePath, pathParameters, options = {
17
17
  return routePath;
18
18
  }
19
19
  endpoint = buildBaseUrl(endpoint, options);
20
- routePath = buildRoutePath(routePath, pathParameters, options);
21
- const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);
20
+ // the route could be
21
+ // 1. a path: "container123/blob456"
22
+ // 2. a component string from template which starts with "?" and may contain more "?" after template is expanded,
23
+ // e.g., "?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27"
24
+ const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);
25
+ const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);
22
26
  const url = new URL(requestUrl);
23
- return (url
24
- .toString()
25
- // Remove double forward slashes
26
- .replace(/([^:]\/)\/+/g, "$1"));
27
+ return url.toString();
28
+ }
29
+ function appendPath(endpoint, pathToAppend) {
30
+ const endpointSearchStart = endpoint.indexOf("?");
31
+ const pathSearchStart = pathToAppend.indexOf("?");
32
+ const endpointParts = endpointSearchStart !== -1
33
+ ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]
34
+ : [endpoint, ""];
35
+ const pathParts = pathSearchStart !== -1
36
+ ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]
37
+ : [pathToAppend, ""];
38
+ const combinedSearch = [endpointParts[1], pathParts[1].replaceAll("?", "&")]
39
+ .filter(Boolean)
40
+ .join("&");
41
+ const baseEndpoint = endpointParts[0];
42
+ const basePathToAppend = pathParts[0];
43
+ let combinedUrl = baseEndpoint;
44
+ if (!baseEndpoint.endsWith("/") && !basePathToAppend.startsWith("/") && basePathToAppend !== "") {
45
+ combinedUrl += `/${basePathToAppend}`;
46
+ }
47
+ else if (baseEndpoint.endsWith("/") && basePathToAppend.startsWith("/")) {
48
+ combinedUrl += basePathToAppend.substring(1);
49
+ }
50
+ else {
51
+ combinedUrl += basePathToAppend;
52
+ }
53
+ if (combinedSearch) {
54
+ combinedUrl += `?${combinedSearch}`;
55
+ }
56
+ return combinedUrl;
27
57
  }
28
58
  function getQueryParamValue(key, allowReserved, style, param) {
29
59
  let separator;
@@ -62,13 +92,48 @@ function getQueryParamValue(key, allowReserved, style, param) {
62
92
  .join(separator);
63
93
  return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;
64
94
  }
65
- function appendQueryParams(url, options = {}) {
95
+ /**
96
+ * Parses a query string into a map of key/value pairs without decoding the values.
97
+ * This avoids the issue where `URL.searchParams` would decode values, potentially
98
+ * corrupting already-encoded values such as SAS signatures.
99
+ */
100
+ function simpleParseQueryParams(queryString) {
101
+ const result = new Map();
102
+ if (!queryString || queryString[0] !== "?") {
103
+ return result;
104
+ }
105
+ // remove the leading ?
106
+ queryString = queryString.slice(1);
107
+ const pairs = queryString.split("&");
108
+ for (const pair of pairs) {
109
+ const eqIndex = pair.indexOf("=");
110
+ const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);
111
+ const value = eqIndex === -1 ? "" : pair.substring(eqIndex + 1);
112
+ const existingValue = result.get(name);
113
+ if (existingValue !== undefined) {
114
+ if (Array.isArray(existingValue)) {
115
+ existingValue.push(value);
116
+ }
117
+ else {
118
+ result.set(name, [existingValue, value]);
119
+ }
120
+ }
121
+ else {
122
+ result.set(name, value);
123
+ }
124
+ }
125
+ return result;
126
+ }
127
+ /** @internal */
128
+ export function appendQueryParams(url, options = {}) {
66
129
  if (!options.queryParameters) {
67
130
  return url;
68
131
  }
69
132
  const parsedUrl = new URL(url);
70
133
  const queryParams = options.queryParameters;
71
- const paramStrings = [];
134
+ // Parse existing query params from the URL manually to avoid re-encoding issues
135
+ const existingParams = simpleParseQueryParams(parsedUrl.search);
136
+ const newParamStrings = [];
72
137
  for (const key of Object.keys(queryParams)) {
73
138
  const param = queryParams[key];
74
139
  if (param === undefined || param === null) {
@@ -81,13 +146,13 @@ function appendQueryParams(url, options = {}) {
81
146
  if (explode) {
82
147
  if (Array.isArray(rawValue)) {
83
148
  for (const item of rawValue) {
84
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
149
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
85
150
  }
86
151
  }
87
152
  else if (typeof rawValue === "object") {
88
153
  // For object explode, the name of the query parameter is ignored and we use the object key instead
89
154
  for (const [actualKey, value] of Object.entries(rawValue)) {
90
- paramStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
155
+ newParamStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
91
156
  }
92
157
  }
93
158
  else {
@@ -96,13 +161,43 @@ function appendQueryParams(url, options = {}) {
96
161
  }
97
162
  }
98
163
  else {
99
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
164
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
165
+ }
166
+ }
167
+ // Merge new params into existing params, deduplicating values for the same key
168
+ for (const paramString of newParamStrings) {
169
+ const eqIndex = paramString.indexOf("=");
170
+ const name = paramString.substring(0, eqIndex);
171
+ const value = paramString.substring(eqIndex + 1);
172
+ const existingValue = existingParams.get(name);
173
+ if (existingValue !== undefined) {
174
+ if (Array.isArray(existingValue)) {
175
+ if (!existingValue.includes(value)) {
176
+ existingValue.push(value);
177
+ }
178
+ }
179
+ else if (existingValue !== value) {
180
+ existingParams.set(name, [existingValue, value]);
181
+ }
182
+ // if existingValue === value (single string match), no change needed
183
+ }
184
+ else {
185
+ existingParams.set(name, value);
100
186
  }
101
187
  }
102
- if (parsedUrl.search !== "") {
103
- parsedUrl.search += "&";
188
+ // Reconstruct the search string manually to avoid URL re-encoding
189
+ const searchPieces = [];
190
+ for (const [name, value] of existingParams) {
191
+ if (Array.isArray(value)) {
192
+ for (const subValue of value) {
193
+ searchPieces.push(`${name}=${subValue}`);
194
+ }
195
+ }
196
+ else {
197
+ searchPieces.push(`${name}=${value}`);
198
+ }
104
199
  }
105
- parsedUrl.search += paramStrings.join("&");
200
+ parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
106
201
  return parsedUrl.toString();
107
202
  }
108
203
  export function buildBaseUrl(endpoint, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n routePath = buildRoutePath(routePath, pathParameters, options);\n const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);\n const url = new URL(requestUrl);\n\n return (\n url\n .toString()\n // Remove double forward slashes\n .replace(/([^:]\\/)\\/+/g, \"$1\")\n );\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\nfunction appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n const paramStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n paramStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));\n }\n }\n\n if (parsedUrl.search !== \"\") {\n parsedUrl.search += \"&\";\n }\n parsedUrl.search += paramStrings.join(\"&\");\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
1
+ {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n // the route could be\n // 1. a path: \"container123/blob456\"\n // 2. a component string from template which starts with \"?\" and may contain more \"?\" after template is expanded,\n // e.g., \"?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27\"\n const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);\n\n const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);\n const url = new URL(requestUrl);\n\n return url.toString();\n}\n\nfunction appendPath(endpoint: string, pathToAppend: string): string {\n const endpointSearchStart = endpoint.indexOf(\"?\");\n const pathSearchStart = pathToAppend.indexOf(\"?\");\n const endpointParts =\n endpointSearchStart !== -1\n ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]\n : [endpoint, \"\"];\n const pathParts =\n pathSearchStart !== -1\n ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]\n : [pathToAppend, \"\"];\n\n const combinedSearch = [endpointParts[1], pathParts[1].replaceAll(\"?\", \"&\")]\n .filter(Boolean)\n .join(\"&\");\n const baseEndpoint = endpointParts[0];\n const basePathToAppend = pathParts[0];\n\n let combinedUrl = baseEndpoint;\n if (!baseEndpoint.endsWith(\"/\") && !basePathToAppend.startsWith(\"/\") && basePathToAppend !== \"\") {\n combinedUrl += `/${basePathToAppend}`;\n } else if (baseEndpoint.endsWith(\"/\") && basePathToAppend.startsWith(\"/\")) {\n combinedUrl += basePathToAppend.substring(1);\n } else {\n combinedUrl += basePathToAppend;\n }\n\n if (combinedSearch) {\n combinedUrl += `?${combinedSearch}`;\n }\n\n return combinedUrl;\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\n/**\n * Parses a query string into a map of key/value pairs without decoding the values.\n * This avoids the issue where `URL.searchParams` would decode values, potentially\n * corrupting already-encoded values such as SAS signatures.\n */\nfunction simpleParseQueryParams(queryString: string): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n if (!queryString || queryString[0] !== \"?\") {\n return result;\n }\n\n // remove the leading ?\n queryString = queryString.slice(1);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);\n const value = eqIndex === -1 ? \"\" : pair.substring(eqIndex + 1);\n\n const existingValue = result.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n } else {\n result.set(name, [existingValue, value]);\n }\n } else {\n result.set(name, value);\n }\n }\n\n return result;\n}\n\n/** @internal */\nexport function appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n // Parse existing query params from the URL manually to avoid re-encoding issues\n const existingParams = simpleParseQueryParams(parsedUrl.search);\n\n const newParamStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item),\n );\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n newParamStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue),\n );\n }\n }\n\n // Merge new params into existing params, deduplicating values for the same key\n for (const paramString of newParamStrings) {\n const eqIndex = paramString.indexOf(\"=\");\n const name = paramString.substring(0, eqIndex);\n const value = paramString.substring(eqIndex + 1);\n\n const existingValue = existingParams.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n if (!existingValue.includes(value)) {\n existingValue.push(value);\n }\n } else if (existingValue !== value) {\n existingParams.set(name, [existingValue, value]);\n }\n // if existingValue === value (single string match), no change needed\n } else {\n existingParams.set(name, value);\n }\n }\n\n // Reconstruct the search string manually to avoid URL re-encoding\n const searchPieces: string[] = [];\n for (const [name, value] of existingParams) {\n if (Array.isArray(value)) {\n for (const subValue of value) {\n searchPieces.push(`${name}=${subValue}`);\n }\n } else {\n searchPieces.push(`${name}=${value}`);\n }\n }\n\n parsedUrl.search = searchPieces.length ? `?${searchPieces.join(\"&\")}` : \"\";\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
@@ -8,6 +8,8 @@ import type { PathParameterWithOptions, RequestParameters } from "./common.js";
8
8
  * @returns a full url with path and query parameters
9
9
  */
10
10
  export declare function buildRequestUrl(endpoint: string, routePath: string, pathParameters: (string | number | PathParameterWithOptions)[], options?: RequestParameters): string;
11
+ /** @internal */
12
+ export declare function appendQueryParams(url: string, options?: RequestParameters): string;
11
13
  export declare function buildBaseUrl(endpoint: string, options: RequestParameters): string;
12
14
  /**
13
15
  * Replace all of the instances of searchValue in value with the provided replaceValue.
@@ -17,6 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
  var urlHelpers_exports = {};
19
19
  __export(urlHelpers_exports, {
20
+ appendQueryParams: () => appendQueryParams,
20
21
  buildBaseUrl: () => buildBaseUrl,
21
22
  buildRequestUrl: () => buildRequestUrl,
22
23
  replaceAll: () => replaceAll
@@ -31,10 +32,31 @@ function buildRequestUrl(endpoint, routePath, pathParameters, options = {}) {
31
32
  return routePath;
32
33
  }
33
34
  endpoint = buildBaseUrl(endpoint, options);
34
- routePath = buildRoutePath(routePath, pathParameters, options);
35
- const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);
35
+ const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);
36
+ const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);
36
37
  const url = new URL(requestUrl);
37
- return url.toString().replace(/([^:]\/)\/+/g, "$1");
38
+ return url.toString();
39
+ }
40
+ function appendPath(endpoint, pathToAppend) {
41
+ const endpointSearchStart = endpoint.indexOf("?");
42
+ const pathSearchStart = pathToAppend.indexOf("?");
43
+ const endpointParts = endpointSearchStart !== -1 ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)] : [endpoint, ""];
44
+ const pathParts = pathSearchStart !== -1 ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)] : [pathToAppend, ""];
45
+ const combinedSearch = [endpointParts[1], pathParts[1].replaceAll("?", "&")].filter(Boolean).join("&");
46
+ const baseEndpoint = endpointParts[0];
47
+ const basePathToAppend = pathParts[0];
48
+ let combinedUrl = baseEndpoint;
49
+ if (!baseEndpoint.endsWith("/") && !basePathToAppend.startsWith("/") && basePathToAppend !== "") {
50
+ combinedUrl += `/${basePathToAppend}`;
51
+ } else if (baseEndpoint.endsWith("/") && basePathToAppend.startsWith("/")) {
52
+ combinedUrl += basePathToAppend.substring(1);
53
+ } else {
54
+ combinedUrl += basePathToAppend;
55
+ }
56
+ if (combinedSearch) {
57
+ combinedUrl += `?${combinedSearch}`;
58
+ }
59
+ return combinedUrl;
38
60
  }
39
61
  function getQueryParamValue(key, allowReserved, style, param) {
40
62
  let separator;
@@ -65,13 +87,38 @@ function getQueryParamValue(key, allowReserved, style, param) {
65
87
  }).join(separator);
66
88
  return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;
67
89
  }
90
+ function simpleParseQueryParams(queryString) {
91
+ const result = /* @__PURE__ */ new Map();
92
+ if (!queryString || queryString[0] !== "?") {
93
+ return result;
94
+ }
95
+ queryString = queryString.slice(1);
96
+ const pairs = queryString.split("&");
97
+ for (const pair of pairs) {
98
+ const eqIndex = pair.indexOf("=");
99
+ const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);
100
+ const value = eqIndex === -1 ? "" : pair.substring(eqIndex + 1);
101
+ const existingValue = result.get(name);
102
+ if (existingValue !== void 0) {
103
+ if (Array.isArray(existingValue)) {
104
+ existingValue.push(value);
105
+ } else {
106
+ result.set(name, [existingValue, value]);
107
+ }
108
+ } else {
109
+ result.set(name, value);
110
+ }
111
+ }
112
+ return result;
113
+ }
68
114
  function appendQueryParams(url, options = {}) {
69
115
  if (!options.queryParameters) {
70
116
  return url;
71
117
  }
72
118
  const parsedUrl = new URL(url);
73
119
  const queryParams = options.queryParameters;
74
- const paramStrings = [];
120
+ const existingParams = simpleParseQueryParams(parsedUrl.search);
121
+ const newParamStrings = [];
75
122
  for (const key of Object.keys(queryParams)) {
76
123
  const param = queryParams[key];
77
124
  if (param === void 0 || param === null) {
@@ -84,11 +131,13 @@ function appendQueryParams(url, options = {}) {
84
131
  if (explode) {
85
132
  if (Array.isArray(rawValue)) {
86
133
  for (const item of rawValue) {
87
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
134
+ newParamStrings.push(
135
+ getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item)
136
+ );
88
137
  }
89
138
  } else if (typeof rawValue === "object") {
90
139
  for (const [actualKey, value] of Object.entries(rawValue)) {
91
- paramStrings.push(
140
+ newParamStrings.push(
92
141
  getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value)
93
142
  );
94
143
  }
@@ -96,13 +145,39 @@ function appendQueryParams(url, options = {}) {
96
145
  throw new Error("explode can only be set to true for objects and arrays");
97
146
  }
98
147
  } else {
99
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
148
+ newParamStrings.push(
149
+ getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue)
150
+ );
151
+ }
152
+ }
153
+ for (const paramString of newParamStrings) {
154
+ const eqIndex = paramString.indexOf("=");
155
+ const name = paramString.substring(0, eqIndex);
156
+ const value = paramString.substring(eqIndex + 1);
157
+ const existingValue = existingParams.get(name);
158
+ if (existingValue !== void 0) {
159
+ if (Array.isArray(existingValue)) {
160
+ if (!existingValue.includes(value)) {
161
+ existingValue.push(value);
162
+ }
163
+ } else if (existingValue !== value) {
164
+ existingParams.set(name, [existingValue, value]);
165
+ }
166
+ } else {
167
+ existingParams.set(name, value);
100
168
  }
101
169
  }
102
- if (parsedUrl.search !== "") {
103
- parsedUrl.search += "&";
170
+ const searchPieces = [];
171
+ for (const [name, value] of existingParams) {
172
+ if (Array.isArray(value)) {
173
+ for (const subValue of value) {
174
+ searchPieces.push(`${name}=${subValue}`);
175
+ }
176
+ } else {
177
+ searchPieces.push(`${name}=${value}`);
178
+ }
104
179
  }
105
- parsedUrl.search += paramStrings.join("&");
180
+ parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
106
181
  return parsedUrl.toString();
107
182
  }
108
183
  function buildBaseUrl(endpoint, options) {
@@ -141,6 +216,7 @@ function replaceAll(value, searchValue, replaceValue) {
141
216
  }
142
217
  // Annotate the CommonJS export names for ESM import in node:
143
218
  0 && (module.exports = {
219
+ appendQueryParams,
144
220
  buildBaseUrl,
145
221
  buildRequestUrl,
146
222
  replaceAll
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["/mnt/vss/_work/1/s/sdk/core/ts-http-runtime/src/client/urlHelpers.ts"],
4
- "sourcesContent": ["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n routePath = buildRoutePath(routePath, pathParameters, options);\n const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);\n const url = new URL(requestUrl);\n\n return (\n url\n .toString()\n // Remove double forward slashes\n .replace(/([^:]\\/)\\/+/g, \"$1\")\n );\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\nfunction appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n const paramStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n paramStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));\n }\n }\n\n if (parsedUrl.search !== \"\") {\n parsedUrl.search += \"&\";\n }\n parsedUrl.search += paramStrings.join(\"&\");\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n // the route could be\n // 1. a path: \"container123/blob456\"\n // 2. a component string from template which starts with \"?\" and may contain more \"?\" after template is expanded,\n // e.g., \"?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27\"\n const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);\n\n const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);\n const url = new URL(requestUrl);\n\n return url.toString();\n}\n\nfunction appendPath(endpoint: string, pathToAppend: string): string {\n const endpointSearchStart = endpoint.indexOf(\"?\");\n const pathSearchStart = pathToAppend.indexOf(\"?\");\n const endpointParts =\n endpointSearchStart !== -1\n ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]\n : [endpoint, \"\"];\n const pathParts =\n pathSearchStart !== -1\n ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]\n : [pathToAppend, \"\"];\n\n const combinedSearch = [endpointParts[1], pathParts[1].replaceAll(\"?\", \"&\")]\n .filter(Boolean)\n .join(\"&\");\n const baseEndpoint = endpointParts[0];\n const basePathToAppend = pathParts[0];\n\n let combinedUrl = baseEndpoint;\n if (!baseEndpoint.endsWith(\"/\") && !basePathToAppend.startsWith(\"/\") && basePathToAppend !== \"\") {\n combinedUrl += `/${basePathToAppend}`;\n } else if (baseEndpoint.endsWith(\"/\") && basePathToAppend.startsWith(\"/\")) {\n combinedUrl += basePathToAppend.substring(1);\n } else {\n combinedUrl += basePathToAppend;\n }\n\n if (combinedSearch) {\n combinedUrl += `?${combinedSearch}`;\n }\n\n return combinedUrl;\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\n/**\n * Parses a query string into a map of key/value pairs without decoding the values.\n * This avoids the issue where `URL.searchParams` would decode values, potentially\n * corrupting already-encoded values such as SAS signatures.\n */\nfunction simpleParseQueryParams(queryString: string): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n if (!queryString || queryString[0] !== \"?\") {\n return result;\n }\n\n // remove the leading ?\n queryString = queryString.slice(1);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);\n const value = eqIndex === -1 ? \"\" : pair.substring(eqIndex + 1);\n\n const existingValue = result.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n } else {\n result.set(name, [existingValue, value]);\n }\n } else {\n result.set(name, value);\n }\n }\n\n return result;\n}\n\n/** @internal */\nexport function appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n // Parse existing query params from the URL manually to avoid re-encoding issues\n const existingParams = simpleParseQueryParams(parsedUrl.search);\n\n const newParamStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item),\n );\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n newParamStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue),\n );\n }\n }\n\n // Merge new params into existing params, deduplicating values for the same key\n for (const paramString of newParamStrings) {\n const eqIndex = paramString.indexOf(\"=\");\n const name = paramString.substring(0, eqIndex);\n const value = paramString.substring(eqIndex + 1);\n\n const existingValue = existingParams.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n if (!existingValue.includes(value)) {\n existingValue.push(value);\n }\n } else if (existingValue !== value) {\n existingParams.set(name, [existingValue, value]);\n }\n // if existingValue === value (single string match), no change needed\n } else {\n existingParams.set(name, value);\n }\n }\n\n // Reconstruct the search string manually to avoid URL re-encoding\n const searchPieces: string[] = [];\n for (const [name, value] of existingParams) {\n if (Array.isArray(value)) {\n for (const subValue of value) {\n searchPieces.push(`${name}=${subValue}`);\n }\n } else {\n searchPieces.push(`${name}=${value}`);\n }\n }\n\n parsedUrl.search = searchPieces.length ? `?${searchPieces.join(\"&\")}` : \"\";\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,8 @@ import type { PathParameterWithOptions, RequestParameters } from "./common.js";
8
8
  * @returns a full url with path and query parameters
9
9
  */
10
10
  export declare function buildRequestUrl(endpoint: string, routePath: string, pathParameters: (string | number | PathParameterWithOptions)[], options?: RequestParameters): string;
11
+ /** @internal */
12
+ export declare function appendQueryParams(url: string, options?: RequestParameters): string;
11
13
  export declare function buildBaseUrl(endpoint: string, options: RequestParameters): string;
12
14
  /**
13
15
  * Replace all of the instances of searchValue in value with the provided replaceValue.
@@ -17,13 +17,43 @@ export function buildRequestUrl(endpoint, routePath, pathParameters, options = {
17
17
  return routePath;
18
18
  }
19
19
  endpoint = buildBaseUrl(endpoint, options);
20
- routePath = buildRoutePath(routePath, pathParameters, options);
21
- const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);
20
+ // the route could be
21
+ // 1. a path: "container123/blob456"
22
+ // 2. a component string from template which starts with "?" and may contain more "?" after template is expanded,
23
+ // e.g., "?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27"
24
+ const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);
25
+ const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);
22
26
  const url = new URL(requestUrl);
23
- return (url
24
- .toString()
25
- // Remove double forward slashes
26
- .replace(/([^:]\/)\/+/g, "$1"));
27
+ return url.toString();
28
+ }
29
+ function appendPath(endpoint, pathToAppend) {
30
+ const endpointSearchStart = endpoint.indexOf("?");
31
+ const pathSearchStart = pathToAppend.indexOf("?");
32
+ const endpointParts = endpointSearchStart !== -1
33
+ ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]
34
+ : [endpoint, ""];
35
+ const pathParts = pathSearchStart !== -1
36
+ ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]
37
+ : [pathToAppend, ""];
38
+ const combinedSearch = [endpointParts[1], pathParts[1].replaceAll("?", "&")]
39
+ .filter(Boolean)
40
+ .join("&");
41
+ const baseEndpoint = endpointParts[0];
42
+ const basePathToAppend = pathParts[0];
43
+ let combinedUrl = baseEndpoint;
44
+ if (!baseEndpoint.endsWith("/") && !basePathToAppend.startsWith("/") && basePathToAppend !== "") {
45
+ combinedUrl += `/${basePathToAppend}`;
46
+ }
47
+ else if (baseEndpoint.endsWith("/") && basePathToAppend.startsWith("/")) {
48
+ combinedUrl += basePathToAppend.substring(1);
49
+ }
50
+ else {
51
+ combinedUrl += basePathToAppend;
52
+ }
53
+ if (combinedSearch) {
54
+ combinedUrl += `?${combinedSearch}`;
55
+ }
56
+ return combinedUrl;
27
57
  }
28
58
  function getQueryParamValue(key, allowReserved, style, param) {
29
59
  let separator;
@@ -62,13 +92,48 @@ function getQueryParamValue(key, allowReserved, style, param) {
62
92
  .join(separator);
63
93
  return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;
64
94
  }
65
- function appendQueryParams(url, options = {}) {
95
+ /**
96
+ * Parses a query string into a map of key/value pairs without decoding the values.
97
+ * This avoids the issue where `URL.searchParams` would decode values, potentially
98
+ * corrupting already-encoded values such as SAS signatures.
99
+ */
100
+ function simpleParseQueryParams(queryString) {
101
+ const result = new Map();
102
+ if (!queryString || queryString[0] !== "?") {
103
+ return result;
104
+ }
105
+ // remove the leading ?
106
+ queryString = queryString.slice(1);
107
+ const pairs = queryString.split("&");
108
+ for (const pair of pairs) {
109
+ const eqIndex = pair.indexOf("=");
110
+ const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);
111
+ const value = eqIndex === -1 ? "" : pair.substring(eqIndex + 1);
112
+ const existingValue = result.get(name);
113
+ if (existingValue !== undefined) {
114
+ if (Array.isArray(existingValue)) {
115
+ existingValue.push(value);
116
+ }
117
+ else {
118
+ result.set(name, [existingValue, value]);
119
+ }
120
+ }
121
+ else {
122
+ result.set(name, value);
123
+ }
124
+ }
125
+ return result;
126
+ }
127
+ /** @internal */
128
+ export function appendQueryParams(url, options = {}) {
66
129
  if (!options.queryParameters) {
67
130
  return url;
68
131
  }
69
132
  const parsedUrl = new URL(url);
70
133
  const queryParams = options.queryParameters;
71
- const paramStrings = [];
134
+ // Parse existing query params from the URL manually to avoid re-encoding issues
135
+ const existingParams = simpleParseQueryParams(parsedUrl.search);
136
+ const newParamStrings = [];
72
137
  for (const key of Object.keys(queryParams)) {
73
138
  const param = queryParams[key];
74
139
  if (param === undefined || param === null) {
@@ -81,13 +146,13 @@ function appendQueryParams(url, options = {}) {
81
146
  if (explode) {
82
147
  if (Array.isArray(rawValue)) {
83
148
  for (const item of rawValue) {
84
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
149
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
85
150
  }
86
151
  }
87
152
  else if (typeof rawValue === "object") {
88
153
  // For object explode, the name of the query parameter is ignored and we use the object key instead
89
154
  for (const [actualKey, value] of Object.entries(rawValue)) {
90
- paramStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
155
+ newParamStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
91
156
  }
92
157
  }
93
158
  else {
@@ -96,13 +161,43 @@ function appendQueryParams(url, options = {}) {
96
161
  }
97
162
  }
98
163
  else {
99
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
164
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
165
+ }
166
+ }
167
+ // Merge new params into existing params, deduplicating values for the same key
168
+ for (const paramString of newParamStrings) {
169
+ const eqIndex = paramString.indexOf("=");
170
+ const name = paramString.substring(0, eqIndex);
171
+ const value = paramString.substring(eqIndex + 1);
172
+ const existingValue = existingParams.get(name);
173
+ if (existingValue !== undefined) {
174
+ if (Array.isArray(existingValue)) {
175
+ if (!existingValue.includes(value)) {
176
+ existingValue.push(value);
177
+ }
178
+ }
179
+ else if (existingValue !== value) {
180
+ existingParams.set(name, [existingValue, value]);
181
+ }
182
+ // if existingValue === value (single string match), no change needed
183
+ }
184
+ else {
185
+ existingParams.set(name, value);
100
186
  }
101
187
  }
102
- if (parsedUrl.search !== "") {
103
- parsedUrl.search += "&";
188
+ // Reconstruct the search string manually to avoid URL re-encoding
189
+ const searchPieces = [];
190
+ for (const [name, value] of existingParams) {
191
+ if (Array.isArray(value)) {
192
+ for (const subValue of value) {
193
+ searchPieces.push(`${name}=${subValue}`);
194
+ }
195
+ }
196
+ else {
197
+ searchPieces.push(`${name}=${value}`);
198
+ }
104
199
  }
105
- parsedUrl.search += paramStrings.join("&");
200
+ parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
106
201
  return parsedUrl.toString();
107
202
  }
108
203
  export function buildBaseUrl(endpoint, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n routePath = buildRoutePath(routePath, pathParameters, options);\n const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);\n const url = new URL(requestUrl);\n\n return (\n url\n .toString()\n // Remove double forward slashes\n .replace(/([^:]\\/)\\/+/g, \"$1\")\n );\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\nfunction appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n const paramStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n paramStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));\n }\n }\n\n if (parsedUrl.search !== \"\") {\n parsedUrl.search += \"&\";\n }\n parsedUrl.search += paramStrings.join(\"&\");\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
1
+ {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAqClC,SAAS,2BAA2B,CAAC,CAAU;IAC7C,MAAM,KAAK,GAAI,CAA+B,CAAC,KAAY,CAAC;IAC5D,OAAO,CACL,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,UAAU,CAC5F,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,SAAiB,EACjB,cAA8D,EAC9D,UAA6B,EAAE;IAE/B,IAAI,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACxE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3C,qBAAqB;IACrB,sCAAsC;IACtC,mHAAmH;IACnH,wGAAwG;IACxG,MAAM,gBAAgB,GAAG,cAAc,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IAEhC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB,EAAE,YAAoB;IACxD,MAAM,mBAAmB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,aAAa,GACjB,mBAAmB,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,mBAAmB,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,mBAAmB,GAAG,CAAC,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrB,MAAM,SAAS,GACb,eAAe,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAEzB,MAAM,cAAc,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;SACzE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAEtC,IAAI,WAAW,GAAG,YAAY,CAAC;IAC/B,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,gBAAgB,KAAK,EAAE,EAAE,CAAC;QAChG,WAAW,IAAI,IAAI,gBAAgB,EAAE,CAAC;IACxC,CAAC;SAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1E,WAAW,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,WAAW,IAAI,gBAAgB,CAAC;IAClC,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,WAAW,IAAI,IAAI,cAAc,EAAE,CAAC;IACtC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,kBAAkB,CACzB,GAAW,EACX,aAAsB,EACtB,KAA0B,EAC1B,KAAU;IAEV,IAAI,SAAiB,CAAC;IACtB,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;QAC9B,SAAS,GAAG,GAAG,CAAC;IAClB,CAAC;SAAM,IAAI,KAAK,KAAK,gBAAgB,EAAE,CAAC;QACtC,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,IAAI,WAAkB,CAAC;IACvB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,WAAW,GAAG,KAAK,CAAC;IACtB,CAAC;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QACrF,wFAAwF;QACxF,yFAAyF;QACzF,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,KAAK,GAAG,WAAW;SACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,8DAA8D,GAAG,QAAQ,CAAC,CAAC;QAC7F,CAAC;QAED,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9E,OAAO,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC;SACD,IAAI,CAAC,SAAS,CAAC,CAAC;IAEnB,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,WAAmB;IACjD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;IACpD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QAC3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uBAAuB;IACvB,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAEhE,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;gBACjC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,UAA6B,EAAE;IAC5E,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QAC7B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAE5C,gFAAgF;IAChF,MAAM,cAAc,GAAG,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEhE,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAQ,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QACnD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC/D,MAAM,KAAK,GAAG,WAAW,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAEhE,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,eAAe,CAAC,IAAI,CAClB,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CACvE,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACxC,mGAAmG;gBACnG,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC1D,eAAe,CAAC,IAAI,CAClB,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,eAAe,IAAI,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAC9E,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,mDAAmD;gBACnD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAClB,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAC3E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,KAAK,MAAM,WAAW,IAAI,eAAe,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAEjD,MAAM,aAAa,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;gBACjC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;iBAAM,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;gBACnC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC;YACnD,CAAC;YACD,qEAAqE;QACvE,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,cAAc,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;gBAC7B,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,SAAS,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,OAAO,SAAS,CAAC,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,OAA0B;IACvE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,gCAAgC,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,6DAA6D,GAAG,QAAQ,CAAC,CAAC;QAC5F,CAAC;QACD,IAAI,KAAK,GAAG,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClF,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7B,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,GAAG,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,cAAc,CACrB,SAAiB,EACjB,cAA8D,EAC9D,UAA6B,EAAE;IAE/B,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,aAAa,GAAG,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,aAAa,IAAI,KAAK,CAAC,CAAC;QAC1F,IAAI,KAAK,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,CAAC,aAAa,EAAE,CAAC;YAC/C,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,KAAyB,EACzB,WAAmB,EACnB,YAAoB;IAEpB,OAAO,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;AAC5F,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n // the route could be\n // 1. a path: \"container123/blob456\"\n // 2. a component string from template which starts with \"?\" and may contain more \"?\" after template is expanded,\n // e.g., \"?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27\"\n const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);\n\n const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);\n const url = new URL(requestUrl);\n\n return url.toString();\n}\n\nfunction appendPath(endpoint: string, pathToAppend: string): string {\n const endpointSearchStart = endpoint.indexOf(\"?\");\n const pathSearchStart = pathToAppend.indexOf(\"?\");\n const endpointParts =\n endpointSearchStart !== -1\n ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]\n : [endpoint, \"\"];\n const pathParts =\n pathSearchStart !== -1\n ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]\n : [pathToAppend, \"\"];\n\n const combinedSearch = [endpointParts[1], pathParts[1].replaceAll(\"?\", \"&\")]\n .filter(Boolean)\n .join(\"&\");\n const baseEndpoint = endpointParts[0];\n const basePathToAppend = pathParts[0];\n\n let combinedUrl = baseEndpoint;\n if (!baseEndpoint.endsWith(\"/\") && !basePathToAppend.startsWith(\"/\") && basePathToAppend !== \"\") {\n combinedUrl += `/${basePathToAppend}`;\n } else if (baseEndpoint.endsWith(\"/\") && basePathToAppend.startsWith(\"/\")) {\n combinedUrl += basePathToAppend.substring(1);\n } else {\n combinedUrl += basePathToAppend;\n }\n\n if (combinedSearch) {\n combinedUrl += `?${combinedSearch}`;\n }\n\n return combinedUrl;\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\n/**\n * Parses a query string into a map of key/value pairs without decoding the values.\n * This avoids the issue where `URL.searchParams` would decode values, potentially\n * corrupting already-encoded values such as SAS signatures.\n */\nfunction simpleParseQueryParams(queryString: string): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n if (!queryString || queryString[0] !== \"?\") {\n return result;\n }\n\n // remove the leading ?\n queryString = queryString.slice(1);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);\n const value = eqIndex === -1 ? \"\" : pair.substring(eqIndex + 1);\n\n const existingValue = result.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n } else {\n result.set(name, [existingValue, value]);\n }\n } else {\n result.set(name, value);\n }\n }\n\n return result;\n}\n\n/** @internal */\nexport function appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n // Parse existing query params from the URL manually to avoid re-encoding issues\n const existingParams = simpleParseQueryParams(parsedUrl.search);\n\n const newParamStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item),\n );\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n newParamStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue),\n );\n }\n }\n\n // Merge new params into existing params, deduplicating values for the same key\n for (const paramString of newParamStrings) {\n const eqIndex = paramString.indexOf(\"=\");\n const name = paramString.substring(0, eqIndex);\n const value = paramString.substring(eqIndex + 1);\n\n const existingValue = existingParams.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n if (!existingValue.includes(value)) {\n existingValue.push(value);\n }\n } else if (existingValue !== value) {\n existingParams.set(name, [existingValue, value]);\n }\n // if existingValue === value (single string match), no change needed\n } else {\n existingParams.set(name, value);\n }\n }\n\n // Reconstruct the search string manually to avoid URL re-encoding\n const searchPieces: string[] = [];\n for (const [name, value] of existingParams) {\n if (Array.isArray(value)) {\n for (const subValue of value) {\n searchPieces.push(`${name}=${subValue}`);\n }\n } else {\n searchPieces.push(`${name}=${value}`);\n }\n }\n\n parsedUrl.search = searchPieces.length ? `?${searchPieces.join(\"&\")}` : \"\";\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
@@ -8,6 +8,8 @@ import type { PathParameterWithOptions, RequestParameters } from "./common.js";
8
8
  * @returns a full url with path and query parameters
9
9
  */
10
10
  export declare function buildRequestUrl(endpoint: string, routePath: string, pathParameters: (string | number | PathParameterWithOptions)[], options?: RequestParameters): string;
11
+ /** @internal */
12
+ export declare function appendQueryParams(url: string, options?: RequestParameters): string;
11
13
  export declare function buildBaseUrl(endpoint: string, options: RequestParameters): string;
12
14
  /**
13
15
  * Replace all of the instances of searchValue in value with the provided replaceValue.
@@ -17,13 +17,43 @@ export function buildRequestUrl(endpoint, routePath, pathParameters, options = {
17
17
  return routePath;
18
18
  }
19
19
  endpoint = buildBaseUrl(endpoint, options);
20
- routePath = buildRoutePath(routePath, pathParameters, options);
21
- const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);
20
+ // the route could be
21
+ // 1. a path: "container123/blob456"
22
+ // 2. a component string from template which starts with "?" and may contain more "?" after template is expanded,
23
+ // e.g., "?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27"
24
+ const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);
25
+ const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);
22
26
  const url = new URL(requestUrl);
23
- return (url
24
- .toString()
25
- // Remove double forward slashes
26
- .replace(/([^:]\/)\/+/g, "$1"));
27
+ return url.toString();
28
+ }
29
+ function appendPath(endpoint, pathToAppend) {
30
+ const endpointSearchStart = endpoint.indexOf("?");
31
+ const pathSearchStart = pathToAppend.indexOf("?");
32
+ const endpointParts = endpointSearchStart !== -1
33
+ ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]
34
+ : [endpoint, ""];
35
+ const pathParts = pathSearchStart !== -1
36
+ ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]
37
+ : [pathToAppend, ""];
38
+ const combinedSearch = [endpointParts[1], pathParts[1].replaceAll("?", "&")]
39
+ .filter(Boolean)
40
+ .join("&");
41
+ const baseEndpoint = endpointParts[0];
42
+ const basePathToAppend = pathParts[0];
43
+ let combinedUrl = baseEndpoint;
44
+ if (!baseEndpoint.endsWith("/") && !basePathToAppend.startsWith("/") && basePathToAppend !== "") {
45
+ combinedUrl += `/${basePathToAppend}`;
46
+ }
47
+ else if (baseEndpoint.endsWith("/") && basePathToAppend.startsWith("/")) {
48
+ combinedUrl += basePathToAppend.substring(1);
49
+ }
50
+ else {
51
+ combinedUrl += basePathToAppend;
52
+ }
53
+ if (combinedSearch) {
54
+ combinedUrl += `?${combinedSearch}`;
55
+ }
56
+ return combinedUrl;
27
57
  }
28
58
  function getQueryParamValue(key, allowReserved, style, param) {
29
59
  let separator;
@@ -62,13 +92,48 @@ function getQueryParamValue(key, allowReserved, style, param) {
62
92
  .join(separator);
63
93
  return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;
64
94
  }
65
- function appendQueryParams(url, options = {}) {
95
+ /**
96
+ * Parses a query string into a map of key/value pairs without decoding the values.
97
+ * This avoids the issue where `URL.searchParams` would decode values, potentially
98
+ * corrupting already-encoded values such as SAS signatures.
99
+ */
100
+ function simpleParseQueryParams(queryString) {
101
+ const result = new Map();
102
+ if (!queryString || queryString[0] !== "?") {
103
+ return result;
104
+ }
105
+ // remove the leading ?
106
+ queryString = queryString.slice(1);
107
+ const pairs = queryString.split("&");
108
+ for (const pair of pairs) {
109
+ const eqIndex = pair.indexOf("=");
110
+ const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);
111
+ const value = eqIndex === -1 ? "" : pair.substring(eqIndex + 1);
112
+ const existingValue = result.get(name);
113
+ if (existingValue !== undefined) {
114
+ if (Array.isArray(existingValue)) {
115
+ existingValue.push(value);
116
+ }
117
+ else {
118
+ result.set(name, [existingValue, value]);
119
+ }
120
+ }
121
+ else {
122
+ result.set(name, value);
123
+ }
124
+ }
125
+ return result;
126
+ }
127
+ /** @internal */
128
+ export function appendQueryParams(url, options = {}) {
66
129
  if (!options.queryParameters) {
67
130
  return url;
68
131
  }
69
132
  const parsedUrl = new URL(url);
70
133
  const queryParams = options.queryParameters;
71
- const paramStrings = [];
134
+ // Parse existing query params from the URL manually to avoid re-encoding issues
135
+ const existingParams = simpleParseQueryParams(parsedUrl.search);
136
+ const newParamStrings = [];
72
137
  for (const key of Object.keys(queryParams)) {
73
138
  const param = queryParams[key];
74
139
  if (param === undefined || param === null) {
@@ -81,13 +146,13 @@ function appendQueryParams(url, options = {}) {
81
146
  if (explode) {
82
147
  if (Array.isArray(rawValue)) {
83
148
  for (const item of rawValue) {
84
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
149
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));
85
150
  }
86
151
  }
87
152
  else if (typeof rawValue === "object") {
88
153
  // For object explode, the name of the query parameter is ignored and we use the object key instead
89
154
  for (const [actualKey, value] of Object.entries(rawValue)) {
90
- paramStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
155
+ newParamStrings.push(getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value));
91
156
  }
92
157
  }
93
158
  else {
@@ -96,13 +161,43 @@ function appendQueryParams(url, options = {}) {
96
161
  }
97
162
  }
98
163
  else {
99
- paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
164
+ newParamStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));
165
+ }
166
+ }
167
+ // Merge new params into existing params, deduplicating values for the same key
168
+ for (const paramString of newParamStrings) {
169
+ const eqIndex = paramString.indexOf("=");
170
+ const name = paramString.substring(0, eqIndex);
171
+ const value = paramString.substring(eqIndex + 1);
172
+ const existingValue = existingParams.get(name);
173
+ if (existingValue !== undefined) {
174
+ if (Array.isArray(existingValue)) {
175
+ if (!existingValue.includes(value)) {
176
+ existingValue.push(value);
177
+ }
178
+ }
179
+ else if (existingValue !== value) {
180
+ existingParams.set(name, [existingValue, value]);
181
+ }
182
+ // if existingValue === value (single string match), no change needed
183
+ }
184
+ else {
185
+ existingParams.set(name, value);
100
186
  }
101
187
  }
102
- if (parsedUrl.search !== "") {
103
- parsedUrl.search += "&";
188
+ // Reconstruct the search string manually to avoid URL re-encoding
189
+ const searchPieces = [];
190
+ for (const [name, value] of existingParams) {
191
+ if (Array.isArray(value)) {
192
+ for (const subValue of value) {
193
+ searchPieces.push(`${name}=${subValue}`);
194
+ }
195
+ }
196
+ else {
197
+ searchPieces.push(`${name}=${value}`);
198
+ }
104
199
  }
105
- parsedUrl.search += paramStrings.join("&");
200
+ parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : "";
106
201
  return parsedUrl.toString();
107
202
  }
108
203
  export function buildBaseUrl(endpoint, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n routePath = buildRoutePath(routePath, pathParameters, options);\n const requestUrl = appendQueryParams(`${endpoint}/${routePath}`, options);\n const url = new URL(requestUrl);\n\n return (\n url\n .toString()\n // Remove double forward slashes\n .replace(/([^:]\\/)\\/+/g, \"$1\")\n );\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\nfunction appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n const paramStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item));\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n paramStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n paramStrings.push(getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue));\n }\n }\n\n if (parsedUrl.search !== \"\") {\n parsedUrl.search += \"&\";\n }\n parsedUrl.search += paramStrings.join(\"&\");\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
1
+ {"version":3,"file":"urlHelpers.js","sourceRoot":"","sources":["../../../src/client/urlHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { PathParameterWithOptions, RequestParameters } from \"./common.js\";\n\ntype QueryParameterStyle = \"form\" | \"spaceDelimited\" | \"pipeDelimited\";\n\n/**\n * An object that can be passed as a query parameter, allowing for additional options to be set relating to how the parameter is encoded.\n */\ninterface QueryParameterWithOptions {\n /**\n * The value of the query parameter.\n */\n value: unknown;\n\n /**\n * If set to true, value must be an array. Setting this option to true will cause the array to be encoded as multiple query parameters.\n * Setting it to false will cause the array values to be encoded as a single query parameter, with each value separated by a comma ','.\n *\n * For example, with `explode` set to true, a query parameter named \"foo\" with value [\"a\", \"b\", \"c\"] will be encoded as foo=a&foo=b&foo=c.\n * If `explode` was set to false, the same example would instead be encouded as foo=a,b,c.\n *\n * Defaults to false.\n */\n explode?: boolean;\n\n /**\n * Style for encoding arrays. Three possible values:\n * - \"form\": array values will be separated by a comma \",\" in the query parameter value.\n * - \"spaceDelimited\": array values will be separated by a space (\" \", url-encoded to \"%20\").\n * - \"pipeDelimited\": array values will be separated by a pipe (\"|\").\n *\n * Defaults to \"form\".\n */\n style?: QueryParameterStyle;\n}\n\nfunction isQueryParameterWithOptions(x: unknown): x is QueryParameterWithOptions {\n const value = (x as QueryParameterWithOptions).value as any;\n return (\n value !== undefined && value.toString !== undefined && typeof value.toString === \"function\"\n );\n}\n\n/**\n * Builds the request url, filling in query and path parameters\n * @param endpoint - base url which can be a template url\n * @param routePath - path to append to the endpoint\n * @param pathParameters - values of the path parameters\n * @param options - request parameters including query parameters\n * @returns a full url with path and query parameters\n */\nexport function buildRequestUrl(\n endpoint: string,\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n if (routePath.startsWith(\"https://\") || routePath.startsWith(\"http://\")) {\n return routePath;\n }\n endpoint = buildBaseUrl(endpoint, options);\n // the route could be\n // 1. a path: \"container123/blob456\"\n // 2. a component string from template which starts with \"?\" and may contain more \"?\" after template is expanded,\n // e.g., \"?restype=container&comp=blobs?where=key177196556777405927%3D%27val1177196556777407626%27\"\n const updatedRoutePath = buildRoutePath(routePath, pathParameters, options);\n\n const requestUrl = appendQueryParams(appendPath(endpoint, updatedRoutePath), options);\n const url = new URL(requestUrl);\n\n return url.toString();\n}\n\nfunction appendPath(endpoint: string, pathToAppend: string): string {\n const endpointSearchStart = endpoint.indexOf(\"?\");\n const pathSearchStart = pathToAppend.indexOf(\"?\");\n const endpointParts =\n endpointSearchStart !== -1\n ? [endpoint.substring(0, endpointSearchStart), endpoint.substring(endpointSearchStart + 1)]\n : [endpoint, \"\"];\n const pathParts =\n pathSearchStart !== -1\n ? [pathToAppend.substring(0, pathSearchStart), pathToAppend.substring(pathSearchStart + 1)]\n : [pathToAppend, \"\"];\n\n const combinedSearch = [endpointParts[1], pathParts[1].replaceAll(\"?\", \"&\")]\n .filter(Boolean)\n .join(\"&\");\n const baseEndpoint = endpointParts[0];\n const basePathToAppend = pathParts[0];\n\n let combinedUrl = baseEndpoint;\n if (!baseEndpoint.endsWith(\"/\") && !basePathToAppend.startsWith(\"/\") && basePathToAppend !== \"\") {\n combinedUrl += `/${basePathToAppend}`;\n } else if (baseEndpoint.endsWith(\"/\") && basePathToAppend.startsWith(\"/\")) {\n combinedUrl += basePathToAppend.substring(1);\n } else {\n combinedUrl += basePathToAppend;\n }\n\n if (combinedSearch) {\n combinedUrl += `?${combinedSearch}`;\n }\n\n return combinedUrl;\n}\n\nfunction getQueryParamValue(\n key: string,\n allowReserved: boolean,\n style: QueryParameterStyle,\n param: any,\n): string {\n let separator: string;\n if (style === \"pipeDelimited\") {\n separator = \"|\";\n } else if (style === \"spaceDelimited\") {\n separator = \"%20\";\n } else {\n separator = \",\";\n }\n\n let paramValues: any[];\n if (Array.isArray(param)) {\n paramValues = param;\n } else if (typeof param === \"object\" && param.toString === Object.prototype.toString) {\n // If the parameter is an object without a custom toString implementation (e.g. a Date),\n // then we should deconstruct the object into an array [key1, value1, key2, value2, ...].\n paramValues = Object.entries(param).flat();\n } else {\n paramValues = [param];\n }\n\n const value = paramValues\n .map((p) => {\n if (p === null || p === undefined) {\n return \"\";\n }\n\n if (!p.toString || typeof p.toString !== \"function\") {\n throw new Error(`Query parameters must be able to be represented as string, ${key} can't`);\n }\n\n const rawValue = p.toISOString !== undefined ? p.toISOString() : p.toString();\n return allowReserved ? rawValue : encodeURIComponent(rawValue);\n })\n .join(separator);\n\n return `${allowReserved ? key : encodeURIComponent(key)}=${value}`;\n}\n\n/**\n * Parses a query string into a map of key/value pairs without decoding the values.\n * This avoids the issue where `URL.searchParams` would decode values, potentially\n * corrupting already-encoded values such as SAS signatures.\n */\nfunction simpleParseQueryParams(queryString: string): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n if (!queryString || queryString[0] !== \"?\") {\n return result;\n }\n\n // remove the leading ?\n queryString = queryString.slice(1);\n const pairs = queryString.split(\"&\");\n\n for (const pair of pairs) {\n const eqIndex = pair.indexOf(\"=\");\n const name = eqIndex === -1 ? pair : pair.substring(0, eqIndex);\n const value = eqIndex === -1 ? \"\" : pair.substring(eqIndex + 1);\n\n const existingValue = result.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n } else {\n result.set(name, [existingValue, value]);\n }\n } else {\n result.set(name, value);\n }\n }\n\n return result;\n}\n\n/** @internal */\nexport function appendQueryParams(url: string, options: RequestParameters = {}): string {\n if (!options.queryParameters) {\n return url;\n }\n const parsedUrl = new URL(url);\n const queryParams = options.queryParameters;\n\n // Parse existing query params from the URL manually to avoid re-encoding issues\n const existingParams = simpleParseQueryParams(parsedUrl.search);\n\n const newParamStrings: string[] = [];\n for (const key of Object.keys(queryParams)) {\n const param = queryParams[key] as any;\n if (param === undefined || param === null) {\n continue;\n }\n\n const hasMetadata = isQueryParameterWithOptions(param);\n const rawValue = hasMetadata ? param.value : param;\n const explode = hasMetadata ? (param.explode ?? false) : false;\n const style = hasMetadata && param.style ? param.style : \"form\";\n\n if (explode) {\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, item),\n );\n }\n } else if (typeof rawValue === \"object\") {\n // For object explode, the name of the query parameter is ignored and we use the object key instead\n for (const [actualKey, value] of Object.entries(rawValue)) {\n newParamStrings.push(\n getQueryParamValue(actualKey, options.skipUrlEncoding ?? false, style, value),\n );\n }\n } else {\n // Explode doesn't really make sense for primitives\n throw new Error(\"explode can only be set to true for objects and arrays\");\n }\n } else {\n newParamStrings.push(\n getQueryParamValue(key, options.skipUrlEncoding ?? false, style, rawValue),\n );\n }\n }\n\n // Merge new params into existing params, deduplicating values for the same key\n for (const paramString of newParamStrings) {\n const eqIndex = paramString.indexOf(\"=\");\n const name = paramString.substring(0, eqIndex);\n const value = paramString.substring(eqIndex + 1);\n\n const existingValue = existingParams.get(name);\n if (existingValue !== undefined) {\n if (Array.isArray(existingValue)) {\n if (!existingValue.includes(value)) {\n existingValue.push(value);\n }\n } else if (existingValue !== value) {\n existingParams.set(name, [existingValue, value]);\n }\n // if existingValue === value (single string match), no change needed\n } else {\n existingParams.set(name, value);\n }\n }\n\n // Reconstruct the search string manually to avoid URL re-encoding\n const searchPieces: string[] = [];\n for (const [name, value] of existingParams) {\n if (Array.isArray(value)) {\n for (const subValue of value) {\n searchPieces.push(`${name}=${subValue}`);\n }\n } else {\n searchPieces.push(`${name}=${value}`);\n }\n }\n\n parsedUrl.search = searchPieces.length ? `?${searchPieces.join(\"&\")}` : \"\";\n return parsedUrl.toString();\n}\n\nexport function buildBaseUrl(endpoint: string, options: RequestParameters): string {\n if (!options.pathParameters) {\n return endpoint;\n }\n const pathParams = options.pathParameters;\n for (const [key, param] of Object.entries(pathParams)) {\n if (param === undefined || param === null) {\n throw new Error(`Path parameters ${key} must not be undefined or null`);\n }\n if (!param.toString || typeof param.toString !== \"function\") {\n throw new Error(`Path parameters must be able to be represented as string, ${key} can't`);\n }\n let value = param.toISOString !== undefined ? param.toISOString() : String(param);\n if (!options.skipUrlEncoding) {\n value = encodeURIComponent(param);\n }\n endpoint = replaceAll(endpoint, `{${key}}`, value) ?? \"\";\n }\n return endpoint;\n}\n\nfunction buildRoutePath(\n routePath: string,\n pathParameters: (string | number | PathParameterWithOptions)[],\n options: RequestParameters = {},\n): string {\n for (const pathParam of pathParameters) {\n const allowReserved = typeof pathParam === \"object\" && (pathParam.allowReserved ?? false);\n let value = typeof pathParam === \"object\" ? pathParam.value : pathParam;\n\n if (!options.skipUrlEncoding && !allowReserved) {\n value = encodeURIComponent(value);\n }\n\n routePath = routePath.replace(/\\{[\\w-]+\\}/, String(value));\n }\n return routePath;\n}\n\n/**\n * Replace all of the instances of searchValue in value with the provided replaceValue.\n * @param value - The value to search and replace in.\n * @param searchValue - The value to search for in the value argument.\n * @param replaceValue - The value to replace searchValue with in the value argument.\n * @returns The value where each instance of searchValue was replaced with replacedValue.\n */\nexport function replaceAll(\n value: string | undefined,\n searchValue: string,\n replaceValue: string,\n): string | undefined {\n return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || \"\");\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/ts-http-runtime",
3
- "version": "0.3.5-alpha.20260306.4",
3
+ "version": "0.3.5-alpha.20260310.2",
4
4
  "description": "Isomorphic client library for making HTTP requests in node.js and browser.",
5
5
  "sdk-type": "client",
6
6
  "type": "module",
@@ -139,9 +139,9 @@
139
139
  "tsx": "^4.20.4",
140
140
  "typescript": "~5.9.3",
141
141
  "vitest": "^4.0.8",
142
- "@azure-tools/vite-plugin-browser-test-map": "^1.0.0",
143
142
  "@azure/dev-tool": "^1.0.0",
144
- "@azure/eslint-plugin-azure-sdk": "^3.0.0"
143
+ "@azure/eslint-plugin-azure-sdk": "^3.0.0",
144
+ "@azure-tools/vite-plugin-browser-test-map": "^1.0.0"
145
145
  },
146
146
  "module": "./dist/esm/index.js",
147
147
  "scripts": {