@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.1

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/bin/cli.js +173 -0
  4. package/contexts/4.34/claude/arcgis-3d-advanced/SKILL.md +586 -0
  5. package/contexts/4.34/claude/arcgis-advanced-layers/SKILL.md +431 -0
  6. package/contexts/4.34/claude/arcgis-analysis-services/SKILL.md +607 -0
  7. package/contexts/4.34/claude/arcgis-arcade/SKILL.md +366 -0
  8. package/contexts/4.34/claude/arcgis-authentication/SKILL.md +301 -0
  9. package/contexts/4.34/claude/arcgis-cim-symbols/SKILL.md +486 -0
  10. package/contexts/4.34/claude/arcgis-coordinates-projection/SKILL.md +406 -0
  11. package/contexts/4.34/claude/arcgis-core-maps/SKILL.md +739 -0
  12. package/contexts/4.34/claude/arcgis-core-utilities/SKILL.md +732 -0
  13. package/contexts/4.34/claude/arcgis-custom-rendering/SKILL.md +445 -0
  14. package/contexts/4.34/claude/arcgis-editing-advanced/SKILL.md +702 -0
  15. package/contexts/4.34/claude/arcgis-feature-effects/SKILL.md +393 -0
  16. package/contexts/4.34/claude/arcgis-geometry-operations/SKILL.md +489 -0
  17. package/contexts/4.34/claude/arcgis-imagery/SKILL.md +307 -0
  18. package/contexts/4.34/claude/arcgis-interaction/SKILL.md +572 -0
  19. package/contexts/4.34/claude/arcgis-knowledge-graphs/SKILL.md +582 -0
  20. package/contexts/4.34/claude/arcgis-layers/SKILL.md +601 -0
  21. package/contexts/4.34/claude/arcgis-map-tools/SKILL.md +668 -0
  22. package/contexts/4.34/claude/arcgis-media-layers/SKILL.md +290 -0
  23. package/contexts/4.34/claude/arcgis-popup-templates/SKILL.md +891 -0
  24. package/contexts/4.34/claude/arcgis-portal-content/SKILL.md +679 -0
  25. package/contexts/4.34/claude/arcgis-scene-effects/SKILL.md +512 -0
  26. package/contexts/4.34/claude/arcgis-smart-mapping/SKILL.md +686 -0
  27. package/contexts/4.34/claude/arcgis-tables-forms/SKILL.md +877 -0
  28. package/contexts/4.34/claude/arcgis-time-animation/SKILL.md +722 -0
  29. package/contexts/4.34/claude/arcgis-utility-networks/SKILL.md +301 -0
  30. package/contexts/4.34/claude/arcgis-visualization/SKILL.md +580 -0
  31. package/contexts/4.34/claude/arcgis-widgets-ui/SKILL.md +574 -0
  32. package/contexts/4.34/copilot/arcgis-3d.instructions.md +267 -0
  33. package/contexts/4.34/copilot/arcgis-analysis.instructions.md +294 -0
  34. package/contexts/4.34/copilot/arcgis-arcade.instructions.md +234 -0
  35. package/contexts/4.34/copilot/arcgis-authentication.instructions.md +187 -0
  36. package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +177 -0
  37. package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +246 -0
  38. package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +247 -0
  39. package/contexts/4.34/copilot/arcgis-editing.instructions.md +262 -0
  40. package/contexts/4.34/copilot/arcgis-geometry.instructions.md +225 -0
  41. package/contexts/4.34/copilot/arcgis-layers.instructions.md +278 -0
  42. package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +266 -0
  43. package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +275 -0
  44. package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +184 -0
  45. package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +112 -0
  46. package/contexts/4.34/copilot/arcgis-visualization.instructions.md +321 -0
  47. package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +277 -0
  48. package/lib/installer.js +379 -0
  49. package/package.json +45 -0
@@ -0,0 +1,366 @@
1
+ ---
2
+ name: arcgis-arcade
3
+ description: Write Arcade expressions for dynamic calculations in popups, renderers, labels, and field calculations. Use for data-driven styling, custom labels, and computed fields.
4
+ ---
5
+
6
+ # ArcGIS Arcade Expressions
7
+
8
+ Use this skill for writing Arcade expressions for popups, renderers, labels, and calculations.
9
+
10
+ ## Arcade Basics
11
+
12
+ Arcade is an expression language for ArcGIS. It's used for:
13
+ - Dynamic popup content
14
+ - Data-driven rendering
15
+ - Custom labels
16
+ - Field calculations
17
+ - Form validation
18
+
19
+ ### Basic Syntax
20
+ ```arcade
21
+ // Variables
22
+ var population = $feature.population;
23
+ var area = $feature.area_sqkm;
24
+
25
+ // Calculations
26
+ var density = population / area;
27
+
28
+ // Return result
29
+ return Round(density, 2);
30
+ ```
31
+
32
+ ## Arcade in PopupTemplates
33
+
34
+ ### Expression Infos
35
+ ```javascript
36
+ const popupTemplate = {
37
+ title: "{name}",
38
+ expressionInfos: [
39
+ {
40
+ name: "population-density",
41
+ title: "Population Density",
42
+ expression: "Round($feature.population / $feature.area_sqkm, 2)"
43
+ },
44
+ {
45
+ name: "formatted-date",
46
+ title: "Formatted Date",
47
+ expression: "Text($feature.created_date, 'MMMM D, YYYY')"
48
+ }
49
+ ],
50
+ content: "Density: {expression/population-density} people/km²"
51
+ };
52
+ ```
53
+
54
+ ### Complex Expressions
55
+ ```javascript
56
+ const popupTemplate = {
57
+ title: "{name}",
58
+ expressionInfos: [{
59
+ name: "predominant-category",
60
+ title: "Predominant Category",
61
+ expression: `
62
+ var fields = [
63
+ { value: $feature.category_a, alias: "Category A" },
64
+ { value: $feature.category_b, alias: "Category B" },
65
+ { value: $feature.category_c, alias: "Category C" }
66
+ ];
67
+
68
+ var maxValue = -Infinity;
69
+ var maxCategory = "";
70
+
71
+ for (var i in fields) {
72
+ if (fields[i].value > maxValue) {
73
+ maxValue = fields[i].value;
74
+ maxCategory = fields[i].alias;
75
+ }
76
+ }
77
+
78
+ return maxCategory;
79
+ `
80
+ }],
81
+ content: [
82
+ {
83
+ type: "text",
84
+ text: "The predominant category is: {expression/predominant-category}"
85
+ },
86
+ {
87
+ type: "fields",
88
+ fieldInfos: [{
89
+ fieldName: "expression/predominant-category"
90
+ }]
91
+ }
92
+ ]
93
+ };
94
+ ```
95
+
96
+ ## Arcade in Renderers
97
+
98
+ ### Value Expression
99
+ ```javascript
100
+ const renderer = {
101
+ type: "unique-value",
102
+ valueExpression: `
103
+ var labor = $feature.labor_force;
104
+ var notLabor = $feature.not_in_labor_force;
105
+
106
+ if (labor > notLabor) {
107
+ return "In labor force";
108
+ } else {
109
+ return "Not in labor force";
110
+ }
111
+ `,
112
+ valueExpressionTitle: "Labor Force Status",
113
+ uniqueValueInfos: [
114
+ {
115
+ value: "In labor force",
116
+ symbol: { type: "simple-fill", color: "blue" }
117
+ },
118
+ {
119
+ value: "Not in labor force",
120
+ symbol: { type: "simple-fill", color: "orange" }
121
+ }
122
+ ]
123
+ };
124
+ ```
125
+
126
+ ### Visual Variable Expression
127
+ ```javascript
128
+ const renderer = {
129
+ type: "simple",
130
+ symbol: { type: "simple-marker", color: "red" },
131
+ visualVariables: [{
132
+ type: "size",
133
+ valueExpression: "Sqrt($feature.population) * 0.1",
134
+ valueExpressionTitle: "Population (scaled)",
135
+ stops: [
136
+ { value: 10, size: 4 },
137
+ { value: 100, size: 40 }
138
+ ]
139
+ }, {
140
+ type: "opacity",
141
+ valueExpression: "($feature.value / $feature.max_value) * 100",
142
+ valueExpressionTitle: "Percentage of max",
143
+ stops: [
144
+ { value: 20, opacity: 0.2 },
145
+ { value: 80, opacity: 1 }
146
+ ]
147
+ }]
148
+ };
149
+ ```
150
+
151
+ ## Arcade in Labels
152
+
153
+ ```javascript
154
+ layer.labelingInfo = [{
155
+ symbol: {
156
+ type: "text",
157
+ color: "black",
158
+ font: { size: 10 }
159
+ },
160
+ labelExpressionInfo: {
161
+ expression: `
162
+ var name = $feature.name;
163
+ var pop = $feature.population;
164
+
165
+ if (pop > 1000000) {
166
+ return name + " (" + Round(pop/1000000, 1) + "M)";
167
+ } else if (pop > 1000) {
168
+ return name + " (" + Round(pop/1000, 0) + "K)";
169
+ }
170
+ return name;
171
+ `
172
+ },
173
+ where: "population > 50000"
174
+ }];
175
+ ```
176
+
177
+ ## Common Arcade Functions
178
+
179
+ ### Math Functions
180
+ ```arcade
181
+ Round(3.14159, 2) // 3.14
182
+ Floor(3.9) // 3
183
+ Ceil(3.1) // 4
184
+ Abs(-5) // 5
185
+ Sqrt(16) // 4
186
+ Pow(2, 3) // 8
187
+ Min(1, 2, 3) // 1
188
+ Max(1, 2, 3) // 3
189
+ Sum([1, 2, 3]) // 6
190
+ Mean([1, 2, 3]) // 2
191
+ ```
192
+
193
+ ### Text Functions
194
+ ```arcade
195
+ Upper("hello") // "HELLO"
196
+ Lower("HELLO") // "hello"
197
+ Trim(" hello ") // "hello"
198
+ Left("hello", 2) // "he"
199
+ Right("hello", 2) // "lo"
200
+ Mid("hello", 2, 2) // "ll"
201
+ Find("l", "hello") // 2
202
+ Replace("hello", "l", "L") // "heLLo"
203
+ Split("a,b,c", ",") // ["a", "b", "c"]
204
+ Concatenate(["a", "b"]) // "ab"
205
+ ```
206
+
207
+ ### Date Functions
208
+ ```arcade
209
+ Now() // Current date/time
210
+ Today() // Current date
211
+ Year($feature.date_field) // Extract year
212
+ Month($feature.date_field) // Extract month (1-12)
213
+ Day($feature.date_field) // Extract day
214
+ DateDiff(Now(), $feature.date, "days") // Days between dates
215
+ Text($feature.date, "MMMM D, YYYY") // Format date
216
+ ```
217
+
218
+ ### Geometry Functions
219
+ ```arcade
220
+ Area($feature, "square-kilometers")
221
+ Length($feature, "kilometers")
222
+ Centroid($feature)
223
+ Buffer($feature, 100, "meters")
224
+ Intersects($feature, $otherFeature)
225
+ Contains($feature, $point)
226
+ ```
227
+
228
+ ### Conditional Functions
229
+ ```arcade
230
+ // IIf (inline if)
231
+ IIf($feature.value > 100, "High", "Low")
232
+
233
+ // When (multiple conditions)
234
+ When(
235
+ $feature.type == "A", "Type A",
236
+ $feature.type == "B", "Type B",
237
+ "Other"
238
+ )
239
+
240
+ // Decode (value matching)
241
+ Decode($feature.code,
242
+ 1, "One",
243
+ 2, "Two",
244
+ 3, "Three",
245
+ "Unknown"
246
+ )
247
+ ```
248
+
249
+ ### Array Functions
250
+ ```arcade
251
+ var arr = [1, 2, 3, 4, 5];
252
+
253
+ Count(arr) // 5
254
+ First(arr) // 1
255
+ Last(arr) // 5
256
+ IndexOf(arr, 3) // 2
257
+ Includes(arr, 3) // true
258
+ Push(arr, 6) // [1, 2, 3, 4, 5, 6]
259
+ Reverse(arr) // [5, 4, 3, 2, 1]
260
+ Sort(arr) // [1, 2, 3, 4, 5]
261
+ Slice(arr, 1, 3) // [2, 3]
262
+ ```
263
+
264
+ ## Feature Access
265
+
266
+ ```arcade
267
+ // Current feature
268
+ $feature.fieldName
269
+
270
+ // All features in layer (for aggregation)
271
+ var allFeatures = FeatureSet($layer);
272
+ var filtered = Filter(allFeatures, "type = 'A'");
273
+ var total = Sum(filtered, "value");
274
+
275
+ // Related records
276
+ var related = FeatureSetByRelationshipName($feature, "relationshipName");
277
+
278
+ // Global variables
279
+ $map // Reference to map
280
+ $view // Reference to view
281
+ $datastore // Reference to data store
282
+ ```
283
+
284
+ ## Execute Arcade Programmatically
285
+
286
+ ```javascript
287
+ import Arcade from "@arcgis/core/arcade/Arcade.js";
288
+
289
+ // Create profile
290
+ const profile = {
291
+ variables: [{
292
+ name: "$feature",
293
+ type: "feature"
294
+ }]
295
+ };
296
+
297
+ // Compile expression
298
+ const executor = await Arcade.createArcadeExecutor(
299
+ "Round($feature.value * 100, 2)",
300
+ profile
301
+ );
302
+
303
+ // Execute with feature
304
+ const result = executor.execute({
305
+ $feature: graphic
306
+ });
307
+
308
+ console.log("Result:", result);
309
+ ```
310
+
311
+ ## Arcade in HTML (Script Tags)
312
+
313
+ ```html
314
+ <script type="text/plain" id="my-expression">
315
+ var total = $feature.value_a + $feature.value_b;
316
+ var percentage = Round((total / $feature.max_value) * 100, 1);
317
+ return percentage + "%";
318
+ </script>
319
+
320
+ <script type="module">
321
+ const expression = document.getElementById("my-expression").text;
322
+
323
+ const popupTemplate = {
324
+ expressionInfos: [{
325
+ name: "my-calc",
326
+ expression: expression
327
+ }],
328
+ content: "Value: {expression/my-calc}"
329
+ };
330
+ </script>
331
+ ```
332
+
333
+ ## TypeScript Usage
334
+
335
+ Arcade expression configurations use autocasting. For TypeScript safety, use `as const`:
336
+
337
+ ```typescript
338
+ // Use 'as const' for expression-based visualizations
339
+ layer.renderer = {
340
+ type: "simple",
341
+ symbol: { type: "simple-marker" },
342
+ visualVariables: [{
343
+ type: "size",
344
+ valueExpression: "$feature.population / $feature.area",
345
+ stops: [
346
+ { value: 50, size: 4 },
347
+ { value: 500, size: 20 }
348
+ ]
349
+ }]
350
+ } as const;
351
+ ```
352
+
353
+ > **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
354
+
355
+ ## Common Pitfalls
356
+
357
+ 1. **Null values**: Check for nulls with `IsEmpty($feature.field)`
358
+
359
+ 2. **Type coercion**: Use `Number()` or `Text()` for explicit conversion
360
+
361
+ 3. **Case sensitivity**: Arcade is case-insensitive for functions but field names match exactly
362
+
363
+ 4. **Performance**: Complex expressions in renderers can slow performance
364
+
365
+ 5. **Debugging**: Use `Console()` function to debug expressions
366
+
@@ -0,0 +1,301 @@
1
+ ---
2
+ name: arcgis-authentication
3
+ description: Implement authentication with ArcGIS using OAuth 2.0, API keys, and identity management. Use for accessing secured services, portal items, and user-specific content.
4
+ ---
5
+
6
+ # ArcGIS Authentication
7
+
8
+ Use this skill for implementing authentication, OAuth, API keys, and identity management.
9
+
10
+ ## OAuth 2.0 Authentication
11
+
12
+ ### Basic OAuth Setup
13
+ ```javascript
14
+ import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
15
+ import esriId from "@arcgis/core/identity/IdentityManager.js";
16
+ import Portal from "@arcgis/core/portal/Portal.js";
17
+
18
+ // Create OAuthInfo with your app ID
19
+ const oauthInfo = new OAuthInfo({
20
+ appId: "YOUR_APP_ID", // Register at developers.arcgis.com
21
+ popup: false // false = redirect, true = popup window
22
+ });
23
+
24
+ // Register with IdentityManager
25
+ esriId.registerOAuthInfos([oauthInfo]);
26
+ ```
27
+
28
+ ### Check Sign-In Status
29
+ ```javascript
30
+ async function checkSignIn() {
31
+ try {
32
+ await esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing");
33
+ // User is signed in
34
+ const portal = new Portal({ authMode: "immediate" });
35
+ await portal.load();
36
+ console.log("Signed in as:", portal.user.username);
37
+ return portal;
38
+ } catch {
39
+ // User is not signed in
40
+ console.log("Not signed in");
41
+ return null;
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### Sign In
47
+ ```javascript
48
+ async function signIn() {
49
+ try {
50
+ const credential = await esriId.getCredential(
51
+ oauthInfo.portalUrl + "/sharing"
52
+ );
53
+ console.log("Credential obtained:", credential);
54
+ return credential;
55
+ } catch (error) {
56
+ console.error("Sign in failed:", error);
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### Sign Out
62
+ ```javascript
63
+ function signOut() {
64
+ esriId.destroyCredentials();
65
+ window.location.reload();
66
+ }
67
+ ```
68
+
69
+ ### Complete OAuth Flow
70
+ ```javascript
71
+ import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
72
+ import esriId from "@arcgis/core/identity/IdentityManager.js";
73
+ import Portal from "@arcgis/core/portal/Portal.js";
74
+
75
+ const oauthInfo = new OAuthInfo({
76
+ appId: "YOUR_APP_ID"
77
+ });
78
+
79
+ esriId.registerOAuthInfos([oauthInfo]);
80
+
81
+ // Check if already signed in
82
+ esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing")
83
+ .then(() => {
84
+ // Already signed in, load portal
85
+ const portal = new Portal({ authMode: "immediate" });
86
+ return portal.load();
87
+ })
88
+ .then((portal) => {
89
+ console.log("Welcome,", portal.user.fullName);
90
+ displayUserContent(portal);
91
+ })
92
+ .catch(() => {
93
+ // Not signed in, show sign-in button
94
+ showSignInButton();
95
+ });
96
+
97
+ function showSignInButton() {
98
+ const btn = document.getElementById("signInBtn");
99
+ btn.onclick = () => {
100
+ esriId.getCredential(oauthInfo.portalUrl + "/sharing")
101
+ .then(() => {
102
+ window.location.reload();
103
+ });
104
+ };
105
+ }
106
+ ```
107
+
108
+ ## OAuth Component
109
+
110
+ ```html
111
+ <!-- Using OAuth component -->
112
+ <arcgis-oauth app-id="YOUR_APP_ID"></arcgis-oauth>
113
+
114
+ <script type="module">
115
+ const oauthComponent = document.querySelector("arcgis-oauth");
116
+
117
+ oauthComponent.addEventListener("arcgisSignIn", (event) => {
118
+ console.log("Signed in:", event.detail.credential);
119
+ });
120
+
121
+ oauthComponent.addEventListener("arcgisSignOut", () => {
122
+ console.log("Signed out");
123
+ });
124
+ </script>
125
+ ```
126
+
127
+ ## API Keys
128
+
129
+ ### Configure API Key
130
+ ```javascript
131
+ import esriConfig from "@arcgis/core/config.js";
132
+
133
+ // Set API key for accessing services
134
+ esriConfig.apiKey = "YOUR_API_KEY";
135
+
136
+ // Now basemaps and services will use the API key
137
+ const map = new Map({
138
+ basemap: "arcgis/streets" // Requires API key
139
+ });
140
+ ```
141
+
142
+ ### API Key in HTML
143
+ ```html
144
+ <script>
145
+ // Set before loading the SDK
146
+ window.esriConfig = {
147
+ apiKey: "YOUR_API_KEY"
148
+ };
149
+ </script>
150
+ <script src="https://js.arcgis.com/4.34/"></script>
151
+ ```
152
+
153
+ ## Enterprise Portal Authentication
154
+
155
+ ### Configure for Enterprise Portal
156
+ ```javascript
157
+ const oauthInfo = new OAuthInfo({
158
+ appId: "YOUR_APP_ID",
159
+ portalUrl: "https://your-portal.com/portal",
160
+ popup: true
161
+ });
162
+
163
+ esriId.registerOAuthInfos([oauthInfo]);
164
+ ```
165
+
166
+ ### Set Portal URL Globally
167
+ ```javascript
168
+ import esriConfig from "@arcgis/core/config.js";
169
+
170
+ esriConfig.portalUrl = "https://your-portal.com/portal";
171
+ ```
172
+
173
+ ## Token-Based Authentication
174
+
175
+ ### Get Token Manually
176
+ ```javascript
177
+ const credential = await esriId.getCredential("https://services.arcgis.com/...");
178
+ console.log("Token:", credential.token);
179
+ console.log("Expires:", new Date(credential.expires));
180
+ ```
181
+
182
+ ### Register Token
183
+ ```javascript
184
+ esriId.registerToken({
185
+ server: "https://services.arcgis.com/",
186
+ token: "YOUR_TOKEN"
187
+ });
188
+ ```
189
+
190
+ ## Portal User Information
191
+
192
+ ```javascript
193
+ import Portal from "@arcgis/core/portal/Portal.js";
194
+
195
+ const portal = new Portal({ authMode: "immediate" });
196
+ await portal.load();
197
+
198
+ // User info
199
+ console.log("Username:", portal.user.username);
200
+ console.log("Full name:", portal.user.fullName);
201
+ console.log("Email:", portal.user.email);
202
+ console.log("Role:", portal.user.role);
203
+ console.log("Thumbnail:", portal.user.thumbnailUrl);
204
+
205
+ // Organization info
206
+ console.log("Org name:", portal.name);
207
+ console.log("Org ID:", portal.id);
208
+ ```
209
+
210
+ ## Query User Items
211
+
212
+ ```javascript
213
+ import Portal from "@arcgis/core/portal/Portal.js";
214
+ import PortalQueryParams from "@arcgis/core/portal/PortalQueryParams.js";
215
+
216
+ const portal = new Portal({ authMode: "immediate" });
217
+ await portal.load();
218
+
219
+ // Query user's items
220
+ const queryParams = new PortalQueryParams({
221
+ query: `owner:${portal.user.username}`,
222
+ sortField: "modified",
223
+ sortOrder: "desc",
224
+ num: 20
225
+ });
226
+
227
+ const result = await portal.queryItems(queryParams);
228
+
229
+ result.results.forEach(item => {
230
+ console.log(item.title, item.type, item.id);
231
+ });
232
+ ```
233
+
234
+ ## Credential Persistence
235
+
236
+ ```javascript
237
+ // Credentials are stored in localStorage by default
238
+ // Disable persistence
239
+ esriId.useSignInPage = false;
240
+
241
+ // Clear stored credentials
242
+ esriId.destroyCredentials();
243
+
244
+ // Check for stored credentials on load
245
+ const credentials = esriId.credentials;
246
+ ```
247
+
248
+ ## Handling Authentication Errors
249
+
250
+ ```javascript
251
+ // Global handler for authentication challenges
252
+ esriId.on("credential-create", (event) => {
253
+ console.log("New credential created:", event.credential);
254
+ });
255
+
256
+ // Handle layer authentication errors
257
+ layer.on("layerview-create-error", (event) => {
258
+ if (event.error.name === "identity-manager:not-authorized") {
259
+ console.log("Authentication required for this layer");
260
+ signIn();
261
+ }
262
+ });
263
+ ```
264
+
265
+ ## Trusted Servers
266
+
267
+ ```javascript
268
+ import esriConfig from "@arcgis/core/config.js";
269
+
270
+ // Add servers that should receive credentials automatically
271
+ esriConfig.request.trustedServers.push("https://services.arcgis.com");
272
+ esriConfig.request.trustedServers.push("https://your-server.com");
273
+ ```
274
+
275
+ ## CORS and Proxy
276
+
277
+ ```javascript
278
+ import esriConfig from "@arcgis/core/config.js";
279
+
280
+ // Configure proxy for cross-origin requests
281
+ esriConfig.request.proxyUrl = "/proxy/";
282
+
283
+ // Configure proxy rules
284
+ esriConfig.request.proxyRules.push({
285
+ urlPrefix: "https://services.arcgis.com",
286
+ proxyUrl: "/proxy/"
287
+ });
288
+ ```
289
+
290
+ ## Common Pitfalls
291
+
292
+ 1. **App ID registration**: App ID must be registered with correct redirect URIs
293
+
294
+ 2. **Popup blockers**: OAuth popups may be blocked - use redirect flow as fallback
295
+
296
+ 3. **Token expiration**: Tokens expire - handle refresh or re-authentication
297
+
298
+ 4. **CORS errors**: Configure trusted servers or use proxy for cross-origin
299
+
300
+ 5. **Portal URL mismatch**: Ensure portal URL matches exactly (trailing slashes matter)
301
+