@esri/arcgis-rest-developer-credentials 1.1.0 → 2.1.0

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 (65) hide show
  1. package/dist/bundled/developer-credentials.esm.js +254 -182
  2. package/dist/bundled/developer-credentials.esm.js.map +1 -1
  3. package/dist/bundled/developer-credentials.esm.min.js +3 -3
  4. package/dist/bundled/developer-credentials.esm.min.js.map +1 -1
  5. package/dist/bundled/developer-credentials.umd.js +257 -182
  6. package/dist/bundled/developer-credentials.umd.js.map +1 -1
  7. package/dist/bundled/developer-credentials.umd.min.js +3 -3
  8. package/dist/bundled/developer-credentials.umd.min.js.map +1 -1
  9. package/dist/cjs/createApiKey.js +37 -12
  10. package/dist/cjs/createApiKey.js.map +1 -1
  11. package/dist/cjs/index.js +1 -2
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/invalidateApiKey.js +46 -0
  14. package/dist/cjs/invalidateApiKey.js.map +1 -0
  15. package/dist/cjs/shared/enum/privileges.js +0 -27
  16. package/dist/cjs/shared/enum/privileges.js.map +1 -1
  17. package/dist/cjs/shared/generateApiKeyToken.js +27 -0
  18. package/dist/cjs/shared/generateApiKeyToken.js.map +1 -0
  19. package/dist/cjs/shared/helpers.js +94 -16
  20. package/dist/cjs/shared/helpers.js.map +1 -1
  21. package/dist/cjs/shared/registerApp.js +1 -5
  22. package/dist/cjs/shared/registerApp.js.map +1 -1
  23. package/dist/cjs/shared/types/apiKeyType.js.map +1 -1
  24. package/dist/cjs/shared/types/appType.js.map +1 -1
  25. package/dist/cjs/updateApiKey.js +45 -26
  26. package/dist/cjs/updateApiKey.js.map +1 -1
  27. package/dist/esm/createApiKey.d.ts +9 -3
  28. package/dist/esm/createApiKey.js +39 -14
  29. package/dist/esm/createApiKey.js.map +1 -1
  30. package/dist/esm/index.d.ts +1 -2
  31. package/dist/esm/index.js +1 -2
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/invalidateApiKey.d.ts +18 -0
  34. package/dist/esm/invalidateApiKey.js +42 -0
  35. package/dist/esm/invalidateApiKey.js.map +1 -0
  36. package/dist/esm/shared/enum/privileges.d.ts +2 -23
  37. package/dist/esm/shared/enum/privileges.js +1 -26
  38. package/dist/esm/shared/enum/privileges.js.map +1 -1
  39. package/dist/esm/shared/generateApiKeyToken.d.ts +11 -0
  40. package/dist/esm/shared/generateApiKeyToken.js +23 -0
  41. package/dist/esm/shared/generateApiKeyToken.js.map +1 -0
  42. package/dist/esm/shared/helpers.d.ts +42 -7
  43. package/dist/esm/shared/helpers.js +88 -14
  44. package/dist/esm/shared/helpers.js.map +1 -1
  45. package/dist/esm/shared/registerApp.d.ts +1 -1
  46. package/dist/esm/shared/registerApp.js +2 -6
  47. package/dist/esm/shared/registerApp.js.map +1 -1
  48. package/dist/esm/shared/types/apiKeyType.d.ts +54 -5
  49. package/dist/esm/shared/types/apiKeyType.js.map +1 -1
  50. package/dist/esm/shared/types/appType.d.ts +7 -3
  51. package/dist/esm/shared/types/appType.js.map +1 -1
  52. package/dist/esm/updateApiKey.d.ts +8 -2
  53. package/dist/esm/updateApiKey.js +47 -28
  54. package/dist/esm/updateApiKey.js.map +1 -1
  55. package/package.json +1 -1
  56. package/dist/cjs/deleteApiKey.js +0 -43
  57. package/dist/cjs/deleteApiKey.js.map +0 -1
  58. package/dist/cjs/deleteOAuthApp.js +0 -43
  59. package/dist/cjs/deleteOAuthApp.js.map +0 -1
  60. package/dist/esm/deleteApiKey.d.ts +0 -27
  61. package/dist/esm/deleteApiKey.js +0 -39
  62. package/dist/esm/deleteApiKey.js.map +0 -1
  63. package/dist/esm/deleteOAuthApp.d.ts +0 -27
  64. package/dist/esm/deleteOAuthApp.js +0 -39
  65. package/dist/esm/deleteOAuthApp.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  /* @preserve
2
- * @esri/arcgis-rest-developer-credentials - v1.0.1 - Apache-2.0
2
+ * @esri/arcgis-rest-developer-credentials - v2.0.0 - Apache-2.0
3
3
  * Copyright (c) 2017-2025 Esri, Inc.
4
- * Thu Jan 23 2025 20:05:00 GMT+0000 (Coordinated Universal Time)
4
+ * Wed Feb 26 2025 22:10:42 GMT+0000 (Coordinated Universal Time)
5
5
  */
6
6
  (function (global, factory) {
7
7
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@esri/arcgis-rest-portal'), require('@esri/arcgis-rest-request')) :
@@ -9,38 +9,62 @@
9
9
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.arcgisRest = global.arcgisRest || {}, global.arcgisRest, global.arcgisRest));
10
10
  })(this, (function (exports, arcgisRestPortal, arcgisRestRequest) { 'use strict';
11
11
 
12
+ /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
13
+ * Apache-2.0 */
12
14
  /**
13
- * Used to describe privilege list of an app.
15
+ * Used to retrieve registered app info. See the [REST Documentation](https://developers.arcgis.com/rest/users-groups-and-items/registered-app-info.htm) for more information.
16
+ *
17
+ * ```js
18
+ * import { getRegisteredAppInfo, IApp } from '@esri/arcgis-rest-developer-credentials';
19
+ * import { ArcGISIdentityManager } from "@esri/arcgis-rest-request";
20
+ *
21
+ * const authSession: ArcGISIdentityManager = await ArcGISIdentityManager.signIn({
22
+ * username: "xyz_usrName",
23
+ * password: "xyz_pw"
24
+ * });
25
+ *
26
+ * getRegisteredAppInfo({
27
+ * itemId: "xyz_itemId",
28
+ * authentication: authSession
29
+ * }).then((registeredApp: IApp) => {
30
+ * // => {client_id: "xyz_id", client_secret: "xyz_secret", ...}
31
+ * }).catch(e => {
32
+ * // => an exception object
33
+ * });
34
+ * ```
35
+ *
36
+ * @param requestOptions - Options for {@linkcode getRegisteredAppInfo | getRegisteredAppInfo()}, including an itemId of which app to retrieve and an {@linkcode ArcGISIdentityManager} authentication session.
37
+ * @returns A Promise that will resolve to an {@linkcode IApp} object representing successfully retrieved app.
14
38
  */
15
- exports.Privileges = void 0;
16
- (function (Privileges) {
17
- Privileges["Basemaps"] = "portal:apikey:basemaps";
18
- Privileges["Demographics"] = "premium:user:demographics";
19
- Privileges["Elevation"] = "premium:user:elevation";
20
- Privileges["FeatureReport"] = "premium:user:featurereport";
21
- Privileges["Geocode"] = "premium:user:geocode";
22
- Privileges["GeocodeStored"] = "premium:user:geocode:stored";
23
- Privileges["GeocodeTemporary"] = "premium:user:geocode:temporary";
24
- Privileges["GeoEnrichment"] = "premium:user:geoenrichment";
25
- Privileges["NetworkAnalysis"] = "premium:user:networkanalysis";
26
- Privileges["NetworkAnalysisRouting"] = "premium:user:networkanalysis:routing";
27
- Privileges["NetworkAnalysisOptimizedRouting"] = "premium:user:networkanalysis:optimizedrouting";
28
- Privileges["NetworkAnalysisClosestFacility"] = "premium:user:networkanalysis:closestfacility";
29
- Privileges["NetworkAnalysisServiceArea"] = "premium:user:networkanalysis:servicearea";
30
- Privileges["NetworkAnalysisLocationalLocation"] = "premium:user:networkanalysis:locationallocation";
31
- Privileges["NetworkAnalysisVehicleRouting"] = "premium:user:networkanalysis:vehiclerouting";
32
- Privileges["NetworkAnalysisOriginDestinationCostMatrix"] = "premium:user:networkanalysis:origindestinationcostmatrix";
33
- Privileges["Places"] = "premium:user:places";
34
- Privileges["SpatialAnalysis"] = "premium:user:spatialanalysis";
35
- Privileges["GeoAnalytics"] = "premium:publisher:geoanalytics";
36
- Privileges["RasterAnalysis"] = "premium:publisher:rasteranalysis";
37
- })(exports.Privileges || (exports.Privileges = {}));
39
+ async function getRegisteredAppInfo(requestOptions) {
40
+ const userName = await requestOptions.authentication.getUsername();
41
+ const url = arcgisRestPortal.getPortalUrl(requestOptions) +
42
+ `/content/users/${userName}/items/${requestOptions.itemId}/registeredAppInfo`;
43
+ requestOptions.httpMethod = "POST";
44
+ const registeredAppResponse = await arcgisRestRequest.request(url, Object.assign(Object.assign({}, requestOptions), { params: { f: "json" } }));
45
+ return registeredAppResponseToApp(registeredAppResponse);
46
+ }
47
+
48
+ async function generateApiKeyToken(options) {
49
+ const portal = arcgisRestPortal.getPortalUrl(options);
50
+ const url = `${portal}/oauth2/token`;
51
+ const appInfo = await getRegisteredAppInfo({
52
+ itemId: options.itemId,
53
+ authentication: options.authentication
54
+ });
55
+ const params = {
56
+ client_id: appInfo.client_id,
57
+ client_secret: appInfo.client_secret,
58
+ apiToken: options.apiKey,
59
+ regenerateApiToken: true,
60
+ grant_type: "client_credentials"
61
+ };
62
+ // authentication is not being passed to the request because client_secret acts as the auth
63
+ return arcgisRestRequest.request(url, {
64
+ params
65
+ });
66
+ }
38
67
 
39
- /**
40
- * @internal
41
- * Used to check privileges validity.
42
- */
43
- const arePrivilegesValid = (privileges) => privileges.every((element) => Object.values(exports.Privileges).includes(element));
44
68
  /**
45
69
  * @internal
46
70
  * Encode special params value (e.g. array type...) in advance in order to make {@linkcode encodeParam} works correctly. Usage is case by case.
@@ -62,7 +86,8 @@
62
86
  "apnsProdCert",
63
87
  "apnsSandboxCert",
64
88
  "gcmApiKey",
65
- "isBeta"
89
+ "isBeta",
90
+ "customAppLoginShowTriage"
66
91
  ];
67
92
  const dateKeys = ["modified", "registered"];
68
93
  return Object.keys(response)
@@ -82,13 +107,11 @@
82
107
  * Used to convert {@linkcode IApp} to {@linkcode IApiKeyInfo} only if `appType` is "apikey".
83
108
  */
84
109
  function appToApiKeyProperties(response) {
85
- if (response.appType !== "apikey" || !("apiKey" in response)) {
86
- throw new Error("Item is not an API key.");
87
- }
88
- delete response.client_id;
89
110
  delete response.client_secret;
90
111
  delete response.redirect_uris;
91
112
  delete response.appType;
113
+ delete response.customAppLoginShowTriage;
114
+ delete response.apiKey;
92
115
  return response;
93
116
  }
94
117
  /**
@@ -96,12 +119,14 @@
96
119
  * Used to convert {@linkcode IApp} to {@linkcode IOAuthAppInfo}.
97
120
  */
98
121
  function appToOAuthAppProperties(response) {
99
- if (response.appType === "apikey") {
100
- throw new Error("Item is not an OAuth 2.0 app.");
101
- }
102
122
  delete response.appType;
103
123
  delete response.httpReferrers;
104
124
  delete response.privileges;
125
+ delete response.apiKey;
126
+ delete response.customAppLoginShowTriage;
127
+ delete response.isPersonalAPIToken;
128
+ delete response.apiToken1Active;
129
+ delete response.apiToken2Active;
105
130
  return response;
106
131
  }
107
132
  /**
@@ -134,6 +159,84 @@
134
159
  return obj;
135
160
  }, {});
136
161
  }
162
+ /**
163
+ * Used to determine if a generated key is in slot 1 or slot 2 key. The full API key should be passed. `undefined` will be returned if the proper slot could not be identified.
164
+ */
165
+ function slotForKey(key) {
166
+ const slot = parseInt(key.substring(key.length - 10, key.length - 9));
167
+ if (slot === 1 || slot === 2) {
168
+ return slot;
169
+ }
170
+ return undefined;
171
+ }
172
+ /**
173
+ * @internal
174
+ * Used to determine which slot to invalidate a key in given a number or a full or patial key.
175
+ */
176
+ function slotForInvalidationKey(param) {
177
+ if (param === 1 || param === 2) {
178
+ return param;
179
+ }
180
+ if (typeof param !== "string") {
181
+ return undefined;
182
+ }
183
+ const fullKeySlot = slotForKey(param);
184
+ if (fullKeySlot) {
185
+ return fullKeySlot;
186
+ }
187
+ }
188
+ /**
189
+ * @internal
190
+ * Used to generate tokens in slot 1 and/or 2 of an API key.
191
+ */
192
+ function generateApiKeyTokens(itemId, slots, requestOptions) {
193
+ return Promise.all(slots.map((slot) => {
194
+ return generateApiKeyToken(Object.assign({ itemId, apiKey: slot }, requestOptions));
195
+ })).then((responses) => {
196
+ return responses
197
+ .map((responses) => responses.access_token)
198
+ .reduce((obj, token, index) => {
199
+ obj[`accessToken${slotForKey(token)}`] = token;
200
+ return obj;
201
+ }, {});
202
+ });
203
+ }
204
+ /**
205
+ * @internal
206
+ * Convert boolean flags to an array of slots for {@linkcode generateApiKeyTokens}.
207
+ */
208
+ function generateOptionsToSlots(generateToken1, generateToken2) {
209
+ const slots = [];
210
+ if (generateToken1) {
211
+ slots.push(1);
212
+ }
213
+ if (generateToken2) {
214
+ slots.push(2);
215
+ }
216
+ return slots;
217
+ }
218
+ /**
219
+ * @internal
220
+ * Build params for updating expiration dates
221
+ */
222
+ function buildExpirationDateParams(requestOptions, fillDefaults) {
223
+ const updateparams = {};
224
+ if (requestOptions.apiToken1ExpirationDate) {
225
+ updateparams.apiToken1ExpirationDate =
226
+ requestOptions.apiToken1ExpirationDate;
227
+ }
228
+ if (requestOptions.apiToken2ExpirationDate) {
229
+ updateparams.apiToken2ExpirationDate =
230
+ requestOptions.apiToken2ExpirationDate;
231
+ }
232
+ if (fillDefaults && !updateparams.apiToken1ExpirationDate) {
233
+ updateparams.apiToken1ExpirationDate = -1;
234
+ }
235
+ if (fillDefaults && !updateparams.apiToken2ExpirationDate) {
236
+ updateparams.apiToken2ExpirationDate = -1;
237
+ }
238
+ return updateparams;
239
+ }
137
240
 
138
241
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
139
242
  * Apache-2.0 */
@@ -161,7 +264,7 @@
161
264
  * appType: "multiple",
162
265
  * redirect_uris: ["http://localhost:3000/"],
163
266
  * httpReferrers: ["http://localhost:3000/"],
164
- * privileges: [Privileges.Geocode, Privileges.FeatureReport],
267
+ * privileges: ["premium:user:geocode:temporary", Privileges.FeatureReport],
165
268
  * authentication: authSession
166
269
  * }).then((registeredApp: IApp) => {
167
270
  * // => {client_id: "xyz_id", client_secret: "xyz_secret", ...}
@@ -174,10 +277,6 @@
174
277
  * @returns A Promise that will resolve to an {@linkcode IApp} object representing the newly registered app.
175
278
  */
176
279
  async function registerApp(requestOptions) {
177
- // privileges validation
178
- if (!arePrivilegesValid(requestOptions.privileges)) {
179
- throw new Error("The `privileges` option contains invalid privileges.");
180
- }
181
280
  // build params
182
281
  const options = arcgisRestRequest.appendCustomParams(requestOptions, [
183
282
  "itemId",
@@ -209,14 +308,20 @@
209
308
  * password: "xyz_pw"
210
309
  * });
211
310
  *
311
+ * const threeDaysFromToday = new Date();
312
+ * threeDaysFromToday.setDate(threeDaysFromToday.getDate() + 3);
313
+ * threeDaysFromToday.setHours(23, 59, 59, 999);
314
+ *
212
315
  * createApiKey({
213
316
  * title: "xyz_title",
214
317
  * description: "xyz_desc",
215
318
  * tags: ["xyz_tag1", "xyz_tag2"],
216
- * privileges: [Privileges.Geocode, Privileges.FeatureReport],
217
- * authentication: authSession
319
+ * privileges: ["premium:user:networkanalysis:routing"],
320
+ * authentication: authSession,
321
+ * generateToken1: true, // optional,generate a new token
322
+ * apiToken1ExpirationDate: threeDaysFromToday // optional, update expiration date
218
323
  * }).then((registeredAPIKey: IApiKeyResponse) => {
219
- * // => {apiKey: "xyz_key", item: {tags: ["xyz_tag1", "xyz_tag2"], ...}, ...}
324
+ * // => {accessToken1: "xyz_key", item: {tags: ["xyz_tag1", "xyz_tag2"], ...}, ...}
220
325
  * }).catch(e => {
221
326
  * // => an exception object
222
327
  * });
@@ -226,9 +331,6 @@
226
331
  * @returns A Promise that will resolve to an {@linkcode IApiKeyResponse} object representing the newly registered API key.
227
332
  */
228
333
  async function createApiKey(requestOptions) {
229
- if (!arePrivilegesValid(requestOptions.privileges)) {
230
- throw new Error("The `privileges` option contains invalid privileges.");
231
- }
232
334
  requestOptions.httpMethod = "POST";
233
335
  // filter param buckets:
234
336
  const baseRequestOptions = extractBaseRequestOptions(requestOptions); // snapshot of basic IRequestOptions before customized params being built into it
@@ -248,52 +350,37 @@
248
350
  "typeKeywords",
249
351
  "url"
250
352
  ];
251
- // step 1: add item
252
- const createItemOption = Object.assign(Object.assign({ item: Object.assign(Object.assign({}, filterKeys(requestOptions, itemAddProperties)), { type: "API Key" }) }, baseRequestOptions), { authentication: requestOptions.authentication, params: {
353
+ /**
354
+ * step 1: create item
355
+ */
356
+ const createItemOption = Object.assign(Object.assign({ item: Object.assign(Object.assign({}, filterKeys(requestOptions, itemAddProperties)), { type: "Application" }) }, baseRequestOptions), { authentication: requestOptions.authentication, params: {
253
357
  f: "json"
254
358
  } });
255
359
  const createItemResponse = await arcgisRestPortal.createItem(createItemOption);
256
- // step 2: register app
257
- const registerAppOption = Object.assign(Object.assign({ itemId: createItemResponse.id, appType: "apikey", redirect_uris: [], httpReferrers: requestOptions.httpReferrers || [], privileges: requestOptions.privileges }, baseRequestOptions), { authentication: requestOptions.authentication });
258
- const registeredAppResponse = await registerApp(registerAppOption);
360
+ /**
361
+ * getRegisteredAppInfoRoute
362
+ */
363
+ const registerAppOptions = Object.assign(Object.assign({ itemId: createItemResponse.id, appType: "multiple", redirect_uris: ["urn:ietf:wg:oauth:2.0:oob"], httpReferrers: requestOptions.httpReferrers || [], privileges: requestOptions.privileges }, baseRequestOptions), { authentication: requestOptions.authentication });
364
+ const registeredAppResponse = await registerApp(registerAppOptions);
365
+ /**
366
+ * step 3: update item with desired expiration dates
367
+ * you cannot set the expiration date propierties until you
368
+ * regiester the app so this has to be a seperate step
369
+ */
370
+ await arcgisRestPortal.updateItem(Object.assign(Object.assign({}, baseRequestOptions), { item: Object.assign({ id: createItemResponse.id }, buildExpirationDateParams(requestOptions, true)), authentication: requestOptions.authentication }));
371
+ /*
372
+ * step 4: get item info
373
+ */
259
374
  const itemInfo = await arcgisRestPortal.getItem(registeredAppResponse.itemId, Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication, params: { f: "json" } }));
260
- return Object.assign(Object.assign({}, appToApiKeyProperties(registeredAppResponse)), { item: itemInfo });
261
- }
262
-
263
- /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
264
- * Apache-2.0 */
265
- /**
266
- * Used to retrieve registered app info. See the [REST Documentation](https://developers.arcgis.com/rest/users-groups-and-items/registered-app-info.htm) for more information.
267
- *
268
- * ```js
269
- * import { getRegisteredAppInfo, IApp } from '@esri/arcgis-rest-developer-credentials';
270
- * import { ArcGISIdentityManager } from "@esri/arcgis-rest-request";
271
- *
272
- * const authSession: ArcGISIdentityManager = await ArcGISIdentityManager.signIn({
273
- * username: "xyz_usrName",
274
- * password: "xyz_pw"
275
- * });
276
- *
277
- * getRegisteredAppInfo({
278
- * itemId: "xyz_itemId",
279
- * authentication: authSession
280
- * }).then((registeredApp: IApp) => {
281
- * // => {client_id: "xyz_id", client_secret: "xyz_secret", ...}
282
- * }).catch(e => {
283
- * // => an exception object
284
- * });
285
- * ```
286
- *
287
- * @param requestOptions - Options for {@linkcode getRegisteredAppInfo | getRegisteredAppInfo()}, including an itemId of which app to retrieve and an {@linkcode ArcGISIdentityManager} authentication session.
288
- * @returns A Promise that will resolve to an {@linkcode IApp} object representing successfully retrieved app.
289
- */
290
- async function getRegisteredAppInfo(requestOptions) {
291
- const userName = await requestOptions.authentication.getUsername();
292
- const url = arcgisRestPortal.getPortalUrl(requestOptions) +
293
- `/content/users/${userName}/items/${requestOptions.itemId}/registeredAppInfo`;
294
- requestOptions.httpMethod = "POST";
295
- const registeredAppResponse = await arcgisRestRequest.request(url, Object.assign(Object.assign({}, requestOptions), { params: { f: "json" } }));
296
- return registeredAppResponseToApp(registeredAppResponse);
375
+ /**
376
+ * step 5: generate tokens if requested
377
+ */
378
+ const generatedTokens = await generateApiKeyTokens(itemInfo.id, generateOptionsToSlots(requestOptions.generateToken1, requestOptions.generateToken2), Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication }));
379
+ /**
380
+ * step 6: get registered app info to get updated active key status
381
+ */
382
+ const updatedRegisteredAppResponse = await getRegisteredAppInfo(Object.assign(Object.assign({}, baseRequestOptions), { itemId: itemInfo.id, authentication: requestOptions.authentication }));
383
+ return Object.assign(Object.assign(Object.assign({}, generatedTokens), appToApiKeyProperties(updatedRegisteredAppResponse)), { item: itemInfo });
297
384
  }
298
385
 
299
386
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
@@ -314,13 +401,19 @@
314
401
  * password: "xyz_pw"
315
402
  * });
316
403
  *
404
+ * const threeDaysFromToday = new Date();
405
+ * threeDaysFromToday.setDate(threeDaysFromToday.getDate() + 3);
406
+ * threeDaysFromToday.setHours(23, 59, 59, 999);
407
+ *
317
408
  * updateApiKey({
318
409
  * itemId: "xyz_itemId",
319
- * privileges: [Privileges.Geocode],
410
+ * privileges: ["premium:user:geocode:temporary"],
320
411
  * httpReferrers: [], // httpReferrers will be set to be empty
321
412
  * authentication: authSession
413
+ * generateToken1: true, // optional,generate a new token
414
+ * apiToken1ExpirationDate: threeDaysFromToday // optional, update expiration date
322
415
  * }).then((updatedAPIKey: IApiKeyResponse) => {
323
- * // => {apiKey: "xyz_key", item: {tags: ["xyz_tag1", "xyz_tag2"], ...}, ...}
416
+ * // => {accessToken1: "xyz_key", item: {tags: ["xyz_tag1", "xyz_tag2"], ...}, ...}
324
417
  * }).catch(e => {
325
418
  * // => an exception object
326
419
  * });
@@ -330,33 +423,46 @@
330
423
  * @returns A Promise that will resolve to an {@linkcode IApiKeyResponse} object representing updated API key.
331
424
  */
332
425
  async function updateApiKey(requestOptions) {
333
- // privileges validation
334
- if (requestOptions.privileges &&
335
- !arePrivilegesValid(requestOptions.privileges)) {
336
- throw new Error("The `privileges` option contains invalid privileges.");
337
- }
338
426
  requestOptions.httpMethod = "POST";
339
- // get app
340
427
  const baseRequestOptions = extractBaseRequestOptions(requestOptions); // get base requestOptions snapshot
341
- const getAppOption = Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication, itemId: requestOptions.itemId });
342
- const appResponse = await getRegisteredAppInfo(getAppOption);
343
- // appType must be APIKey to continue
344
- if (appResponse.appType !== "apikey" || !("apiKey" in appResponse)) {
345
- throw new Error("Item is not an API key.");
428
+ /**
429
+ * step 1: update expiration dates if provided. Build the object up to avoid overwriting any existing properties.
430
+ */
431
+ if (requestOptions.apiToken1ExpirationDate ||
432
+ requestOptions.apiToken2ExpirationDate) {
433
+ const updateParams = buildExpirationDateParams(requestOptions);
434
+ await arcgisRestPortal.updateItem(Object.assign(Object.assign({}, baseRequestOptions), { item: Object.assign({ id: requestOptions.itemId }, updateParams), authentication: requestOptions.authentication }));
346
435
  }
347
- const clientId = appResponse.client_id;
348
- const options = arcgisRestRequest.appendCustomParams(Object.assign(Object.assign({}, appResponse), requestOptions), // object with the custom params to look in
349
- ["privileges", "httpReferrers"] // keys you want copied to the params object
350
- );
351
- options.params.f = "json";
352
- // encode special params value (e.g. array type...) in advance in order to make encodeQueryString() works correctly
353
- stringifyArrays(options);
354
- const url = arcgisRestPortal.getPortalUrl(options) + `/oauth2/apps/${clientId}/update`;
355
- // Raw response from `/oauth2/apps/${clientId}/update`, apiKey not included because key is same.
356
- const updateResponse = await arcgisRestRequest.request(url, Object.assign(Object.assign({}, options), { authentication: requestOptions.authentication }));
357
- const app = registeredAppResponseToApp(Object.assign(Object.assign({}, updateResponse), { apiKey: appResponse.apiKey }));
358
- const itemInfo = await arcgisRestPortal.getItem(requestOptions.itemId, Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication, params: { f: "json" } }));
359
- return Object.assign(Object.assign({}, appToApiKeyProperties(app)), { item: itemInfo });
436
+ /**
437
+ * step 2: update privileges and httpReferrers if provided. Build the object up to avoid overwriting any existing properties.
438
+ */
439
+ if (requestOptions.privileges || requestOptions.httpReferrers) {
440
+ const getAppOption = Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication, itemId: requestOptions.itemId });
441
+ const appResponse = await getRegisteredAppInfo(getAppOption);
442
+ const clientId = appResponse.client_id;
443
+ const options = arcgisRestRequest.appendCustomParams(Object.assign(Object.assign({}, appResponse), requestOptions), // object with the custom params to look in
444
+ ["privileges", "httpReferrers"] // keys you want copied to the params object
445
+ );
446
+ options.params.f = "json";
447
+ // encode special params value (e.g. array type...) in advance in order to make encodeQueryString() works correctly
448
+ stringifyArrays(options);
449
+ const url = arcgisRestPortal.getPortalUrl(options) + `/oauth2/apps/${clientId}/update`;
450
+ // Raw response from `/oauth2/apps/${clientId}/update`, apiKey not included because key is same.
451
+ await arcgisRestRequest.request(url, Object.assign(Object.assign({}, options), { authentication: requestOptions.authentication }));
452
+ }
453
+ /**
454
+ * step 3: get the updated item info to return to the user.
455
+ */
456
+ const updatedItemInfo = await arcgisRestPortal.getItem(requestOptions.itemId, Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication, params: { f: "json" } }));
457
+ /**
458
+ * step 4: generate tokens if requested
459
+ */
460
+ const generatedTokens = await generateApiKeyTokens(requestOptions.itemId, generateOptionsToSlots(requestOptions.generateToken1, requestOptions.generateToken2), Object.assign(Object.assign({}, baseRequestOptions), { authentication: requestOptions.authentication }));
461
+ /**
462
+ * step 5: get updated registered app info
463
+ */
464
+ const updatedRegisteredAppResponse = await getRegisteredAppInfo(Object.assign(Object.assign({}, baseRequestOptions), { itemId: requestOptions.itemId, authentication: requestOptions.authentication }));
465
+ return Object.assign(Object.assign(Object.assign({}, generatedTokens), appToApiKeyProperties(updatedRegisteredAppResponse)), { item: updatedItemInfo });
360
466
  }
361
467
 
362
468
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
@@ -395,37 +501,39 @@
395
501
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
396
502
  * Apache-2.0 */
397
503
  /**
398
- * Used to delete the API Key with given `itemId`.
504
+ * Used to invalidate an API key.
399
505
  *
400
506
  * ```js
401
- * import { deleteApiKey, IDeleteApiKeyResponse } from '@esri/arcgis-rest-developer-credentials';
402
- * import { ArcGISIdentityManager } from "@esri/arcgis-rest-request";
403
- *
404
- * const authSession: ArcGISIdentityManager = await ArcGISIdentityManager.signIn({
405
- * username: "xyz_usrName",
406
- * password: "xyz_pw"
407
- * });
408
- *
409
- * deleteApiKey({
410
- * itemId: "xyz_itemId",
411
- * authentication: authSession
412
- * }).then((deletedApiKey: IDeleteApiKeyResponse) => {
413
- * // => {itemId: "xyz_itemId", success: true}
507
+ * import { invalidateApiKey } from "@esri/arcgis-rest-developer-credentials";
508
+ *
509
+ * invalidateApiKey({
510
+ * itemId: ITEM_ID,
511
+ * authentication,
512
+ * apiKey: 1, // invalidate the key in slot 1
513
+ * }).then((response) => {
514
+ * // => {success: true}
414
515
  * }).catch(e => {
415
516
  * // => an exception object
416
517
  * });
417
- * ```
418
- *
419
- * @param requestOptions - Options for {@linkcode deleteApiKey | deleteApiKey()}, including `itemId` of which API key to be deleted and an {@linkcode ArcGISIdentityManager} authentication session.
420
- * @returns A Promise that will resolve to an {@linkcode IDeleteApiKeyResponse} object representing deletion status.
421
518
  */
422
- async function deleteApiKey(requestOptions) {
423
- requestOptions.httpMethod = "POST";
424
- const baseRequestOptions = extractBaseRequestOptions(requestOptions);
425
- // validate provided itemId associates with API Key
426
- await getApiKey(Object.assign(Object.assign({}, baseRequestOptions), { itemId: requestOptions.itemId, authentication: requestOptions.authentication }));
427
- const removeItemResponse = await arcgisRestPortal.removeItem(Object.assign(Object.assign({}, baseRequestOptions), { id: requestOptions.itemId, authentication: requestOptions.authentication, params: { f: "json" } }));
428
- return removeItemResponse;
519
+ async function invalidateApiKey(requestOptions) {
520
+ const portal = arcgisRestPortal.getPortalUrl(requestOptions);
521
+ const url = `${portal}/oauth2/revokeToken`;
522
+ const appInfo = await getRegisteredAppInfo({
523
+ itemId: requestOptions.itemId,
524
+ authentication: requestOptions.authentication
525
+ });
526
+ const params = {
527
+ client_id: appInfo.client_id,
528
+ client_secret: appInfo.client_secret,
529
+ apiToken: slotForInvalidationKey(requestOptions.apiKey),
530
+ regenerateApiToken: true,
531
+ grant_type: "client_credentials"
532
+ };
533
+ // authentication is not being passed to the request because client_secret acts as the auth
534
+ return arcgisRestRequest.request(url, {
535
+ params
536
+ });
429
537
  }
430
538
 
431
539
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
@@ -461,42 +569,6 @@
461
569
  return Object.assign(Object.assign({}, appToOAuthAppProperties(appResponse)), { item: itemInfo });
462
570
  }
463
571
 
464
- /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
465
- * Apache-2.0 */
466
- /**
467
- * Used to delete the OAuth2.0 app with given `itemId`.
468
- *
469
- * ```js
470
- * import { deleteOAuthApp, IDeleteOAuthAppResponse } from '@esri/arcgis-rest-developer-credentials';
471
- * import { ArcGISIdentityManager } from "@esri/arcgis-rest-request";
472
- *
473
- * const authSession: ArcGISIdentityManager = await ArcGISIdentityManager.signIn({
474
- * username: "xyz_usrName",
475
- * password: "xyz_pw"
476
- * });
477
- *
478
- * deleteOAuthApp({
479
- * itemId: "xyz_itemId",
480
- * authentication: authSession
481
- * }).then((deletedOAuthApp: IDeleteOAuthAppResponse) => {
482
- * // => {itemId: "xyz_itemId", success: true}
483
- * }).catch(e => {
484
- * // => an exception object
485
- * });
486
- * ```
487
- *
488
- * @param requestOptions - Options for {@linkcode deleteOAuthApp | deleteOAuthApp()}, including `itemId` of which OAuth app to be deleted and an {@linkcode ArcGISIdentityManager} authentication session.
489
- * @returns A Promise that will resolve to an {@linkcode IDeleteOAuthAppResponse} object representing deletion status.
490
- */
491
- async function deleteOAuthApp(requestOptions) {
492
- requestOptions.httpMethod = "POST";
493
- const baseRequestOptions = extractBaseRequestOptions(requestOptions);
494
- // validate provided itemId associates with OAuth app
495
- await getOAuthApp(Object.assign(Object.assign({}, baseRequestOptions), { itemId: requestOptions.itemId, authentication: requestOptions.authentication }));
496
- const removeItemResponse = await arcgisRestPortal.removeItem(Object.assign(Object.assign({}, baseRequestOptions), { id: requestOptions.itemId, authentication: requestOptions.authentication, params: { f: "json" } }));
497
- return removeItemResponse;
498
- }
499
-
500
572
  /* Copyright (c) 2023 Environmental Systems Research Institute, Inc.
501
573
  * Apache-2.0 */
502
574
  /**
@@ -655,18 +727,21 @@
655
727
 
656
728
  exports.appToApiKeyProperties = appToApiKeyProperties;
657
729
  exports.appToOAuthAppProperties = appToOAuthAppProperties;
658
- exports.arePrivilegesValid = arePrivilegesValid;
730
+ exports.buildExpirationDateParams = buildExpirationDateParams;
659
731
  exports.createApiKey = createApiKey;
660
732
  exports.createOAuthApp = createOAuthApp;
661
- exports.deleteApiKey = deleteApiKey;
662
- exports.deleteOAuthApp = deleteOAuthApp;
663
733
  exports.extractBaseRequestOptions = extractBaseRequestOptions;
664
734
  exports.filterKeys = filterKeys;
735
+ exports.generateApiKeyTokens = generateApiKeyTokens;
736
+ exports.generateOptionsToSlots = generateOptionsToSlots;
665
737
  exports.getApiKey = getApiKey;
666
738
  exports.getOAuthApp = getOAuthApp;
667
739
  exports.getRegisteredAppInfo = getRegisteredAppInfo;
740
+ exports.invalidateApiKey = invalidateApiKey;
668
741
  exports.registerApp = registerApp;
669
742
  exports.registeredAppResponseToApp = registeredAppResponseToApp;
743
+ exports.slotForInvalidationKey = slotForInvalidationKey;
744
+ exports.slotForKey = slotForKey;
670
745
  exports.stringifyArrays = stringifyArrays;
671
746
  exports.unregisterApp = unregisterApp;
672
747
  exports.updateApiKey = updateApiKey;