diff --git a/demos/tree-shaking-rollup/README.md b/demos/tree-shaking-rollup/README.md index 9cb71ea3f4..2cae0e4d49 100644 --- a/demos/tree-shaking-rollup/README.md +++ b/demos/tree-shaking-rollup/README.md @@ -4,6 +4,6 @@ This demo shows how to have rollup [tree shake](https://rollupjs.org/guide/en#tr 1. Make sure you run `npm run bootstrap` in the root folder to setup the dependencies 1. cd into `/demos/tree-shaking-rollup/` -1. Run `npm run build` +1. Run `npm run build:app` diff --git a/demos/tree-shaking-rollup/package.json b/demos/tree-shaking-rollup/package.json index 092aba7a1b..e768147bf1 100644 --- a/demos/tree-shaking-rollup/package.json +++ b/demos/tree-shaking-rollup/package.json @@ -5,7 +5,7 @@ "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "rollup -c" + "build:app": "rollup -c" }, "keywords": [], "author": "", diff --git a/demos/tree-shaking-webpack/README.md b/demos/tree-shaking-webpack/README.md index 0fce2c906f..6f5d9cd26e 100644 --- a/demos/tree-shaking-webpack/README.md +++ b/demos/tree-shaking-webpack/README.md @@ -4,6 +4,6 @@ This demo shows how to have webpack [tree shake](https://rollupjs.org/guide/en#t 1. Make sure you run `npm run bootstrap` in the root folder to setup the dependencies 1. cd into `/demos/tree-shaking-webpack/` -1. Run `npm run build` +1. Run `npm run build:app` diff --git a/demos/tree-shaking-webpack/package.json b/demos/tree-shaking-webpack/package.json index 43a7e824db..3cf18a6b20 100644 --- a/demos/tree-shaking-webpack/package.json +++ b/demos/tree-shaking-webpack/package.json @@ -5,7 +5,7 @@ "description": "", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "webpack" + "build:app": "webpack" }, "keywords": [], "author": "", diff --git a/demos/vue/package.json b/demos/vue/package.json index 91e45203f3..cb848eacc3 100644 --- a/demos/vue/package.json +++ b/demos/vue/package.json @@ -7,7 +7,7 @@ "private": true, "scripts": { "serve": "vue-cli-service serve", - "build": "vue-cli-service build", + "build:app": "vue-cli-service build", "lint": "vue-cli-service lint", "start": "npm run serve" }, diff --git a/package-lock.json b/package-lock.json index 14b03ae763..d26ecfc2ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5242,21 +5242,21 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true @@ -5274,14 +5274,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -5299,35 +5299,35 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -5344,21 +5344,21 @@ }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -5368,14 +5368,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -5407,7 +5407,7 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true @@ -5424,7 +5424,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -5434,7 +5434,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -5445,21 +5445,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -5469,14 +5469,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -5486,7 +5486,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true @@ -5514,7 +5514,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -5524,7 +5524,7 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true @@ -5562,7 +5562,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -5591,7 +5591,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -5604,21 +5604,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -5628,21 +5628,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -5653,14 +5653,14 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true @@ -5680,7 +5680,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -5689,7 +5689,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -5722,14 +5722,14 @@ }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true @@ -5743,21 +5743,21 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -5769,7 +5769,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -5779,7 +5779,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -5789,7 +5789,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -5812,7 +5812,7 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true @@ -5829,7 +5829,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true diff --git a/packages/arcgis-rest-auth/test/UserSession.test.ts b/packages/arcgis-rest-auth/test/UserSession.test.ts index 96644ef068..e19b76aa0e 100644 --- a/packages/arcgis-rest-auth/test/UserSession.test.ts +++ b/packages/arcgis-rest-auth/test/UserSession.test.ts @@ -456,14 +456,6 @@ describe("UserSession", () => { } }); - fetchMock.post("https://gis.city.gov/sharing/generateToken", { - error: { - code: 400, - message: "Unable to generate token", - details: ["Unable to generate token for this server"] - } - }); - session .getToken( "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query" @@ -491,6 +483,17 @@ describe("UserSession", () => { fullVersion: "10.5.1.120" }); + fetchMock.post( + "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query", + { + error: { + code: 499, + message: "Token Required", + details: [] + } + } + ); + request( "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query", { @@ -513,7 +516,7 @@ describe("UserSession", () => { }); }); - it("should throw an ArcGISAuthError when no owning system is advertised", done => { + it("should not throw an ArcGISAuthError when the unfederated service is public", done => { const session = new UserSession({ clientId: "id", token: "token", @@ -523,24 +526,31 @@ describe("UserSession", () => { fetchMock.post("https://gisservices.city.gov/public/rest/info", { currentVersion: 10.51, - fullVersion: "10.5.1.120", - authInfo: { - isTokenBasedSecurity: true, - tokenServicesUrl: "https://gis.city.gov/sharing/generateToken" - } + fullVersion: "10.5.1.120" }); - session - .getToken( - "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query" - ) - .catch(e => { - expect(e.name).toEqual(ErrorTypes.ArcGISAuthError); - expect(e.code).toEqual("NOT_FEDERATED"); - expect(e.message).toEqual( - "NOT_FEDERATED: https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query is not federated with any portal and is not explicitly trusted." - ); + fetchMock.post( + "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query", + { + count: 123 + } + ); + + request( + "https://gisservices.city.gov/public/rest/services/trees/FeatureServer/0/query", + { + authentication: session, + params: { + returnCount: true + } + } + ) + .then(res => { + expect(res.count).toEqual(123); done(); + }) + .catch(e => { + fail(e); }); }); }); diff --git a/packages/arcgis-rest-request/src/request.ts b/packages/arcgis-rest-request/src/request.ts index c73af84665..0bd838530e 100644 --- a/packages/arcgis-rest-request/src/request.ts +++ b/packages/arcgis-rest-request/src/request.ts @@ -6,6 +6,7 @@ import { encodeQueryString } from "./utils/encode-query-string"; import { requiresFormData } from "./utils/process-params"; import { checkForErrors } from "./utils/check-for-errors"; import { ArcGISRequestError } from "./utils/ArcGISRequestError"; +import { ArcGISAuthError } from "./utils/ArcGISAuthError"; import { IRequestOptions } from "./utils/IRequestOptions"; import { IParams } from "./utils/IParams"; import { warn } from "./utils/warn"; @@ -130,6 +131,8 @@ export function request( ...options.params }; + let originalAuthError: ArcGISAuthError = null; + const fetchOptions: RequestInit = { method: httpMethod, /* ensures behavior mimics XMLHttpRequest. @@ -139,11 +142,20 @@ export function request( return (authentication ? authentication.getToken(url, { fetch: options.fetch }).catch(err => { - /* if necessary, append original request url and - requestOptions to the error thrown by getToken() */ + /** + * append original request url and requestOptions + * to the error thrown by getToken() + * to assist with retrying + */ err.url = url; err.options = options; - throw err; + /** + * if an attempt is made to talk to an unfederated server + * first try the request anonymously. if a 'token required' + * error is thrown, throw the UNFEDERATED error then. + */ + originalAuthError = err; + return Promise.resolve(""); }) : Promise.resolve("") ) @@ -230,7 +242,29 @@ export function request( }) .then(data => { if ((params.f === "json" || params.f === "geojson") && !rawResponse) { - return checkForErrors(data, url, params, options); + const response = checkForErrors( + data, + url, + params, + options, + originalAuthError + ); + if (originalAuthError) { + /* if the request was made to an unfederated service that + didnt require authentication, add the base url and a dummy token + to the list of trusted servers to avoid another federation check + in the event of a repeat request */ + const truncatedUrl: string = url + .toLowerCase() + .split(/\/rest(\/admin)?\/services\//)[0]; + (options.authentication as any).trustedServers[truncatedUrl] = { + token: [], + // default to 24 hours + expires: new Date(Date.now() + 86400 * 1000) + }; + originalAuthError = null; + } + return response; } else { return data; } diff --git a/packages/arcgis-rest-request/src/utils/check-for-errors.ts b/packages/arcgis-rest-request/src/utils/check-for-errors.ts index 6604ada9d8..429d2fb031 100644 --- a/packages/arcgis-rest-request/src/utils/check-for-errors.ts +++ b/packages/arcgis-rest-request/src/utils/check-for-errors.ts @@ -16,7 +16,8 @@ export function checkForErrors( response: any, url?: string, params?: IParams, - options?: IRequestOptions + options?: IRequestOptions, + originalAuthError?: ArcGISAuthError ): any { // this is an error message from billing.arcgis.com backend if (response.code >= 400) { @@ -35,7 +36,11 @@ export function checkForErrors( messageCode === "GWM_0003" || (code === 400 && message === "Unable to generate token.") ) { - throw new ArcGISAuthError(message, errorCode, response, url, options); + if (originalAuthError) { + throw originalAuthError; + } else { + throw new ArcGISAuthError(message, errorCode, response, url, options); + } } throw new ArcGISRequestError(message, errorCode, response, url, options);