@itwin/core-frontend 5.16.0-dev.4 → 5.16.0-dev.6

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.
Files changed (134) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/lib/cjs/core-frontend.d.ts +1 -1
  3. package/lib/cjs/core-frontend.d.ts.map +1 -1
  4. package/lib/cjs/core-frontend.js +3 -2
  5. package/lib/cjs/core-frontend.js.map +1 -1
  6. package/lib/cjs/internal/cross-package.d.ts +1 -1
  7. package/lib/cjs/internal/cross-package.d.ts.map +1 -1
  8. package/lib/cjs/internal/cross-package.js +4 -1
  9. package/lib/cjs/internal/cross-package.js.map +1 -1
  10. package/lib/cjs/internal/tile/map/ArcGisUtilities.d.ts +15 -2
  11. package/lib/cjs/internal/tile/map/ArcGisUtilities.d.ts.map +1 -1
  12. package/lib/cjs/internal/tile/map/ArcGisUtilities.js +54 -29
  13. package/lib/cjs/internal/tile/map/ArcGisUtilities.js.map +1 -1
  14. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISImageryProvider.d.ts +14 -0
  15. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISImageryProvider.d.ts.map +1 -1
  16. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISImageryProvider.js +91 -45
  17. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISImageryProvider.js.map +1 -1
  18. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.d.ts.map +1 -1
  19. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.js +5 -4
  20. package/lib/cjs/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.js.map +1 -1
  21. package/lib/cjs/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.d.ts.map +1 -1
  22. package/lib/cjs/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.js +8 -2
  23. package/lib/cjs/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.js.map +1 -1
  24. package/lib/cjs/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.d.ts.map +1 -1
  25. package/lib/cjs/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.js +8 -2
  26. package/lib/cjs/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.js.map +1 -1
  27. package/lib/cjs/internal/tile/map/MapLayerFetch.d.ts +57 -0
  28. package/lib/cjs/internal/tile/map/MapLayerFetch.d.ts.map +1 -0
  29. package/lib/cjs/internal/tile/map/MapLayerFetch.js +95 -0
  30. package/lib/cjs/internal/tile/map/MapLayerFetch.js.map +1 -0
  31. package/lib/cjs/internal/tile/map/UrlUtils.js +1 -1
  32. package/lib/cjs/internal/tile/map/UrlUtils.js.map +1 -1
  33. package/lib/cjs/internal/tile/map/WmsCapabilities.d.ts +2 -5
  34. package/lib/cjs/internal/tile/map/WmsCapabilities.d.ts.map +1 -1
  35. package/lib/cjs/internal/tile/map/WmsCapabilities.js +16 -9
  36. package/lib/cjs/internal/tile/map/WmsCapabilities.js.map +1 -1
  37. package/lib/cjs/internal/tile/map/WmsUtilities.d.ts +29 -1
  38. package/lib/cjs/internal/tile/map/WmsUtilities.d.ts.map +1 -1
  39. package/lib/cjs/internal/tile/map/WmsUtilities.js +43 -11
  40. package/lib/cjs/internal/tile/map/WmsUtilities.js.map +1 -1
  41. package/lib/cjs/internal/tile/map/WmtsCapabilities.d.ts +2 -5
  42. package/lib/cjs/internal/tile/map/WmtsCapabilities.d.ts.map +1 -1
  43. package/lib/cjs/internal/tile/map/WmtsCapabilities.js +16 -9
  44. package/lib/cjs/internal/tile/map/WmtsCapabilities.js.map +1 -1
  45. package/lib/cjs/tile/internal.d.ts +2 -0
  46. package/lib/cjs/tile/internal.d.ts.map +1 -1
  47. package/lib/cjs/tile/internal.js +2 -0
  48. package/lib/cjs/tile/internal.js.map +1 -1
  49. package/lib/cjs/tile/map/MapLayerFetchHandler.d.ts +94 -0
  50. package/lib/cjs/tile/map/MapLayerFetchHandler.d.ts.map +1 -0
  51. package/lib/cjs/tile/map/MapLayerFetchHandler.js +10 -0
  52. package/lib/cjs/tile/map/MapLayerFetchHandler.js.map +1 -0
  53. package/lib/cjs/tile/map/MapLayerFormatRegistry.d.ts +27 -1
  54. package/lib/cjs/tile/map/MapLayerFormatRegistry.d.ts.map +1 -1
  55. package/lib/cjs/tile/map/MapLayerFormatRegistry.js +42 -1
  56. package/lib/cjs/tile/map/MapLayerFormatRegistry.js.map +1 -1
  57. package/lib/cjs/tile/map/MapLayerImageryFormats.d.ts.map +1 -1
  58. package/lib/cjs/tile/map/MapLayerImageryFormats.js +20 -4
  59. package/lib/cjs/tile/map/MapLayerImageryFormats.js.map +1 -1
  60. package/lib/cjs/tile/map/MapLayerImageryProvider.d.ts +28 -16
  61. package/lib/cjs/tile/map/MapLayerImageryProvider.d.ts.map +1 -1
  62. package/lib/cjs/tile/map/MapLayerImageryProvider.js +134 -66
  63. package/lib/cjs/tile/map/MapLayerImageryProvider.js.map +1 -1
  64. package/lib/cjs/tile/map/MapLayerSources.d.ts +19 -4
  65. package/lib/cjs/tile/map/MapLayerSources.d.ts.map +1 -1
  66. package/lib/cjs/tile/map/MapLayerSources.js +28 -11
  67. package/lib/cjs/tile/map/MapLayerSources.js.map +1 -1
  68. package/lib/esm/core-frontend.d.ts +1 -1
  69. package/lib/esm/core-frontend.d.ts.map +1 -1
  70. package/lib/esm/core-frontend.js +1 -1
  71. package/lib/esm/core-frontend.js.map +1 -1
  72. package/lib/esm/internal/cross-package.d.ts +1 -1
  73. package/lib/esm/internal/cross-package.d.ts.map +1 -1
  74. package/lib/esm/internal/cross-package.js +1 -1
  75. package/lib/esm/internal/cross-package.js.map +1 -1
  76. package/lib/esm/internal/tile/map/ArcGisUtilities.d.ts +15 -2
  77. package/lib/esm/internal/tile/map/ArcGisUtilities.d.ts.map +1 -1
  78. package/lib/esm/internal/tile/map/ArcGisUtilities.js +55 -30
  79. package/lib/esm/internal/tile/map/ArcGisUtilities.js.map +1 -1
  80. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISImageryProvider.d.ts +14 -0
  81. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISImageryProvider.d.ts.map +1 -1
  82. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISImageryProvider.js +92 -46
  83. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISImageryProvider.js.map +1 -1
  84. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.d.ts.map +1 -1
  85. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.js +5 -4
  86. package/lib/esm/internal/tile/map/ImageryProviders/ArcGISMapLayerImageryProvider.js.map +1 -1
  87. package/lib/esm/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.d.ts.map +1 -1
  88. package/lib/esm/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.js +9 -3
  89. package/lib/esm/internal/tile/map/ImageryProviders/WmsMapLayerImageryProvider.js.map +1 -1
  90. package/lib/esm/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.d.ts.map +1 -1
  91. package/lib/esm/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.js +9 -3
  92. package/lib/esm/internal/tile/map/ImageryProviders/WmtsMapLayerImageryProvider.js.map +1 -1
  93. package/lib/esm/internal/tile/map/MapLayerFetch.d.ts +57 -0
  94. package/lib/esm/internal/tile/map/MapLayerFetch.d.ts.map +1 -0
  95. package/lib/esm/internal/tile/map/MapLayerFetch.js +91 -0
  96. package/lib/esm/internal/tile/map/MapLayerFetch.js.map +1 -0
  97. package/lib/esm/internal/tile/map/UrlUtils.js +1 -1
  98. package/lib/esm/internal/tile/map/UrlUtils.js.map +1 -1
  99. package/lib/esm/internal/tile/map/WmsCapabilities.d.ts +2 -5
  100. package/lib/esm/internal/tile/map/WmsCapabilities.d.ts.map +1 -1
  101. package/lib/esm/internal/tile/map/WmsCapabilities.js +16 -9
  102. package/lib/esm/internal/tile/map/WmsCapabilities.js.map +1 -1
  103. package/lib/esm/internal/tile/map/WmsUtilities.d.ts +29 -1
  104. package/lib/esm/internal/tile/map/WmsUtilities.d.ts.map +1 -1
  105. package/lib/esm/internal/tile/map/WmsUtilities.js +44 -12
  106. package/lib/esm/internal/tile/map/WmsUtilities.js.map +1 -1
  107. package/lib/esm/internal/tile/map/WmtsCapabilities.d.ts +2 -5
  108. package/lib/esm/internal/tile/map/WmtsCapabilities.d.ts.map +1 -1
  109. package/lib/esm/internal/tile/map/WmtsCapabilities.js +16 -9
  110. package/lib/esm/internal/tile/map/WmtsCapabilities.js.map +1 -1
  111. package/lib/esm/tile/internal.d.ts +2 -0
  112. package/lib/esm/tile/internal.d.ts.map +1 -1
  113. package/lib/esm/tile/internal.js +2 -0
  114. package/lib/esm/tile/internal.js.map +1 -1
  115. package/lib/esm/tile/map/MapLayerFetchHandler.d.ts +94 -0
  116. package/lib/esm/tile/map/MapLayerFetchHandler.d.ts.map +1 -0
  117. package/lib/esm/tile/map/MapLayerFetchHandler.js +9 -0
  118. package/lib/esm/tile/map/MapLayerFetchHandler.js.map +1 -0
  119. package/lib/esm/tile/map/MapLayerFormatRegistry.d.ts +27 -1
  120. package/lib/esm/tile/map/MapLayerFormatRegistry.d.ts.map +1 -1
  121. package/lib/esm/tile/map/MapLayerFormatRegistry.js +40 -0
  122. package/lib/esm/tile/map/MapLayerFormatRegistry.js.map +1 -1
  123. package/lib/esm/tile/map/MapLayerImageryFormats.d.ts.map +1 -1
  124. package/lib/esm/tile/map/MapLayerImageryFormats.js +21 -5
  125. package/lib/esm/tile/map/MapLayerImageryFormats.js.map +1 -1
  126. package/lib/esm/tile/map/MapLayerImageryProvider.d.ts +28 -16
  127. package/lib/esm/tile/map/MapLayerImageryProvider.d.ts.map +1 -1
  128. package/lib/esm/tile/map/MapLayerImageryProvider.js +136 -68
  129. package/lib/esm/tile/map/MapLayerImageryProvider.js.map +1 -1
  130. package/lib/esm/tile/map/MapLayerSources.d.ts +19 -4
  131. package/lib/esm/tile/map/MapLayerSources.d.ts.map +1 -1
  132. package/lib/esm/tile/map/MapLayerSources.js +28 -11
  133. package/lib/esm/tile/map/MapLayerSources.js.map +1 -1
  134. package/package.json +21 -21
@@ -3,7 +3,7 @@
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import { Angle, Constant } from "@itwin/core-geometry";
6
- import { MapCartoRectangle, MapLayerSource, MapLayerSourceStatus, MapLayerUntrustedOriginError } from "../../../tile/internal";
6
+ import { credentialedFetchRedirect, fetchMapLayerRequest, MapCartoRectangle, MapLayerAuthenticationFailedError, MapLayerSource, MapLayerSourceStatus, MapLayerUntrustedOriginError } from "../../../tile/internal";
7
7
  import { IModelApp } from "../../../IModelApp";
8
8
  import { headersIncludeAuthMethod } from "../../../request/utils";
9
9
  /** @packageDocumentation
@@ -146,6 +146,8 @@ export class ArcGisUtilities {
146
146
  metadata = await this.getServiceJson({ url: source.url, formatId: source.formatId, userName: source.userName, password: source.password, queryParams: source.collectQueryParams(), ignoreCache });
147
147
  }
148
148
  catch (err) {
149
+ if (err instanceof MapLayerAuthenticationFailedError)
150
+ return { status: MapLayerSourceStatus.RequireAuth };
149
151
  if (err instanceof MapLayerUntrustedOriginError) {
150
152
  let blockedOrigin;
151
153
  try {
@@ -160,16 +162,17 @@ export class ArcGisUtilities {
160
162
  if (json === undefined) {
161
163
  return { status: MapLayerSourceStatus.InvalidUrl };
162
164
  }
163
- else if (json.error !== undefined) {
165
+ const errorCode = metadata?.errorCode;
166
+ if (errorCode !== undefined) {
164
167
  // If we got a 'Token Required' error, lets check what authentification methods this ESRI service offers
165
168
  // and return information needed to initiate the authentification process... the end-user
166
169
  // will have to provide his credentials before we can fully validate this source.
167
170
  // Note: Some servers will throw a error 403 (You do not have permissions to access this resource or perform this operation),
168
171
  // instead of 499 (TokenRequired)
169
- if (json.error.code === ArcGisErrorCode.TokenRequired || json.error.code === ArcGisErrorCode.MissingPermissions) {
172
+ if (errorCode === ArcGisErrorCode.TokenRequired || errorCode === ArcGisErrorCode.MissingPermissions) {
170
173
  return (source.userName || source.password) ? { status: MapLayerSourceStatus.InvalidCredentials } : { status: MapLayerSourceStatus.RequireAuth };
171
174
  }
172
- else if (json.error.code === ArcGisErrorCode.InvalidCredentials)
175
+ else if (errorCode === ArcGisErrorCode.InvalidCredentials)
173
176
  return { status: MapLayerSourceStatus.InvalidCredentials };
174
177
  }
175
178
  // Check this service support the expected queries
@@ -220,11 +223,17 @@ export class ArcGisUtilities {
220
223
  * @param requireToken Flag to indicate if a token is required
221
224
  * @throws [[MapLayerUntrustedOriginError]] if an NTLM/Negotiate challenge could not be answered because
222
225
  * the URL's origin is not trusted (see [[MapLayerFormatRegistry.restrictCredentialsToTrustedOrigins]]);
226
+ * [[MapLayerAuthenticationFailedError]] if a registered [[MapLayerFetchHandler]] reported an
227
+ * authentication failure;
223
228
  * all other errors are caught and reported by returning `undefined`.
224
229
  */
225
230
  static async getServiceJson(args) {
226
- const { url, formatId, userName, password, queryParams, ignoreCache, requireToken } = args;
227
- if (!ignoreCache) {
231
+ const { url, layerUrl = url, layerProperties, formatId, userName, password, queryParams, ignoreCache, requireToken } = args;
232
+ const accessClient = IModelApp.mapLayerFormatRegistry?.getAccessClient(formatId);
233
+ // The cache is keyed by URL only, so responses customized by the fetch handler (e.g.
234
+ // header-authenticated) must not be shared with or served from differently-customized requests.
235
+ const hasFetchHandler = (IModelApp.mapLayerFormatRegistry?.mapLayerFetchHandlers.length ?? 0) > 0;
236
+ if (!ignoreCache && !hasFetchHandler) {
228
237
  const cached = ArcGisUtilities._serviceCache.get(url);
229
238
  if (cached !== undefined)
230
239
  return cached;
@@ -243,55 +252,71 @@ export class ArcGisUtilities {
243
252
  appendParams(tmpUrl, queryParams);
244
253
  return tmpUrl;
245
254
  };
255
+ // Routes each request through the registered fetch handler (if any); handler failures propagate.
256
+ // The NTLM/SSO retry applies only to the initial request, and never to sends the handler modified.
257
+ const requestJson = async (target, allowSsoRetry) => {
258
+ return fetchMapLayerRequest({
259
+ url: target.toString(),
260
+ formatId,
261
+ layerUrl,
262
+ layerProperties,
263
+ send: async (request, credentialed) => {
264
+ // Sends the handler modified may carry injected secrets: same redirect policy as credentialed ones.
265
+ let rsp = await fetch(request.url, { method: "GET", headers: request.headers, redirect: credentialed ? credentialedFetchRedirect() : undefined });
266
+ if (allowSsoRetry && rsp.status === 401 && !requireToken && !credentialed && headersIncludeAuthMethod(rsp.headers, ["ntlm", "negotiate"])) {
267
+ // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.
268
+ const challengedUrl = rsp.url || request.url;
269
+ if (!IModelApp.mapLayerFormatRegistry.isSsoAllowed(challengedUrl))
270
+ throw new MapLayerUntrustedOriginError(challengedUrl);
271
+ IModelApp.mapLayerFormatRegistry.logUntrustedOriginUse(challengedUrl);
272
+ // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).
273
+ rsp = await fetch(challengedUrl, {
274
+ method: "GET",
275
+ credentials: "include",
276
+ redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? "error" : undefined,
277
+ });
278
+ }
279
+ return rsp;
280
+ },
281
+ });
282
+ };
246
283
  let accessTokenRequired = false;
247
284
  try {
248
285
  let tmpUrl = createUrlObj();
249
286
  // In some cases, caller might already know token is required, so append it immediately
250
287
  if (requireToken) {
251
- const accessClient = IModelApp.mapLayerFormatRegistry.getAccessClient(formatId);
252
288
  if (accessClient) {
253
289
  accessTokenRequired = true;
254
290
  await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, { mapLayerUrl: new URL(url), userName, password });
255
291
  }
256
292
  }
257
- let response = await fetch(tmpUrl, { method: "GET" });
258
- if (response.status === 401 && !requireToken && headersIncludeAuthMethod(response.headers, ["ntlm", "negotiate"])) {
259
- // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.
260
- const challengedUrl = response.url || tmpUrl.toString();
261
- if (!IModelApp.mapLayerFormatRegistry.isSsoAllowed(challengedUrl))
262
- throw new MapLayerUntrustedOriginError(challengedUrl);
263
- IModelApp.mapLayerFormatRegistry.logUntrustedOriginUse(challengedUrl);
264
- // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).
265
- response = await fetch(challengedUrl, {
266
- method: "GET",
267
- credentials: "include",
268
- redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? "error" : undefined,
269
- });
270
- }
293
+ let { response, managedByHandler } = await requestJson(tmpUrl, true);
271
294
  // Append security token when corresponding error code is returned by ArcGIS service
272
- let errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);
295
+ const errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);
273
296
  if (!accessTokenRequired
274
297
  && (errorCode === ArcGisErrorCode.TokenRequired || errorCode === ArcGisErrorCode.MissingPermissions)) {
275
298
  accessTokenRequired = true;
276
299
  // If token required
277
- const accessClient = IModelApp.mapLayerFormatRegistry.getAccessClient(formatId);
278
300
  if (accessClient) {
279
301
  tmpUrl = createUrlObj();
280
302
  await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, { mapLayerUrl: new URL(url), userName, password });
281
- response = await fetch(tmpUrl.toString(), { method: "GET" });
282
- errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);
303
+ ({ response, managedByHandler } = await requestJson(tmpUrl, false));
283
304
  }
284
305
  }
285
306
  const json = await response.json();
286
- const info = { content: json, accessTokenRequired };
287
- // Cache the response only if it doesn't contain any error.
288
- ArcGisUtilities._serviceCache.set(url, (errorCode === undefined ? info : undefined));
307
+ // Classified from the parsed body regardless of the Content-Type the server labelled it with.
308
+ const contentErrorCode = json?.error?.code;
309
+ const info = { content: json, accessTokenRequired, errorCode: managedByHandler ? undefined : contentErrorCode };
310
+ // Cache the response only if it doesn't contain any error, and never when a fetch handler managed it or
311
+ // is registered (the cache is keyed by URL only, so protected data must not be cached).
312
+ if (!hasFetchHandler && !managedByHandler)
313
+ ArcGisUtilities._serviceCache.set(url, (contentErrorCode === undefined ? info : undefined));
289
314
  return info; // Always return json, even though it contains an error code.
290
315
  }
291
316
  catch (err) {
292
317
  ArcGisUtilities._serviceCache.set(url, undefined);
293
- if (err instanceof MapLayerUntrustedOriginError)
294
- throw err; // propagate so callers can report the blocked origin
318
+ if (err instanceof MapLayerUntrustedOriginError || err instanceof MapLayerAuthenticationFailedError)
319
+ throw err; // propagate so callers can report the blocked origin / authentication failure
295
320
  return undefined;
296
321
  }
297
322
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ArcGisUtilities.js","sourceRoot":"","sources":["../../../../../src/internal/tile/map/ArcGisUtilities.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { Angle, Constant } from \"@itwin/core-geometry\";\r\nimport { MapSubLayerProps } from \"@itwin/core-common\";\r\nimport { MapCartoRectangle, MapLayerAccessClient, MapLayerAccessToken, MapLayerAccessTokenParams, MapLayerSource, MapLayerSourceStatus, MapLayerSourceValidation, MapLayerUntrustedOriginError, ValidateSourceArgs} from \"../../../tile/internal\";\r\nimport { IModelApp } from \"../../../IModelApp\";\r\nimport { headersIncludeAuthMethod } from \"../../../request/utils\";\r\n\r\n/** @packageDocumentation\r\n * @module Tiles\r\n */\r\n\r\n\r\nconst restServicesSubPath = \"/rest/services/\";\r\n\r\n/**\r\n * Class representing an ArcGIS error code.\r\n * @internal\r\n */\r\nexport enum ArcGisErrorCode {\r\n InvalidCredentials = 401,\r\n MissingPermissions = 403,\r\n InvalidToken = 498,\r\n TokenRequired = 499,\r\n UnknownError = 1000,\r\n NoTokenService = 1001,\r\n}\r\n\r\n/**\r\n * Class representing an ArcGIS service metadata.\r\n * @internal\r\n */\r\nexport interface ArcGISServiceMetadata {\r\n /** JSON content from the service */\r\n content: any;\r\n\r\n /** Indicates if an access token is required to access the service */\r\n accessTokenRequired: boolean;\r\n}\r\n\r\n/** Arguments for validating ArcGIS sources * @internal\r\n */\r\nexport interface ArcGisValidateSourceArgs extends ValidateSourceArgs {\r\n /** List of capabilities 'keyword' that needs to be advertised in the service's metadata in order to be valid. For example: 'Map', 'Query', etc*/\r\n capabilitiesFilter: string[];\r\n}\r\n\r\n/** Arguments for fetching service metadata * @internal\r\n */\r\nexport interface ArcGisGetServiceJsonArgs {\r\n url: string;\r\n formatId: string;\r\n userName?: string;\r\n password?: string;\r\n queryParams?: {[key: string]: string};\r\n ignoreCache?: boolean;\r\n requireToken?: boolean;\r\n}\r\n\r\n/**\r\n * Class containing utilities relating to ArcGIS services and coordinate systems.\r\n * @internal\r\n */\r\nexport class ArcGisUtilities {\r\n\r\n private static getBBoxString(range?: MapCartoRectangle) {\r\n if (!range)\r\n range = MapCartoRectangle.createMaximum();\r\n\r\n return `${range.low.x * Angle.degreesPerRadian},${range.low.y * Angle.degreesPerRadian},${range.high.x * Angle.degreesPerRadian},${range.high.y * Angle.degreesPerRadian}`;\r\n }\r\n\r\n public static async getNationalMapSources(): Promise<MapLayerSource[]> {\r\n const sources = new Array<MapLayerSource>();\r\n const response = await fetch(\"https://viewer.nationalmap.gov/tnmaccess/api/getMapServiceList\", { method: \"GET\" });\r\n const services = await response.json();\r\n\r\n if (!Array.isArray(services))\r\n return sources;\r\n\r\n for (const service of services) {\r\n if (service.wmsUrl.length === 0) // Exclude Wfs..\r\n continue;\r\n switch (service.serviceType) {\r\n case \"ArcGIS\":\r\n // The hard-coded props guarantee a defined result from fromJSON.\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n sources.push(MapLayerSource.fromJSON({ name: service.displayName, url: service.serviceLink, formatId: \"ArcGIS\" })!);\r\n break;\r\n default: {\r\n const wmsIndex = service.wmsUrl.lastIndexOf(\"/wms\");\r\n if (wmsIndex > 0) {\r\n const url = service.wmsUrl.slice(0, wmsIndex + 4);\r\n // The hard-coded props guarantee a defined result from fromJSON.\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n sources.push(MapLayerSource.fromJSON({ name: service.displayName, url, formatId: \"WMS\" })!);\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n return sources;\r\n }\r\n\r\n public static async getServiceDirectorySources(url: string, baseUrl?: string): Promise<MapLayerSource[]> {\r\n if (undefined === baseUrl)\r\n baseUrl = url;\r\n let sources = new Array<MapLayerSource>();\r\n const response = await fetch(`${url}?f=json`, { method: \"GET\" });\r\n const json = await response.json();\r\n if (json !== undefined) {\r\n if (Array.isArray(json.folders)) {\r\n for (const folder of json.folders) {\r\n sources = sources.concat(await ArcGisUtilities.getServiceDirectorySources(`${url}/${folder}`, url));\r\n }\r\n }\r\n if (Array.isArray(json.services)) {\r\n for (const service of json.services) {\r\n let source;\r\n if (service.type === \"MapServer\")\r\n source = MapLayerSource.fromJSON({ name: service.name, url: `${baseUrl}/${service.name}/MapServer`, formatId: \"ArcGIS\" });\r\n else if (service.type === \"ImageServer\")\r\n source = MapLayerSource.fromJSON({ name: service.name, url: `${baseUrl}/${service.name}/ImageServer`, formatId: \"ArcGIS\" });\r\n if (source)\r\n sources.push(source);\r\n }\r\n }\r\n }\r\n\r\n return sources;\r\n }\r\n\r\n /**\r\n * Get map layer sources from an ArcGIS query.\r\n * @param range Range for the query.\r\n * @param url URL for the query.\r\n * @returns List of map layer sources.\r\n */\r\n public static async getSourcesFromQuery(range?: MapCartoRectangle, url = \"https://usgs.maps.arcgis.com/sharing/rest/search\"): Promise<MapLayerSource[]> {\r\n const sources = new Array<MapLayerSource>();\r\n for (let start = 1; start > 0;) {\r\n const response = await fetch(`${url}?f=json&q=(group:9d1199a521334e77a7d15abbc29f8144) AND (type:\"Map Service\")&bbox=${ArcGisUtilities.getBBoxString(range)}&sortOrder=desc&start=${start}&num=100`, { method: \"GET\" });\r\n const json = await response.json();\r\n if (!json)\r\n break;\r\n\r\n start = json.nextStart ? json.nextStart : -1;\r\n if (json !== undefined && Array.isArray(json.results)) {\r\n for (const result of json.results) {\r\n const source = MapLayerSource.fromJSON({ name: result.name ? result.name : result.title, url: result.url, formatId: \"ArcGIS\" });\r\n if (source)\r\n sources.push(source);\r\n }\r\n }\r\n }\r\n\r\n return sources;\r\n }\r\n\r\n /**\r\n * Parse the URL to check if it represents a valid ArcGIS service\r\n * @param url URL to validate.\r\n * @param serviceType Service type to validate (i.e FeatureServer, MapServer)\r\n * @return Validation Status.\r\n */\r\n public static validateUrl(url: string, serviceType: string): MapLayerSourceStatus {\r\n const urlObj = new URL(url.toLowerCase());\r\n const restServicesPos = urlObj.pathname.search(restServicesSubPath);\r\n if (restServicesPos !== -1) {\r\n // This seem to be an ArcGIS URL, lets check the service type\r\n if (urlObj.pathname.includes(serviceType.toLowerCase(), restServicesPos + restServicesSubPath.length)) {\r\n return MapLayerSourceStatus.Valid;\r\n } else {\r\n return MapLayerSourceStatus.IncompatibleFormat;\r\n }\r\n } else {\r\n return MapLayerSourceStatus.InvalidUrl;\r\n }\r\n }\r\n\r\n /**\r\n * Attempt to access an ArcGIS service, and validate its service metadata.\r\n * @param source Source to validate.\r\n * @param opts Validation options\r\n */\r\n public static async validateSource(args: ArcGisValidateSourceArgs): Promise<MapLayerSourceValidation> {\r\n const {source, ignoreCache, capabilitiesFilter} = args;\r\n let metadata: ArcGISServiceMetadata | undefined;\r\n try {\r\n metadata = await this.getServiceJson({url: source.url, formatId: source.formatId, userName: source.userName, password: source.password, queryParams: source.collectQueryParams(), ignoreCache});\r\n } catch (err) {\r\n if (err instanceof MapLayerUntrustedOriginError) {\r\n let blockedOrigin: string | undefined;\r\n try { blockedOrigin = new URL(err.url).origin; } catch { /* non-hierarchical URL */ }\r\n return { status: MapLayerSourceStatus.UntrustedOrigin, blockedOrigin };\r\n }\r\n throw err;\r\n }\r\n const json = metadata?.content;\r\n if (json === undefined) {\r\n return { status: MapLayerSourceStatus.InvalidUrl };\r\n } else if (json.error !== undefined) {\r\n\r\n // If we got a 'Token Required' error, lets check what authentification methods this ESRI service offers\r\n // and return information needed to initiate the authentification process... the end-user\r\n // will have to provide his credentials before we can fully validate this source.\r\n // Note: Some servers will throw a error 403 (You do not have permissions to access this resource or perform this operation),\r\n // instead of 499 (TokenRequired)\r\n if (json.error.code === ArcGisErrorCode.TokenRequired || json.error.code === ArcGisErrorCode.MissingPermissions) {\r\n return (source.userName || source.password) ? {status: MapLayerSourceStatus.InvalidCredentials} : {status: MapLayerSourceStatus.RequireAuth};\r\n } else if (json.error.code === ArcGisErrorCode.InvalidCredentials)\r\n return { status: MapLayerSourceStatus.InvalidCredentials};\r\n }\r\n\r\n // Check this service support the expected queries\r\n let hasCapabilities = false;\r\n let capsArray: string[] = [];\r\n if (json.capabilities && typeof json.capabilities === \"string\" ) {\r\n const capabilities: string = json.capabilities;\r\n capsArray = capabilities.split(\",\").map((entry) => entry.toLowerCase());\r\n\r\n const filtered = capsArray.filter((element, _index, _array) => capabilitiesFilter.includes(element));\r\n hasCapabilities = (filtered.length === capabilitiesFilter.length);\r\n }\r\n if (!hasCapabilities) {\r\n return { status: MapLayerSourceStatus.InvalidFormat};\r\n }\r\n\r\n // Only EPSG:3857 is supported with pre-rendered tiles.\r\n if (json.tileInfo && capsArray.includes(\"tilesonly\") && !ArcGisUtilities.isEpsg3857Compatible(json.tileInfo)) {\r\n return { status: MapLayerSourceStatus.InvalidCoordinateSystem};\r\n }\r\n\r\n let subLayers;\r\n if (json.layers) {\r\n\r\n subLayers = new Array<MapSubLayerProps>();\r\n\r\n for (const layer of json.layers) {\r\n const parent = layer.parentLayerId < 0 ? undefined : layer.parentLayerId;\r\n const children = Array.isArray(layer.subLayerIds) ? layer.subLayerIds : undefined;\r\n subLayers.push({ name: layer.name, visible: layer.defaultVisibility !== false, id: layer.id, parent, children });\r\n }\r\n }\r\n return { status: MapLayerSourceStatus.Valid, subLayers };\r\n }\r\n\r\n /** Validate MapService tiling metadata and checks if the tile tree is 'Google Maps' compatible. */\r\n public static isEpsg3857Compatible(tileInfo: any) {\r\n if (tileInfo.spatialReference?.latestWkid !== 3857 || !Array.isArray(tileInfo.lods))\r\n return false;\r\n\r\n const zeroLod = tileInfo.lods[0];\r\n return zeroLod.level === 0 && Math.abs(zeroLod.resolution - 156543.03392800014) < .001;\r\n }\r\n\r\n private static _serviceCache = new Map<string, ArcGISServiceMetadata|undefined>();\r\n\r\n /**\r\n * Fetches an ArcGIS service metadata, and returns its JSON representation.\r\n * If an access client has been configured for the specified formatId,\r\n * it will be used to apply required security token.\r\n * By default, response for each URL are cached.\r\n * @param url URL of the ArcGIS service\r\n * @param formatId Format ID of the service\r\n * @param userName Username to use for legacy token based security\r\n * @param password Password to use for legacy token based security\r\n * @param ignoreCache Flag to skip cache lookup (i.e. force a new server request)\r\n * @param requireToken Flag to indicate if a token is required\r\n * @throws [[MapLayerUntrustedOriginError]] if an NTLM/Negotiate challenge could not be answered because\r\n * the URL's origin is not trusted (see [[MapLayerFormatRegistry.restrictCredentialsToTrustedOrigins]]);\r\n * all other errors are caught and reported by returning `undefined`.\r\n */\r\n\r\n public static async getServiceJson(args: ArcGisGetServiceJsonArgs): Promise<ArcGISServiceMetadata|undefined> {\r\n const {url, formatId, userName, password, queryParams, ignoreCache, requireToken} = args;\r\n if (!ignoreCache) {\r\n const cached = ArcGisUtilities._serviceCache.get(url);\r\n if (cached !== undefined)\r\n return cached;\r\n }\r\n const appendParams = (urlObj: URL, params?: {[key: string]: string}) => {\r\n if (params) {\r\n Object.keys(params).forEach((paramKey) => {\r\n if (!urlObj.searchParams.has(paramKey))\r\n urlObj.searchParams.append(paramKey, params[paramKey]);\r\n });\r\n }\r\n };\r\n\r\n const createUrlObj = () => {\r\n const tmpUrl = new URL(url);\r\n tmpUrl.searchParams.append(\"f\", \"json\");\r\n appendParams(tmpUrl, queryParams);\r\n return tmpUrl;\r\n };\r\n\r\n let accessTokenRequired = false;\r\n try {\r\n let tmpUrl = createUrlObj();\r\n\r\n // In some cases, caller might already know token is required, so append it immediately\r\n if (requireToken) {\r\n const accessClient = IModelApp.mapLayerFormatRegistry.getAccessClient(formatId);\r\n if (accessClient) {\r\n accessTokenRequired = true;\r\n await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, {mapLayerUrl: new URL(url), userName, password});\r\n }\r\n }\r\n let response = await fetch(tmpUrl, { method: \"GET\" });\r\n if (response.status === 401 && !requireToken && headersIncludeAuthMethod(response.headers, [\"ntlm\", \"negotiate\"])) {\r\n // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.\r\n const challengedUrl = response.url || tmpUrl.toString();\r\n if (!IModelApp.mapLayerFormatRegistry.isSsoAllowed(challengedUrl))\r\n throw new MapLayerUntrustedOriginError(challengedUrl);\r\n\r\n IModelApp.mapLayerFormatRegistry.logUntrustedOriginUse(challengedUrl);\r\n\r\n // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).\r\n response = await fetch(challengedUrl, {\r\n method: \"GET\",\r\n credentials: \"include\",\r\n redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? \"error\" : undefined,\r\n });\r\n }\r\n\r\n // Append security token when corresponding error code is returned by ArcGIS service\r\n let errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);\r\n if (!accessTokenRequired\r\n && (errorCode === ArcGisErrorCode.TokenRequired || errorCode === ArcGisErrorCode.MissingPermissions) ) {\r\n accessTokenRequired = true;\r\n // If token required\r\n const accessClient = IModelApp.mapLayerFormatRegistry.getAccessClient(formatId);\r\n if (accessClient) {\r\n tmpUrl = createUrlObj();\r\n await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, {mapLayerUrl: new URL(url), userName, password});\r\n response = await fetch(tmpUrl.toString(), { method: \"GET\" });\r\n errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);\r\n }\r\n }\r\n\r\n const json = await response.json();\r\n const info = {content: json, accessTokenRequired};\r\n // Cache the response only if it doesn't contain any error.\r\n ArcGisUtilities._serviceCache.set(url, (errorCode === undefined ? info : undefined));\r\n return info; // Always return json, even though it contains an error code.\r\n\r\n } catch (err) {\r\n ArcGisUtilities._serviceCache.set(url, undefined);\r\n if (err instanceof MapLayerUntrustedOriginError)\r\n throw err; // propagate so callers can report the blocked origin\r\n return undefined;\r\n }\r\n }\r\n\r\n /** Read a response from ArcGIS server and check for error code in the response. */\r\n public static async checkForResponseErrorCode(response: Response) {\r\n const tmpResponse = response;\r\n if (response.headers && tmpResponse.headers.get(\"content-type\")?.toLowerCase().includes(\"json\")) {\r\n\r\n try {\r\n // Note:\r\n // Since response stream can only be read once (i.e. calls to .json() method)\r\n // we have to clone the response object in order to check for potential error code,\r\n // but still keep the response stream as unread.\r\n const clonedResponse = tmpResponse.clone();\r\n const json = await clonedResponse.json();\r\n if (json?.error?.code !== undefined)\r\n return json?.error?.code as number;\r\n } catch { }\r\n\r\n }\r\n return undefined;\r\n }\r\n\r\n // return the appended access token if available.\r\n public static async appendSecurityToken(url: URL, accessClient: MapLayerAccessClient, accessTokenParams: MapLayerAccessTokenParams): Promise<MapLayerAccessToken|undefined> {\r\n\r\n // Append security token if available\r\n let accessToken: MapLayerAccessToken|undefined;\r\n try {\r\n accessToken = await accessClient.getAccessToken(accessTokenParams);\r\n } catch {}\r\n\r\n if (accessToken?.token) {\r\n url.searchParams.append(\"token\", accessToken.token);\r\n return accessToken;\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Compute scale, resolution values for requested zoom levels (WSG 84)\r\n * Use a scale of 96 dpi for Google Maps scales\r\n * Based on this article: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale\r\n * @param startZoom Zoom level where scales begins to be computed\r\n * @param endZoom Zoom level where scales ends to be computed\r\n * @param latitude Latitude in degrees to use to compute scales (i.e 0 for Equator)\r\n * @param tileSize Size of a tile in pixels (i.e 256)\r\n * @param screenDpi Monitor resolution in dots per inch (i.e. typically 96dpi is used by Google Maps)\r\n * @returns An array containing resolution and scale values for each requested zoom level\r\n */\r\n public static computeZoomLevelsScales(startZoom: number = 0, endZoom: number = 20, latitude: number = 0, tileSize: number = 256, screenDpi = 96): {zoom: number, resolution: number, scale: number}[] {\r\n // Note: There is probably a more direct way to compute this, but I prefer to go for a simple and well documented approach.\r\n if (startZoom <0 || endZoom < startZoom || tileSize < 0 || screenDpi < 1 || latitude < -90 || latitude > 90)\r\n return [];\r\n\r\n const inchPerMeter = 1 / 0.0254;\r\n const results: {zoom: number, resolution: number, scale: number}[] = [];\r\n const equatorLength = Constant.earthRadiusWGS84.equator * 2 * Math.PI;\r\n const zoom0Resolution = equatorLength / tileSize; // in meters per pixel\r\n\r\n const cosLatitude = Math.cos(latitude);\r\n for (let zoom = startZoom; zoom<= endZoom; zoom++) {\r\n const resolution = zoom0Resolution * cosLatitude / Math.pow(2, zoom);\r\n const scale = screenDpi * inchPerMeter * resolution;\r\n results.push({zoom, resolution, scale});\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Match the provided minScale, maxScale values to corresponding wgs84 zoom levels\r\n * @param defaultMaxLod Value of the last LOD (i.e 22)\r\n * @param tileSize Size of a tile in pixels (i.e 256)\r\n * @param minScale Minimum scale value that needs to be matched to a LOD level\r\n * @param maxScale Maximum scale value that needs to be matched to a LOD level\r\n * @returns minLod: LOD value matching minScale, maxLod: LOD value matching maxScale\r\n */\r\n public static getZoomLevelsScales( defaultMaxLod: number, tileSize: number, minScale?: number, maxScale?: number, tolerance: number = 0): {minLod?: number, maxLod?: number} {\r\n\r\n let minLod: number|undefined, maxLod: number|undefined;\r\n\r\n const zoomScales = ArcGisUtilities.computeZoomLevelsScales(0, defaultMaxLod, 0 /* latitude 0 = Equator*/, tileSize);\r\n\r\n if (zoomScales.length > 0) {\r\n\r\n if (minScale) {\r\n minLod = 0;\r\n // We are looking for the largest scale value with a scale value smaller than minScale\r\n for (; minLod < zoomScales.length && (zoomScales[minLod].scale > minScale && Math.abs(zoomScales[minLod].scale - minScale) > tolerance); minLod++)\r\n ;\r\n\r\n }\r\n\r\n if (maxScale) {\r\n maxLod = defaultMaxLod;\r\n // We are looking for the smallest scale value with a value greater than maxScale\r\n for (; maxLod >= 0 && zoomScales[maxLod].scale < maxScale && Math.abs(zoomScales[maxLod].scale - maxScale) > tolerance; maxLod--)\r\n ;\r\n }\r\n }\r\n return {minLod, maxLod};\r\n }\r\n\r\n}\r\n"]}
1
+ {"version":3,"file":"ArcGisUtilities.js","sourceRoot":"","sources":["../../../../../src/internal/tile/map/ArcGisUtilities.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAC/F,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,iBAAiB,EAAwE,iCAAiC,EAAuB,cAAc,EAAE,oBAAoB,EAA4B,4BAA4B,EAAqB,MAAM,wBAAwB,CAAC;AAC3V,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE;;GAEG;AAGH,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,mFAAwB,CAAA;IACxB,mFAAwB,CAAA;IACxB,uEAAkB,CAAA;IAClB,yEAAmB,CAAA;IACnB,wEAAmB,CAAA;IACnB,4EAAqB,CAAA;AACvB,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B;AA4CD;;;GAGG;AACH,MAAM,OAAO,eAAe;IAElB,MAAM,CAAC,aAAa,CAAC,KAAyB;QACpD,IAAI,CAAC,KAAK;YACR,KAAK,GAAG,iBAAiB,CAAC,aAAa,EAAE,CAAC;QAE5C,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAC7K,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,qBAAqB;QACvC,MAAM,OAAO,GAAG,IAAI,KAAK,EAAkB,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gEAAgE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAClH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC1B,OAAO,OAAO,CAAC;QAEjB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAK,gBAAgB;gBAClD,SAAS;YACX,QAAQ,OAAO,CAAC,WAAW,EAAE,CAAC;gBAC5B,KAAK,QAAQ;oBACX,iEAAiE;oBACjE,oEAAoE;oBACpE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAE,CAAC,CAAC;oBACpH,MAAM;gBACR,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBACpD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;wBACjB,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;wBAClD,iEAAiE;wBACjE,oEAAoE;wBACpE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAE,CAAC,CAAC;oBAC9F,CAAC;oBACD,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,GAAW,EAAE,OAAgB;QAC1E,IAAI,SAAS,KAAK,OAAO;YACvB,OAAO,GAAG,GAAG,CAAC;QAChB,IAAI,OAAO,GAAG,IAAI,KAAK,EAAkB,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,eAAe,CAAC,0BAA0B,CAAC,GAAG,GAAG,IAAI,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;gBACtG,CAAC;YACH,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,IAAI,MAAM,CAAC;oBACX,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;wBAC9B,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;yBACvH,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa;wBACrC,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAC9H,IAAI,MAAM;wBACR,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,KAAyB,EAAE,GAAG,GAAG,kDAAkD;QACzH,MAAM,OAAO,GAAG,IAAI,KAAK,EAAkB,CAAC;QAC5C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC;YAC/B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,oFAAoF,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,yBAAyB,KAAK,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACxN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI;gBACP,MAAM;YAER,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClC,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;oBAChI,IAAI,MAAM;wBACR,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,WAAW,CAAC,GAAW,EAAE,WAAmB;QACxD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1C,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACpE,IAAI,eAAe,KAAK,CAAC,CAAC,EAAE,CAAC;YAC3B,6DAA6D;YAC7D,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtG,OAAO,oBAAoB,CAAC,KAAK,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,OAAO,oBAAoB,CAAC,kBAAkB,CAAC;YACjD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,oBAAoB,CAAC,UAAU,CAAC;QACzC,CAAC;IACH,CAAC;IAED;;;;MAIE;IACK,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAA8B;QAC/D,MAAM,EAAC,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAC,GAAG,IAAI,CAAC;QACvD,IAAI,QAA2C,CAAC;QAChD,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,EAAC,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,kBAAkB,EAAE,EAAE,WAAW,EAAC,CAAC,CAAC;QAClM,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,iCAAiC;gBAClD,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,WAAW,EAAE,CAAC;YACtD,IAAI,GAAG,YAAY,4BAA4B,EAAE,CAAC;gBAChD,IAAI,aAAiC,CAAC;gBACtC,IAAI,CAAC;oBAAC,aAAa,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;gBACrF,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,eAAe,EAAE,aAAa,EAAE,CAAC;YACzE,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,EAAE,OAAO,CAAC;QAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,UAAU,EAAE,CAAC;QACrD,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,EAAE,SAAS,CAAC;QACtC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,wGAAwG;YACxG,yFAAyF;YACzF,iFAAiF;YACjF,6HAA6H;YAC7H,uCAAuC;YACvC,IAAI,SAAS,KAAK,eAAe,CAAC,aAAa,IAAI,SAAS,KAAK,eAAe,CAAC,kBAAkB,EAAG,CAAC;gBACrG,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,oBAAoB,CAAC,kBAAkB,EAAC,CAAC,CAAC,CAAC,EAAC,MAAM,EAAE,oBAAoB,CAAC,WAAW,EAAC,CAAC;YAC/I,CAAC;iBAAM,IAAI,SAAS,KAAK,eAAe,CAAC,kBAAkB;gBACzD,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,kBAAkB,EAAC,CAAC;QAC9D,CAAC;QAED,kDAAkD;QAClD,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,SAAS,GAAa,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,YAAY,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAG,CAAC;YAChE,MAAM,YAAY,GAAW,IAAI,CAAC,YAAY,CAAC;YAC/C,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YAExE,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACrG,eAAe,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,aAAa,EAAC,CAAC;QACvD,CAAC;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7G,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,uBAAuB,EAAC,CAAC;QACjE,CAAC;QAED,IAAI,SAAS,CAAC;QACd,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAEhB,SAAS,GAAG,IAAI,KAAK,EAAoB,CAAC;YAE1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;gBACzE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;gBAClF,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,iBAAiB,KAAK,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC;IAC3D,CAAC;IAED,mGAAmG;IAC5F,MAAM,CAAC,oBAAoB,CAAC,QAAa;QAC9C,IAAI,QAAQ,CAAC,gBAAgB,EAAE,UAAU,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjF,OAAO,KAAK,CAAC;QAEf,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,OAAO,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,GAAG,kBAAkB,CAAC,GAAG,IAAI,CAAC;IACzF,CAAC;IAEO,MAAM,CAAC,aAAa,GAAG,IAAI,GAAG,EAA2C,CAAC;IAElF;;;;;;;;;;;;;;;;OAgBG;IAEI,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAA8B;QAC/D,MAAM,EAAC,GAAG,EAAE,QAAQ,GAAG,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAC,GAAG,IAAI,CAAC;QAC1H,MAAM,YAAY,GAAG,SAAS,CAAC,sBAAsB,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;QACjF,qFAAqF;QACrF,gGAAgG;QAChG,MAAM,eAAe,GAAG,CAAC,SAAS,CAAC,sBAAsB,EAAE,qBAAqB,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAClG,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtD,IAAI,MAAM,KAAK,SAAS;gBACtB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,MAAM,YAAY,GAAG,CAAC,MAAW,EAAE,MAAgC,EAAE,EAAE;YACrE,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;wBACpC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC3D,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACxC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAClC,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,iGAAiG;QACjG,mGAAmG;QACnG,MAAM,WAAW,GAAG,KAAK,EAAE,MAAW,EAAE,aAAsB,EAAgC,EAAE;YAC9F,OAAO,oBAAoB,CAAC;gBAC1B,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE;gBACtB,QAAQ;gBACR,QAAQ;gBACR,eAAe;gBACf,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE;oBACpC,oGAAoG;oBACpG,IAAI,GAAG,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,yBAAyB,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;oBAClJ,IAAI,aAAa,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,YAAY,IAAI,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;wBAC1I,kGAAkG;wBAClG,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;wBAC7C,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,YAAY,CAAC,aAAa,CAAC;4BAC/D,MAAM,IAAI,4BAA4B,CAAC,aAAa,CAAC,CAAC;wBAExD,SAAS,CAAC,sBAAsB,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;wBAEtE,8FAA8F;wBAC9F,GAAG,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;4BAC/B,MAAM,EAAE,KAAK;4BACb,WAAW,EAAE,SAAS;4BACtB,QAAQ,EAAE,SAAS,CAAC,sBAAsB,CAAC,mCAAmC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;yBACrG,CAAC,CAAC;oBACL,CAAC;oBACD,OAAO,GAAG,CAAC;gBACb,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,mBAAmB,GAAG,KAAK,CAAC;QAChC,IAAI,CAAC;YACH,IAAI,MAAM,GAAG,YAAY,EAAE,CAAC;YAE5B,uFAAuF;YACvF,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,YAAY,EAAE,CAAC;oBACjB,mBAAmB,GAAG,IAAI,CAAC;oBAC3B,MAAM,eAAe,CAAC,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAC,WAAW,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAC,CAAC,CAAC;gBACnH,CAAC;YACH,CAAC;YACD,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAErE,oFAAoF;YACpF,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC;YAC5E,IAAI,CAAC,mBAAmB;mBACnB,CAAC,SAAS,KAAK,eAAe,CAAC,aAAa,IAAI,SAAS,KAAK,eAAe,CAAC,kBAAkB,CAAC,EAAG,CAAC;gBACxG,mBAAmB,GAAG,IAAI,CAAC;gBAC3B,oBAAoB;gBACpB,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,GAAG,YAAY,EAAE,CAAC;oBACxB,MAAM,eAAe,CAAC,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAC,WAAW,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAC,CAAC,CAAC;oBACjH,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;gBACtE,CAAC;YACH,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,8FAA8F;YAC9F,MAAM,gBAAgB,GAAgC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;YACxE,MAAM,IAAI,GAA0B,EAAC,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,EAAC,CAAC;YACrI,wGAAwG;YACxG,wFAAwF;YACxF,IAAI,CAAC,eAAe,IAAI,CAAC,gBAAgB;gBACvC,eAAe,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YAC9F,OAAO,IAAI,CAAC,CAAE,6DAA6D;QAE7E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,eAAe,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAClD,IAAI,GAAG,YAAY,4BAA4B,IAAI,GAAG,YAAY,iCAAiC;gBACjG,MAAM,GAAG,CAAC,CAAI,8EAA8E;YAC9F,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,mFAAmF;IAC5E,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,QAAkB;QAC9D,MAAM,WAAW,GAAG,QAAQ,CAAC;QAC7B,IAAI,QAAQ,CAAC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAEhG,IAAI,CAAC;gBACH,QAAQ;gBACR,6EAA6E;gBAC7E,mFAAmF;gBACnF,gDAAgD;gBAChD,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC;gBAC3C,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,CAAC;gBACzC,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,SAAS;oBACjC,OAAO,IAAI,EAAE,KAAK,EAAE,IAAc,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC,CAAC,CAAC;QAEb,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,iDAAiD;IAC1C,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAQ,EAAE,YAAkC,EAAE,iBAA4C;QAEhI,qCAAqC;QACrC,IAAI,WAA0C,CAAC;QAC/C,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,YAAY,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;QACrE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,IAAI,WAAW,EAAE,KAAK,EAAE,CAAC;YACvB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;YACpD,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;OAUG;IACI,MAAM,CAAC,uBAAuB,CAAC,YAAoB,CAAC,EAAE,UAAkB,EAAE,EAAE,WAAmB,CAAC,EAAE,WAAmB,GAAG,EAAE,SAAS,GAAG,EAAE;QAC7I,2HAA2H;QAC3H,IAAI,SAAS,GAAE,CAAC,IAAI,OAAO,GAAG,SAAS,IAAI,QAAQ,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC,IAAK,QAAQ,GAAG,CAAC,EAAE,IAAI,QAAQ,GAAG,EAAE;YAC1G,OAAO,EAAE,CAAC;QAEZ,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC;QAChC,MAAM,OAAO,GAAwD,EAAE,CAAC;QACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,gBAAgB,CAAC,OAAO,GAAG,CAAC,GAAI,IAAI,CAAC,EAAE,CAAC;QACvE,MAAM,eAAe,GAAG,aAAa,GAAG,QAAQ,CAAC,CAAC,sBAAsB;QAExE,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,KAAK,IAAI,IAAI,GAAG,SAAS,EAAG,IAAI,IAAG,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;YACnD,MAAM,UAAU,GAAG,eAAe,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACrE,MAAM,KAAK,GAAI,SAAS,GAAG,YAAY,GAAI,UAAU,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAC,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,mBAAmB,CAAE,aAAqB,EAAE,QAAgB,EAAE,QAAiB,EAAE,QAAiB,EAAE,YAAoB,CAAC;QAErI,IAAI,MAAwB,EAAE,MAAwB,CAAC;QAEvD,MAAM,UAAU,GAAG,eAAe,CAAC,uBAAuB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC;QAEpH,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAE1B,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,GAAG,CAAC,CAAC;gBACX,sFAAsF;gBACtF,OAAO,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,GAAG,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE;oBAC/I,CAAC;YAEL,CAAC;YAED,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,GAAG,aAAa,CAAC;gBACvB,iFAAiF;gBACjF,OAAO,MAAM,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,GAAG,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE;oBAC9H,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO,EAAC,MAAM,EAAE,MAAM,EAAC,CAAC;IAC1B,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { Angle, Constant } from \"@itwin/core-geometry\";\r\nimport { MapLayerProviderProperties, MapSubLayerProps } from \"@itwin/core-common\";\r\nimport { credentialedFetchRedirect, fetchMapLayerRequest, MapCartoRectangle, MapLayerAccessClient, MapLayerAccessToken, MapLayerAccessTokenParams, MapLayerAuthenticationFailedError, MapLayerFetchResult, MapLayerSource, MapLayerSourceStatus, MapLayerSourceValidation, MapLayerUntrustedOriginError, ValidateSourceArgs} from \"../../../tile/internal\";\r\nimport { IModelApp } from \"../../../IModelApp\";\r\nimport { headersIncludeAuthMethod } from \"../../../request/utils\";\r\n\r\n/** @packageDocumentation\r\n * @module Tiles\r\n */\r\n\r\n\r\nconst restServicesSubPath = \"/rest/services/\";\r\n\r\n/**\r\n * Class representing an ArcGIS error code.\r\n * @internal\r\n */\r\nexport enum ArcGisErrorCode {\r\n InvalidCredentials = 401,\r\n MissingPermissions = 403,\r\n InvalidToken = 498,\r\n TokenRequired = 499,\r\n UnknownError = 1000,\r\n NoTokenService = 1001,\r\n}\r\n\r\n/**\r\n * The result of fetching an ArcGIS service's metadata (see [[ArcGisUtilities.getServiceJson]]): the service's\r\n * JSON document in `content`, alongside what the framework determined while obtaining it.\r\n * @internal\r\n */\r\nexport interface ArcGISServiceMetadata {\r\n /** The JSON document returned by the service, as-is. */\r\n content: any;\r\n\r\n /** Indicates if an access token is required to access the service */\r\n accessTokenRequired: boolean;\r\n\r\n /** The ArcGIS error code carried by `content`, if any. Omitted when the response is managed by a fetch handler\r\n * (see [[MapLayerFetchResult.managedByHandler]]): the handler then reports failures by throwing\r\n * [[MapLayerAuthenticationFailedError]], and the framework applies no classification of its own.\r\n */\r\n errorCode?: ArcGisErrorCode;\r\n}\r\n\r\n/** Arguments for validating ArcGIS sources * @internal\r\n */\r\nexport interface ArcGisValidateSourceArgs extends ValidateSourceArgs {\r\n /** List of capabilities 'keyword' that needs to be advertised in the service's metadata in order to be valid. For example: 'Map', 'Query', etc*/\r\n capabilitiesFilter: string[];\r\n}\r\n\r\n/** Arguments for fetching service metadata * @internal\r\n */\r\nexport interface ArcGisGetServiceJsonArgs {\r\n url: string;\r\n /** Stable map-layer source URL used to identify the request to a fetch handler. Defaults to `url`. */\r\n layerUrl?: string;\r\n /** The layer's provider-specific settings properties, exposed to a fetch handler as [[MapLayerRequest.layerProperties]]. */\r\n layerProperties?: MapLayerProviderProperties;\r\n formatId: string;\r\n userName?: string;\r\n password?: string;\r\n queryParams?: {[key: string]: string};\r\n ignoreCache?: boolean;\r\n requireToken?: boolean;\r\n}\r\n\r\n/**\r\n * Class containing utilities relating to ArcGIS services and coordinate systems.\r\n * @internal\r\n */\r\nexport class ArcGisUtilities {\r\n\r\n private static getBBoxString(range?: MapCartoRectangle) {\r\n if (!range)\r\n range = MapCartoRectangle.createMaximum();\r\n\r\n return `${range.low.x * Angle.degreesPerRadian},${range.low.y * Angle.degreesPerRadian},${range.high.x * Angle.degreesPerRadian},${range.high.y * Angle.degreesPerRadian}`;\r\n }\r\n\r\n public static async getNationalMapSources(): Promise<MapLayerSource[]> {\r\n const sources = new Array<MapLayerSource>();\r\n const response = await fetch(\"https://viewer.nationalmap.gov/tnmaccess/api/getMapServiceList\", { method: \"GET\" });\r\n const services = await response.json();\r\n\r\n if (!Array.isArray(services))\r\n return sources;\r\n\r\n for (const service of services) {\r\n if (service.wmsUrl.length === 0) // Exclude Wfs..\r\n continue;\r\n switch (service.serviceType) {\r\n case \"ArcGIS\":\r\n // The hard-coded props guarantee a defined result from fromJSON.\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n sources.push(MapLayerSource.fromJSON({ name: service.displayName, url: service.serviceLink, formatId: \"ArcGIS\" })!);\r\n break;\r\n default: {\r\n const wmsIndex = service.wmsUrl.lastIndexOf(\"/wms\");\r\n if (wmsIndex > 0) {\r\n const url = service.wmsUrl.slice(0, wmsIndex + 4);\r\n // The hard-coded props guarantee a defined result from fromJSON.\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n sources.push(MapLayerSource.fromJSON({ name: service.displayName, url, formatId: \"WMS\" })!);\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n return sources;\r\n }\r\n\r\n public static async getServiceDirectorySources(url: string, baseUrl?: string): Promise<MapLayerSource[]> {\r\n if (undefined === baseUrl)\r\n baseUrl = url;\r\n let sources = new Array<MapLayerSource>();\r\n const response = await fetch(`${url}?f=json`, { method: \"GET\" });\r\n const json = await response.json();\r\n if (json !== undefined) {\r\n if (Array.isArray(json.folders)) {\r\n for (const folder of json.folders) {\r\n sources = sources.concat(await ArcGisUtilities.getServiceDirectorySources(`${url}/${folder}`, url));\r\n }\r\n }\r\n if (Array.isArray(json.services)) {\r\n for (const service of json.services) {\r\n let source;\r\n if (service.type === \"MapServer\")\r\n source = MapLayerSource.fromJSON({ name: service.name, url: `${baseUrl}/${service.name}/MapServer`, formatId: \"ArcGIS\" });\r\n else if (service.type === \"ImageServer\")\r\n source = MapLayerSource.fromJSON({ name: service.name, url: `${baseUrl}/${service.name}/ImageServer`, formatId: \"ArcGIS\" });\r\n if (source)\r\n sources.push(source);\r\n }\r\n }\r\n }\r\n\r\n return sources;\r\n }\r\n\r\n /**\r\n * Get map layer sources from an ArcGIS query.\r\n * @param range Range for the query.\r\n * @param url URL for the query.\r\n * @returns List of map layer sources.\r\n */\r\n public static async getSourcesFromQuery(range?: MapCartoRectangle, url = \"https://usgs.maps.arcgis.com/sharing/rest/search\"): Promise<MapLayerSource[]> {\r\n const sources = new Array<MapLayerSource>();\r\n for (let start = 1; start > 0;) {\r\n const response = await fetch(`${url}?f=json&q=(group:9d1199a521334e77a7d15abbc29f8144) AND (type:\"Map Service\")&bbox=${ArcGisUtilities.getBBoxString(range)}&sortOrder=desc&start=${start}&num=100`, { method: \"GET\" });\r\n const json = await response.json();\r\n if (!json)\r\n break;\r\n\r\n start = json.nextStart ? json.nextStart : -1;\r\n if (json !== undefined && Array.isArray(json.results)) {\r\n for (const result of json.results) {\r\n const source = MapLayerSource.fromJSON({ name: result.name ? result.name : result.title, url: result.url, formatId: \"ArcGIS\" });\r\n if (source)\r\n sources.push(source);\r\n }\r\n }\r\n }\r\n\r\n return sources;\r\n }\r\n\r\n /**\r\n * Parse the URL to check if it represents a valid ArcGIS service\r\n * @param url URL to validate.\r\n * @param serviceType Service type to validate (i.e FeatureServer, MapServer)\r\n * @return Validation Status.\r\n */\r\n public static validateUrl(url: string, serviceType: string): MapLayerSourceStatus {\r\n const urlObj = new URL(url.toLowerCase());\r\n const restServicesPos = urlObj.pathname.search(restServicesSubPath);\r\n if (restServicesPos !== -1) {\r\n // This seem to be an ArcGIS URL, lets check the service type\r\n if (urlObj.pathname.includes(serviceType.toLowerCase(), restServicesPos + restServicesSubPath.length)) {\r\n return MapLayerSourceStatus.Valid;\r\n } else {\r\n return MapLayerSourceStatus.IncompatibleFormat;\r\n }\r\n } else {\r\n return MapLayerSourceStatus.InvalidUrl;\r\n }\r\n }\r\n\r\n /**\r\n * Attempt to access an ArcGIS service, and validate its service metadata.\r\n * @param source Source to validate.\r\n * @param opts Validation options\r\n */\r\n public static async validateSource(args: ArcGisValidateSourceArgs): Promise<MapLayerSourceValidation> {\r\n const {source, ignoreCache, capabilitiesFilter} = args;\r\n let metadata: ArcGISServiceMetadata | undefined;\r\n try {\r\n metadata = await this.getServiceJson({url: source.url, formatId: source.formatId, userName: source.userName, password: source.password, queryParams: source.collectQueryParams(), ignoreCache});\r\n } catch (err) {\r\n if (err instanceof MapLayerAuthenticationFailedError)\r\n return { status: MapLayerSourceStatus.RequireAuth };\r\n if (err instanceof MapLayerUntrustedOriginError) {\r\n let blockedOrigin: string | undefined;\r\n try { blockedOrigin = new URL(err.url).origin; } catch { /* non-hierarchical URL */ }\r\n return { status: MapLayerSourceStatus.UntrustedOrigin, blockedOrigin };\r\n }\r\n throw err;\r\n }\r\n const json = metadata?.content;\r\n if (json === undefined) {\r\n return { status: MapLayerSourceStatus.InvalidUrl };\r\n }\r\n const errorCode = metadata?.errorCode;\r\n if (errorCode !== undefined) {\r\n // If we got a 'Token Required' error, lets check what authentification methods this ESRI service offers\r\n // and return information needed to initiate the authentification process... the end-user\r\n // will have to provide his credentials before we can fully validate this source.\r\n // Note: Some servers will throw a error 403 (You do not have permissions to access this resource or perform this operation),\r\n // instead of 499 (TokenRequired)\r\n if (errorCode === ArcGisErrorCode.TokenRequired || errorCode === ArcGisErrorCode.MissingPermissions) {\r\n return (source.userName || source.password) ? {status: MapLayerSourceStatus.InvalidCredentials} : {status: MapLayerSourceStatus.RequireAuth};\r\n } else if (errorCode === ArcGisErrorCode.InvalidCredentials)\r\n return { status: MapLayerSourceStatus.InvalidCredentials};\r\n }\r\n\r\n // Check this service support the expected queries\r\n let hasCapabilities = false;\r\n let capsArray: string[] = [];\r\n if (json.capabilities && typeof json.capabilities === \"string\" ) {\r\n const capabilities: string = json.capabilities;\r\n capsArray = capabilities.split(\",\").map((entry) => entry.toLowerCase());\r\n\r\n const filtered = capsArray.filter((element, _index, _array) => capabilitiesFilter.includes(element));\r\n hasCapabilities = (filtered.length === capabilitiesFilter.length);\r\n }\r\n if (!hasCapabilities) {\r\n return { status: MapLayerSourceStatus.InvalidFormat};\r\n }\r\n\r\n // Only EPSG:3857 is supported with pre-rendered tiles.\r\n if (json.tileInfo && capsArray.includes(\"tilesonly\") && !ArcGisUtilities.isEpsg3857Compatible(json.tileInfo)) {\r\n return { status: MapLayerSourceStatus.InvalidCoordinateSystem};\r\n }\r\n\r\n let subLayers;\r\n if (json.layers) {\r\n\r\n subLayers = new Array<MapSubLayerProps>();\r\n\r\n for (const layer of json.layers) {\r\n const parent = layer.parentLayerId < 0 ? undefined : layer.parentLayerId;\r\n const children = Array.isArray(layer.subLayerIds) ? layer.subLayerIds : undefined;\r\n subLayers.push({ name: layer.name, visible: layer.defaultVisibility !== false, id: layer.id, parent, children });\r\n }\r\n }\r\n return { status: MapLayerSourceStatus.Valid, subLayers };\r\n }\r\n\r\n /** Validate MapService tiling metadata and checks if the tile tree is 'Google Maps' compatible. */\r\n public static isEpsg3857Compatible(tileInfo: any) {\r\n if (tileInfo.spatialReference?.latestWkid !== 3857 || !Array.isArray(tileInfo.lods))\r\n return false;\r\n\r\n const zeroLod = tileInfo.lods[0];\r\n return zeroLod.level === 0 && Math.abs(zeroLod.resolution - 156543.03392800014) < .001;\r\n }\r\n\r\n private static _serviceCache = new Map<string, ArcGISServiceMetadata|undefined>();\r\n\r\n /**\r\n * Fetches an ArcGIS service metadata, and returns its JSON representation.\r\n * If an access client has been configured for the specified formatId,\r\n * it will be used to apply required security token.\r\n * By default, response for each URL are cached.\r\n * @param url URL of the ArcGIS service\r\n * @param formatId Format ID of the service\r\n * @param userName Username to use for legacy token based security\r\n * @param password Password to use for legacy token based security\r\n * @param ignoreCache Flag to skip cache lookup (i.e. force a new server request)\r\n * @param requireToken Flag to indicate if a token is required\r\n * @throws [[MapLayerUntrustedOriginError]] if an NTLM/Negotiate challenge could not be answered because\r\n * the URL's origin is not trusted (see [[MapLayerFormatRegistry.restrictCredentialsToTrustedOrigins]]);\r\n * [[MapLayerAuthenticationFailedError]] if a registered [[MapLayerFetchHandler]] reported an\r\n * authentication failure;\r\n * all other errors are caught and reported by returning `undefined`.\r\n */\r\n\r\n public static async getServiceJson(args: ArcGisGetServiceJsonArgs): Promise<ArcGISServiceMetadata|undefined> {\r\n const {url, layerUrl = url, layerProperties, formatId, userName, password, queryParams, ignoreCache, requireToken} = args;\r\n const accessClient = IModelApp.mapLayerFormatRegistry?.getAccessClient(formatId);\r\n // The cache is keyed by URL only, so responses customized by the fetch handler (e.g.\r\n // header-authenticated) must not be shared with or served from differently-customized requests.\r\n const hasFetchHandler = (IModelApp.mapLayerFormatRegistry?.mapLayerFetchHandlers.length ?? 0) > 0;\r\n if (!ignoreCache && !hasFetchHandler) {\r\n const cached = ArcGisUtilities._serviceCache.get(url);\r\n if (cached !== undefined)\r\n return cached;\r\n }\r\n const appendParams = (urlObj: URL, params?: {[key: string]: string}) => {\r\n if (params) {\r\n Object.keys(params).forEach((paramKey) => {\r\n if (!urlObj.searchParams.has(paramKey))\r\n urlObj.searchParams.append(paramKey, params[paramKey]);\r\n });\r\n }\r\n };\r\n\r\n const createUrlObj = () => {\r\n const tmpUrl = new URL(url);\r\n tmpUrl.searchParams.append(\"f\", \"json\");\r\n appendParams(tmpUrl, queryParams);\r\n return tmpUrl;\r\n };\r\n\r\n // Routes each request through the registered fetch handler (if any); handler failures propagate.\r\n // The NTLM/SSO retry applies only to the initial request, and never to sends the handler modified.\r\n const requestJson = async (target: URL, allowSsoRetry: boolean): Promise<MapLayerFetchResult> => {\r\n return fetchMapLayerRequest({\r\n url: target.toString(),\r\n formatId,\r\n layerUrl,\r\n layerProperties,\r\n send: async (request, credentialed) => {\r\n // Sends the handler modified may carry injected secrets: same redirect policy as credentialed ones.\r\n let rsp = await fetch(request.url, { method: \"GET\", headers: request.headers, redirect: credentialed ? credentialedFetchRedirect() : undefined });\r\n if (allowSsoRetry && rsp.status === 401 && !requireToken && !credentialed && headersIncludeAuthMethod(rsp.headers, [\"ntlm\", \"negotiate\"])) {\r\n // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.\r\n const challengedUrl = rsp.url || request.url;\r\n if (!IModelApp.mapLayerFormatRegistry.isSsoAllowed(challengedUrl))\r\n throw new MapLayerUntrustedOriginError(challengedUrl);\r\n\r\n IModelApp.mapLayerFormatRegistry.logUntrustedOriginUse(challengedUrl);\r\n\r\n // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).\r\n rsp = await fetch(challengedUrl, {\r\n method: \"GET\",\r\n credentials: \"include\",\r\n redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? \"error\" : undefined,\r\n });\r\n }\r\n return rsp;\r\n },\r\n });\r\n };\r\n\r\n let accessTokenRequired = false;\r\n try {\r\n let tmpUrl = createUrlObj();\r\n\r\n // In some cases, caller might already know token is required, so append it immediately\r\n if (requireToken) {\r\n if (accessClient) {\r\n accessTokenRequired = true;\r\n await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, {mapLayerUrl: new URL(url), userName, password});\r\n }\r\n }\r\n let { response, managedByHandler } = await requestJson(tmpUrl, true);\r\n\r\n // Append security token when corresponding error code is returned by ArcGIS service\r\n const errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);\r\n if (!accessTokenRequired\r\n && (errorCode === ArcGisErrorCode.TokenRequired || errorCode === ArcGisErrorCode.MissingPermissions) ) {\r\n accessTokenRequired = true;\r\n // If token required\r\n if (accessClient) {\r\n tmpUrl = createUrlObj();\r\n await ArcGisUtilities.appendSecurityToken(tmpUrl, accessClient, {mapLayerUrl: new URL(url), userName, password});\r\n ({ response, managedByHandler } = await requestJson(tmpUrl, false));\r\n }\r\n }\r\n\r\n const json = await response.json();\r\n // Classified from the parsed body regardless of the Content-Type the server labelled it with.\r\n const contentErrorCode: ArcGisErrorCode | undefined = json?.error?.code;\r\n const info: ArcGISServiceMetadata = {content: json, accessTokenRequired, errorCode: managedByHandler ? undefined : contentErrorCode};\r\n // Cache the response only if it doesn't contain any error, and never when a fetch handler managed it or\r\n // is registered (the cache is keyed by URL only, so protected data must not be cached).\r\n if (!hasFetchHandler && !managedByHandler)\r\n ArcGisUtilities._serviceCache.set(url, (contentErrorCode === undefined ? info : undefined));\r\n return info; // Always return json, even though it contains an error code.\r\n\r\n } catch (err) {\r\n ArcGisUtilities._serviceCache.set(url, undefined);\r\n if (err instanceof MapLayerUntrustedOriginError || err instanceof MapLayerAuthenticationFailedError)\r\n throw err; // propagate so callers can report the blocked origin / authentication failure\r\n return undefined;\r\n }\r\n }\r\n\r\n /** Read a response from ArcGIS server and check for error code in the response. */\r\n public static async checkForResponseErrorCode(response: Response) {\r\n const tmpResponse = response;\r\n if (response.headers && tmpResponse.headers.get(\"content-type\")?.toLowerCase().includes(\"json\")) {\r\n\r\n try {\r\n // Note:\r\n // Since response stream can only be read once (i.e. calls to .json() method)\r\n // we have to clone the response object in order to check for potential error code,\r\n // but still keep the response stream as unread.\r\n const clonedResponse = tmpResponse.clone();\r\n const json = await clonedResponse.json();\r\n if (json?.error?.code !== undefined)\r\n return json?.error?.code as number;\r\n } catch { }\r\n\r\n }\r\n return undefined;\r\n }\r\n\r\n // return the appended access token if available.\r\n public static async appendSecurityToken(url: URL, accessClient: MapLayerAccessClient, accessTokenParams: MapLayerAccessTokenParams): Promise<MapLayerAccessToken|undefined> {\r\n\r\n // Append security token if available\r\n let accessToken: MapLayerAccessToken|undefined;\r\n try {\r\n accessToken = await accessClient.getAccessToken(accessTokenParams);\r\n } catch {}\r\n\r\n if (accessToken?.token) {\r\n url.searchParams.append(\"token\", accessToken.token);\r\n return accessToken;\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Compute scale, resolution values for requested zoom levels (WSG 84)\r\n * Use a scale of 96 dpi for Google Maps scales\r\n * Based on this article: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale\r\n * @param startZoom Zoom level where scales begins to be computed\r\n * @param endZoom Zoom level where scales ends to be computed\r\n * @param latitude Latitude in degrees to use to compute scales (i.e 0 for Equator)\r\n * @param tileSize Size of a tile in pixels (i.e 256)\r\n * @param screenDpi Monitor resolution in dots per inch (i.e. typically 96dpi is used by Google Maps)\r\n * @returns An array containing resolution and scale values for each requested zoom level\r\n */\r\n public static computeZoomLevelsScales(startZoom: number = 0, endZoom: number = 20, latitude: number = 0, tileSize: number = 256, screenDpi = 96): {zoom: number, resolution: number, scale: number}[] {\r\n // Note: There is probably a more direct way to compute this, but I prefer to go for a simple and well documented approach.\r\n if (startZoom <0 || endZoom < startZoom || tileSize < 0 || screenDpi < 1 || latitude < -90 || latitude > 90)\r\n return [];\r\n\r\n const inchPerMeter = 1 / 0.0254;\r\n const results: {zoom: number, resolution: number, scale: number}[] = [];\r\n const equatorLength = Constant.earthRadiusWGS84.equator * 2 * Math.PI;\r\n const zoom0Resolution = equatorLength / tileSize; // in meters per pixel\r\n\r\n const cosLatitude = Math.cos(latitude);\r\n for (let zoom = startZoom; zoom<= endZoom; zoom++) {\r\n const resolution = zoom0Resolution * cosLatitude / Math.pow(2, zoom);\r\n const scale = screenDpi * inchPerMeter * resolution;\r\n results.push({zoom, resolution, scale});\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Match the provided minScale, maxScale values to corresponding wgs84 zoom levels\r\n * @param defaultMaxLod Value of the last LOD (i.e 22)\r\n * @param tileSize Size of a tile in pixels (i.e 256)\r\n * @param minScale Minimum scale value that needs to be matched to a LOD level\r\n * @param maxScale Maximum scale value that needs to be matched to a LOD level\r\n * @returns minLod: LOD value matching minScale, maxLod: LOD value matching maxScale\r\n */\r\n public static getZoomLevelsScales( defaultMaxLod: number, tileSize: number, minScale?: number, maxScale?: number, tolerance: number = 0): {minLod?: number, maxLod?: number} {\r\n\r\n let minLod: number|undefined, maxLod: number|undefined;\r\n\r\n const zoomScales = ArcGisUtilities.computeZoomLevelsScales(0, defaultMaxLod, 0 /* latitude 0 = Equator*/, tileSize);\r\n\r\n if (zoomScales.length > 0) {\r\n\r\n if (minScale) {\r\n minLod = 0;\r\n // We are looking for the largest scale value with a scale value smaller than minScale\r\n for (; minLod < zoomScales.length && (zoomScales[minLod].scale > minScale && Math.abs(zoomScales[minLod].scale - minScale) > tolerance); minLod++)\r\n ;\r\n\r\n }\r\n\r\n if (maxScale) {\r\n maxLod = defaultMaxLod;\r\n // We are looking for the smallest scale value with a value greater than maxScale\r\n for (; maxLod >= 0 && zoomScales[maxLod].scale < maxScale && Math.abs(zoomScales[maxLod].scale - maxScale) > tolerance; maxLod--)\r\n ;\r\n }\r\n }\r\n return {minLod, maxLod};\r\n }\r\n\r\n}\r\n"]}
@@ -18,6 +18,8 @@ export declare abstract class ArcGISImageryProvider extends MapLayerImageryProvi
18
18
  */
19
19
  protected _accessTokenRequired: boolean;
20
20
  protected _querySupported: boolean;
21
+ /** Responses of [[fetch]] managed by a fetch handler (see [[MapLayerFetchResult.managedByHandler]]). */
22
+ private readonly _handlerManagedFetchResponses;
21
23
  get supportsMapFeatureInfo(): boolean;
22
24
  constructor(settings: ImageMapLayerSettings, usesCachedTiles: boolean);
23
25
  /** Updates the accessClient token state whenever the status of the provider change.
@@ -28,6 +30,16 @@ export declare abstract class ArcGISImageryProvider extends MapLayerImageryProvi
28
30
  * This wrapper maintains token state and should be used instead of the the ArcGisUtilities version.
29
31
  */
30
32
  protected getServiceJson(): Promise<ArcGISServiceMetadata | undefined>;
33
+ /** The default send for [[fetch]]: legacy redirect policy and origin-trust checks for one target.
34
+ * The NTLM/SSO retry applies only when `allowSsoRetry` (the initial request of an operation), and
35
+ * never to sends a fetch handler modified.
36
+ */
37
+ private sendArcGisRequest;
38
+ /** Routes one request - initial, HTML fallback or token retry - through the registered fetch handler
39
+ * (if any), with fresh headers per request so injected values are neither accumulated nor exposed to
40
+ * cross-origin redirects.
41
+ */
42
+ private requestViaHandler;
31
43
  /**
32
44
  * Make a request to an ArcGIS service using the provided URL and init parameters.
33
45
  * @param url URL to query
@@ -35,5 +47,7 @@ export declare abstract class ArcGISImageryProvider extends MapLayerImageryProvi
35
47
  * Refer to fetch API for more details (https://developer.mozilla.org/en-US/docs/Web/API/fetch)
36
48
  */
37
49
  protected fetch(url: URL, options?: RequestInit): Promise<Response>;
50
+ /** Also true for responses of [[fetch]] a handler returned as its own. */
51
+ protected isManagedByHandler(response: Response): boolean;
38
52
  }
39
53
  //# sourceMappingURL=ArcGISImageryProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ArcGISImageryProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/tile/map/ImageryProviders/ArcGISImageryProvider.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAmB,qBAAqB,EAAmB,oBAAoB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,6BAA6B,EAAgC,MAAM,2BAA2B,CAAC;AAKrO;;;;;;GAMG;AACH,8BAAsB,qBAAsB,SAAQ,uBAAuB;IAEzE,SAAS,CAAC,aAAa,EAAE,oBAAoB,GAAC,SAAS,CAAC;IACxD,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,GAAC,SAAS,CAAC;IAE1D;;MAEE;IACF,SAAS,CAAC,oBAAoB,UAAS;IAEvC,SAAS,CAAC,eAAe,UAAS;IAElC,IAAoB,sBAAsB,YAAkC;gBAEhE,QAAQ,EAAE,qBAAqB,EAAE,eAAe,EAAE,OAAO;IAKrE;SACK;cACc,eAAe,CAAC,MAAM,EAAE,6BAA6B;IAaxE;;;MAGE;cACc,cAAc;IAyB9B;;;;;OAKG;cACa,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW;CA2HtD"}
1
+ {"version":3,"file":"ArcGISImageryProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/tile/map/ImageryProviders/ArcGISImageryProvider.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAmB,qBAAqB,EAAoE,oBAAoB,EAAE,mBAAmB,EAA0D,uBAAuB,EAAE,6BAA6B,EAAiD,MAAM,2BAA2B,CAAC;AAK/V;;;;;;GAMG;AACH,8BAAsB,qBAAsB,SAAQ,uBAAuB;IAEzE,SAAS,CAAC,aAAa,EAAE,oBAAoB,GAAC,SAAS,CAAC;IACxD,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,GAAC,SAAS,CAAC;IAE1D;;MAEE;IACF,SAAS,CAAC,oBAAoB,UAAS;IAEvC,SAAS,CAAC,eAAe,UAAS;IAElC,wGAAwG;IACxG,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAA2B;IAEzE,IAAoB,sBAAsB,YAAkC;gBAEhE,QAAQ,EAAE,qBAAqB,EAAE,eAAe,EAAE,OAAO;IAKrE;SACK;cACc,eAAe,CAAC,MAAM,EAAE,6BAA6B;IAaxE;;;MAGE;cACc,cAAc;IA2B9B;;;OAGG;YACW,iBAAiB;IAmC/B;;;OAGG;YACW,iBAAiB;IAW/B;;;;;OAKG;cACa,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,WAAW;IA+GrD,0EAA0E;cACvD,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;CAGnE"}
@@ -5,7 +5,7 @@
5
5
  /** @packageDocumentation
6
6
  * @module Tiles
7
7
  */
8
- import { ArcGisErrorCode, ArcGisUtilities, MapLayerImageryProvider, MapLayerImageryProviderStatus, MapLayerUntrustedOriginError } from "../../../../tile/internal";
8
+ import { ArcGisErrorCode, ArcGisUtilities, credentialedFetchRedirect, fetchMapLayerRequest, MapLayerAuthenticationFailedError, MapLayerImageryProvider, MapLayerImageryProviderStatus, MapLayerUntrustedOriginError } from "../../../../tile/internal";
9
9
  import { IModelApp } from "../../../../IModelApp";
10
10
  import { NotifyMessageDetails, OutputMessagePriority } from "../../../../NotificationManager";
11
11
  import { headersIncludeAuthMethod } from "../../../../request/utils";
@@ -24,6 +24,8 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
24
24
  */
25
25
  _accessTokenRequired = false;
26
26
  _querySupported = false;
27
+ /** Responses of [[fetch]] managed by a fetch handler (see [[MapLayerFetchResult.managedByHandler]]). */
28
+ _handlerManagedFetchResponses = new WeakSet();
27
29
  get supportsMapFeatureInfo() { return this._querySupported; }
28
30
  constructor(settings, usesCachedTiles) {
29
31
  super(settings, usesCachedTiles);
@@ -48,11 +50,13 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
48
50
  async getServiceJson() {
49
51
  let metadata;
50
52
  try {
51
- metadata = await ArcGisUtilities.getServiceJson({ url: this._settings.url, formatId: this._settings.formatId, userName: this._settings.userName, password: this._settings.password, queryParams: this._settings.collectQueryParams() });
53
+ metadata = await ArcGisUtilities.getServiceJson({ url: this._settings.url, layerProperties: this._settings.properties, formatId: this._settings.formatId, userName: this._settings.userName, password: this._settings.password, queryParams: this._settings.collectQueryParams() });
52
54
  }
53
55
  catch (err) {
54
56
  if (err instanceof MapLayerUntrustedOriginError)
55
57
  this.reportBlockedOrigin(err.url);
58
+ else if (err instanceof MapLayerAuthenticationFailedError)
59
+ this.setStatus(MapLayerImageryProviderStatus.RequireAuth);
56
60
  }
57
61
  if (metadata && metadata.accessTokenRequired) {
58
62
  const accessClient = IModelApp.mapLayerFormatRegistry.getAccessClient(this._settings.formatId);
@@ -70,6 +74,56 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
70
74
  }
71
75
  return metadata;
72
76
  }
77
+ /** The default send for [[fetch]]: legacy redirect policy and origin-trust checks for one target.
78
+ * The NTLM/SSO retry applies only when `allowSsoRetry` (the initial request of an operation), and
79
+ * never to sends a fetch handler modified.
80
+ */
81
+ async sendArcGisRequest(request, credentialed, allowSsoRetry, options) {
82
+ const includeCredentials = this.includeUserCredentials(request.url);
83
+ let rsp = await fetch(request.url, {
84
+ ...options,
85
+ headers: request.headers,
86
+ credentials: includeCredentials ? "include" : undefined,
87
+ // Sends the handler modified may carry injected secrets: same redirect policy as credentialed ones.
88
+ redirect: (includeCredentials || credentialed) ? (credentialedFetchRedirect() ?? options?.redirect) : options?.redirect,
89
+ });
90
+ if (includeCredentials || credentialed)
91
+ this.checkCredentialedRedirect(request.url, rsp);
92
+ if (allowSsoRetry && rsp.status === 401 && !this._lastAccessToken && !credentialed && headersIncludeAuthMethod(rsp.headers, ["ntlm", "negotiate"])) {
93
+ // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.
94
+ const challengedUrl = rsp.url || request.url;
95
+ if (this.isSsoAllowed(challengedUrl)) {
96
+ // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).
97
+ this.logUntrustedOriginUse(challengedUrl);
98
+ rsp = await fetch(challengedUrl, {
99
+ ...options,
100
+ credentials: "include",
101
+ redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? "error" : undefined,
102
+ });
103
+ if (rsp.status === 200) {
104
+ this.recordSsoSucceeded(challengedUrl); // avoid going through 401 challenges over and over for this origin
105
+ }
106
+ }
107
+ else {
108
+ this.reportBlockedOrigin(challengedUrl);
109
+ }
110
+ }
111
+ return rsp;
112
+ }
113
+ /** Routes one request - initial, HTML fallback or token retry - through the registered fetch handler
114
+ * (if any), with fresh headers per request so injected values are neither accumulated nor exposed to
115
+ * cross-origin redirects.
116
+ */
117
+ async requestViaHandler(target, allowSsoRetry, options) {
118
+ return fetchMapLayerRequest({
119
+ url: target.toString(),
120
+ formatId: this._settings.formatId,
121
+ layerUrl: this._settings.url,
122
+ layerProperties: this._settings.properties,
123
+ headers: new Headers(options?.headers),
124
+ send: async (request, credentialed) => this.sendArcGisRequest(request, credentialed, allowSsoRetry, options),
125
+ });
126
+ }
73
127
  /**
74
128
  * Make a request to an ArcGIS service using the provided URL and init parameters.
75
129
  * @param url URL to query
@@ -78,19 +132,24 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
78
132
  */
79
133
  async fetch(url, options) {
80
134
  let errorCode;
81
- const urlObj = new URL(url);
82
135
  const queryParams = this._settings.collectQueryParams();
83
- Object.keys(queryParams).forEach((paramKey) => {
84
- if (!urlObj.searchParams.has(paramKey))
85
- urlObj.searchParams.append(paramKey, queryParams[paramKey]);
86
- });
87
- if (this._accessTokenRequired && this._accessClient) {
88
- this._lastAccessToken = await ArcGisUtilities.appendSecurityToken(urlObj, this._accessClient, {
89
- mapLayerUrl: new URL(this._settings.url),
90
- portal: typeof this._settings.properties?.portal === "string" ? this._settings.properties.portal : undefined,
91
- userName: this._settings.userName,
92
- password: this._settings.password
136
+ const buildRequestUrl = () => {
137
+ const requestUrl = new URL(url);
138
+ Object.keys(queryParams).forEach((paramKey) => {
139
+ if (!requestUrl.searchParams.has(paramKey))
140
+ requestUrl.searchParams.append(paramKey, queryParams[paramKey]);
93
141
  });
142
+ return requestUrl;
143
+ };
144
+ const accessTokenParams = {
145
+ mapLayerUrl: new URL(this._settings.url),
146
+ portal: typeof this._settings.properties?.portal === "string" ? this._settings.properties.portal : undefined,
147
+ userName: this._settings.userName,
148
+ password: this._settings.password,
149
+ };
150
+ const urlObj = buildRequestUrl();
151
+ if (this._accessTokenRequired && this._accessClient) {
152
+ this._lastAccessToken = await ArcGisUtilities.appendSecurityToken(urlObj, this._accessClient, accessTokenParams);
94
153
  }
95
154
  // We want to complete the first request before letting other requests go;
96
155
  // this done to avoid flooding server with requests missing credentials
@@ -99,35 +158,9 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
99
158
  else
100
159
  await this._firstRequestPromise;
101
160
  let response;
161
+ let managedByHandler = false;
102
162
  try {
103
- const requestUrl = urlObj.toString();
104
- const includeCredentials = this.includeUserCredentials(requestUrl);
105
- response = await fetch(urlObj, {
106
- ...options,
107
- credentials: includeCredentials ? "include" : undefined,
108
- redirect: includeCredentials ? this.credentialedRedirect : options?.redirect,
109
- });
110
- if (includeCredentials)
111
- this.checkCredentialedRedirect(requestUrl, response);
112
- if (response.status === 401 && !this._lastAccessToken && headersIncludeAuthMethod(response.headers, ["ntlm", "negotiate"])) {
113
- // fetch follows redirects transparently, so trust decisions target the final (post-redirect) URL.
114
- const challengedUrl = response.url || requestUrl;
115
- if (this.isSsoAllowed(challengedUrl)) {
116
- // We got a http 401 challenge, lets try again with SSO enabled (i.e. Windows Authentication).
117
- this.logUntrustedOriginUse(challengedUrl);
118
- response = await fetch(challengedUrl, {
119
- ...options,
120
- credentials: "include",
121
- redirect: IModelApp.mapLayerFormatRegistry.restrictCredentialsToTrustedOrigins ? "error" : undefined,
122
- });
123
- if (response.status === 200) {
124
- this.recordSsoSucceeded(challengedUrl); // avoid going through 401 challenges over and over for this origin
125
- }
126
- }
127
- else {
128
- this.reportBlockedOrigin(challengedUrl);
129
- }
130
- }
163
+ ({ response, managedByHandler } = await this.requestViaHandler(urlObj, true, options));
131
164
  if ((this._lastAccessToken && response.status === 400)
132
165
  || response.headers.get("content-type")?.toLowerCase().includes("htm")) {
133
166
  // For some reasons when we make a request with the fetch() api and there is a token error
@@ -138,7 +171,7 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
138
171
  if (this._lastAccessToken && this._accessTokenRequired)
139
172
  tmpUrl.searchParams.append("token", this._lastAccessToken.token);
140
173
  tmpUrl.searchParams.append("f", "json");
141
- response = await fetch(tmpUrl.toString(), options);
174
+ ({ response, managedByHandler } = await this.requestViaHandler(tmpUrl, false, options));
142
175
  }
143
176
  errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);
144
177
  if (errorCode !== undefined &&
@@ -150,19 +183,21 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
150
183
  // Token might have expired, make a second attempt by forcing new token.
151
184
  if (this._accessClient?.invalidateToken !== undefined && this._lastAccessToken !== undefined)
152
185
  this._accessClient.invalidateToken(this._lastAccessToken);
153
- const urlObj2 = new URL(url);
186
+ // A fresh URL: the expired token must not remain as a first `token` parameter.
187
+ const retryUrl = buildRequestUrl();
154
188
  if (this._accessClient) {
155
189
  try {
156
- this._lastAccessToken = await ArcGisUtilities.appendSecurityToken(urlObj, this._accessClient, { mapLayerUrl: urlObj, userName: this._settings.userName, password: this._settings.password });
190
+ this._lastAccessToken = await ArcGisUtilities.appendSecurityToken(retryUrl, this._accessClient, accessTokenParams);
157
191
  }
158
192
  catch {
159
193
  }
160
194
  }
161
195
  // Make a second attempt with refreshed token
162
- response = await fetch(urlObj2.toString(), options);
196
+ ({ response, managedByHandler } = await this.requestViaHandler(retryUrl, false, options));
163
197
  errorCode = await ArcGisUtilities.checkForResponseErrorCode(response);
164
198
  }
165
- if (errorCode !== undefined &&
199
+ // An error code in a response managed by the fetch handler is not classified here.
200
+ if (!managedByHandler && errorCode !== undefined &&
166
201
  (errorCode === ArcGisErrorCode.TokenRequired
167
202
  || errorCode === ArcGisErrorCode.InvalidToken
168
203
  || errorCode === ArcGisErrorCode.MissingPermissions)) {
@@ -177,12 +212,23 @@ export class ArcGISImageryProvider extends MapLayerImageryProvider {
177
212
  }
178
213
  }
179
214
  }
215
+ catch (error) {
216
+ if (error instanceof MapLayerAuthenticationFailedError)
217
+ this.reportAuthenticationFailure();
218
+ throw error;
219
+ }
180
220
  finally {
181
221
  this.onFirstRequestCompleted.raiseEvent();
182
222
  }
183
223
  if (response === undefined)
184
224
  throw new Error("fetch call failed");
225
+ if (managedByHandler)
226
+ this._handlerManagedFetchResponses.add(response);
185
227
  return response;
186
228
  }
229
+ /** Also true for responses of [[fetch]] a handler returned as its own. */
230
+ isManagedByHandler(response) {
231
+ return this._handlerManagedFetchResponses.has(response) || super.isManagedByHandler(response);
232
+ }
187
233
  }
188
234
  //# sourceMappingURL=ArcGISImageryProvider.js.map