esri-gl 0.9.0 → 0.10.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 (49) hide show
  1. package/README.md +375 -35
  2. package/dist/IdentifyImage-DWBF8K_a.js +4277 -0
  3. package/dist/IdentifyImage-DWBF8K_a.js.map +1 -0
  4. package/dist/index-CfCttkZx.d.ts +1535 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +4 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.umd.js +4318 -0
  9. package/dist/index.umd.js.map +1 -0
  10. package/dist/package.json +69 -0
  11. package/dist/react-map-gl.d.ts +102 -0
  12. package/dist/react-map-gl.js +555 -0
  13. package/dist/react-map-gl.js.map +1 -0
  14. package/dist/react.d.ts +116 -0
  15. package/dist/react.js +412 -0
  16. package/dist/react.js.map +1 -0
  17. package/dist/useFeatureService-B0ot0WFz.js +205 -0
  18. package/dist/useFeatureService-B0ot0WFz.js.map +1 -0
  19. package/dist/useFeatureService-BmqltfVc.d.ts +140 -0
  20. package/package.json +103 -47
  21. package/dist/esri-gl.esm.js +0 -2694
  22. package/dist/esri-gl.esm.js.map +0 -1
  23. package/dist/esri-gl.js +0 -2719
  24. package/dist/esri-gl.js.map +0 -1
  25. package/dist/esri-gl.min.js +0 -2
  26. package/dist/esri-gl.min.js.map +0 -1
  27. package/dist/types/Layers/BasemapLayer.d.ts +0 -30
  28. package/dist/types/Layers/DynamicMapLayer.d.ts +0 -75
  29. package/dist/types/Layers/Layer.d.ts +0 -67
  30. package/dist/types/Layers/RasterLayer.d.ts +0 -71
  31. package/dist/types/Services/DynamicMapService.d.ts +0 -35
  32. package/dist/types/Services/FeatureService.d.ts +0 -48
  33. package/dist/types/Services/ImageService.d.ts +0 -32
  34. package/dist/types/Services/MapService.d.ts +0 -30
  35. package/dist/types/Services/MapServiceTypes.d.ts +0 -87
  36. package/dist/types/Services/Service.d.ts +0 -118
  37. package/dist/types/Services/SimpleMapService.d.ts +0 -30
  38. package/dist/types/Services/TiledMapService.d.ts +0 -28
  39. package/dist/types/Services/VectorBasemapStyle.d.ts +0 -9
  40. package/dist/types/Services/VectorTileService.d.ts +0 -41
  41. package/dist/types/Tasks/Find.d.ts +0 -85
  42. package/dist/types/Tasks/IdentifyFeatures.d.ts +0 -91
  43. package/dist/types/Tasks/IdentifyImage.d.ts +0 -107
  44. package/dist/types/Tasks/Query.d.ts +0 -180
  45. package/dist/types/Tasks/Task.d.ts +0 -50
  46. package/dist/types/examples/EsriLeafletStyleAPI.d.ts +0 -9
  47. package/dist/types/main.d.ts +0 -14
  48. package/dist/types/types.d.ts +0 -88
  49. package/dist/types/utils.d.ts +0 -4
package/README.md CHANGED
@@ -2,10 +2,19 @@
2
2
 
3
3
  A TypeScript library that bridges Esri ArcGIS REST services with MapLibre GL JS and Mapbox GL JS. It replicates Esri Leaflet's architecture patterns while being compatible with modern WebGL mapping libraries.
4
4
 
5
+ > **🚧 Development Notice**
6
+ >
7
+ > This project is currently under active development. APIs may change between releases and some features may not be fully stable. Please use with caution in production environments and check the [changelog](CHANGES.md) for breaking changes between versions.
8
+
5
9
  [![npm version](https://badge.fury.io/js/esri-gl.svg)](https://badge.fury.io/js/esri-gl)
6
10
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
7
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
12
 
13
+ ## 🔗 Links
14
+
15
+ - **📚 [Documentation](https://esri-gl.netlify.app/)** - Complete API reference and guides
16
+ - **🎮 [Live Demos](https://esri-gl-demo.netlify.app/)** - Interactive examples and code samples
17
+
9
18
  **Note**: This library is compatible with both **MapLibre GL JS** and **Mapbox GL JS**.
10
19
 
11
20
  ## Features
@@ -28,7 +37,13 @@ A TypeScript library that bridges Esri ArcGIS REST services with MapLibre GL JS
28
37
  - **Layer Definitions** - Filter data server-side using SQL-like expressions
29
38
  - **Time-aware Services** - Support for temporal data visualization
30
39
  - **Attribution Management** - Automatic service attribution handling
40
+ - **React Integration** - Hooks and components for React applications
41
+ - **React Map GL Support** - Direct integration with react-map-gl
31
42
  - **TypeScript Support** - Full type safety with comprehensive interfaces
43
+ - **ArcGIS Online (AGOL) Support** - Proper JSON error handling, token auth, and API key support
44
+ - **Feature Editing** - Add, update, delete features and apply batch edits
45
+ - **Attachments** - Query, add, and delete feature attachments
46
+ - **Query Pagination** - Automatic pagination through large result sets
32
47
 
33
48
  ## Installation
34
49
 
@@ -37,30 +52,7 @@ A TypeScript library that bridges Esri ArcGIS REST services with MapLibre GL JS
37
52
  npm install esri-gl
38
53
  ```
39
54
 
40
- ### Alpha/Beta Releases
41
- ```bash
42
- # Latest alpha release (current: v0.1.0-alpha.2)
43
- npm install esri-gl@alpha
44
55
 
45
- # Specific alpha version
46
- npm install esri-gl@0.1.0-alpha.2
47
-
48
- # Latest beta release
49
- npm install esri-gl@beta
50
- ```
51
-
52
- ### GitHub Packages (Alternative Registry)
53
- ```bash
54
- # Configure npm to use GitHub Packages for @muimsd scope
55
- npm config set @muimsd:registry https://npm.pkg.github.com/
56
-
57
- # Install from GitHub Packages
58
- npm install @muimsd/esri-gl
59
-
60
- # Or use the setup script
61
- ./scripts/github-packages.sh configure
62
- ./scripts/github-packages.sh install
63
- ```
64
56
 
65
57
  ## Quick Start
66
58
 
@@ -174,16 +166,60 @@ const service = new TiledMapService('source-id', map, {
174
166
  ```
175
167
 
176
168
  ### FeatureService
177
- Vector data with intelligent vector tile detection and automatic GeoJSON fallback.
169
+ Efficient tile-based feature loading from ArcGIS FeatureServers with PBF (Protocol Buffer) support for minimal payload size.
178
170
 
179
171
  ```typescript
180
172
  const service = new FeatureService('source-id', map, {
181
173
  url: 'https://example.com/arcgis/rest/services/MyService/FeatureServer/0',
182
- useVectorTiles: true, // Smart detection with fallback
183
- useBoundingBox: true, // Viewport-based loading
184
174
  where: '1=1',
185
175
  outFields: '*',
186
- maxRecordCount: 2000
176
+ // PBF options (requires ArcGIS Server 10.7+)
177
+ minZoom: 2, // Minimum zoom level for data requests
178
+ simplifyFactor: 0.3, // Geometry simplification (0-1)
179
+ precision: 8, // Coordinate decimal precision
180
+ useServiceBounds: true, // Limit requests to service extent
181
+ setAttributionFromService: true // Auto-set attribution
182
+ });
183
+
184
+ // Update filters dynamically
185
+ service.setWhere("STATUS = 'Active'");
186
+ service.setDate(new Date(), new Date('2024-01-01'));
187
+ service.setToken('your-token');
188
+
189
+ // Query features by location
190
+ const features = await service.getFeaturesByLonLat({ lng: -118, lat: 34 }, 100);
191
+
192
+ // Query by object IDs
193
+ const specific = await service.getFeaturesByObjectIds([1, 2, 3], true);
194
+ ```
195
+
196
+ #### Feature Editing (AGOL)
197
+
198
+ ```typescript
199
+ // Edit features on an AGOL Feature Service
200
+ const service = new FeatureService('editable-source', map, {
201
+ url: 'https://services.arcgis.com/.../FeatureServer/0',
202
+ token: 'your-agol-token'
203
+ });
204
+
205
+ // Add features
206
+ const addResults = await service.addFeatures([
207
+ { type: 'Feature', geometry: { type: 'Point', coordinates: [-95, 37] }, properties: { name: 'New Point' } }
208
+ ]);
209
+
210
+ // Update features
211
+ const updateResults = await service.updateFeatures([
212
+ { type: 'Feature', geometry: { type: 'Point', coordinates: [-95, 37] }, properties: { OBJECTID: 1, name: 'Updated' } }
213
+ ]);
214
+
215
+ // Delete features
216
+ const deleteResults = await service.deleteFeatures({ objectIds: [1, 2, 3] });
217
+
218
+ // Batch edits
219
+ const batchResults = await service.applyEdits({
220
+ adds: [newFeature],
221
+ updates: [updatedFeature],
222
+ deletes: [4, 5]
187
223
  });
188
224
  ```
189
225
 
@@ -227,6 +263,15 @@ const service = new VectorBasemapStyle('source-id', map, {
227
263
  });
228
264
  ```
229
265
 
266
+ ```typescript
267
+ // Custom portal item style
268
+ const customBasemap = new VectorBasemapStyle('source-id', map, {
269
+ style: 'arcgis/streets',
270
+ itemId: 'your-portal-item-id',
271
+ token: 'your-token'
272
+ });
273
+ ```
274
+
230
275
  ## Task-Based Operations
231
276
 
232
277
  Modeled after Esri Leaflet's chainable task pattern for querying and identifying features.
@@ -282,6 +327,252 @@ const results = await query({
282
327
  .run();
283
328
  ```
284
329
 
330
+ ```typescript
331
+ // Automatic pagination through all results
332
+ import { query } from 'esri-gl';
333
+
334
+ const allResults = await query({
335
+ url: 'https://example.com/arcgis/rest/services/MyService/FeatureServer/0'
336
+ })
337
+ .where("STATE_NAME = 'California'")
338
+ .runAll(); // Automatically paginates through all pages
339
+ ```
340
+
341
+ ## React Integration
342
+
343
+ esri-gl provides first-class React.js support with comprehensive hooks, components, and seamless integration with **react-map-gl**. Whether you're building with vanilla React + MapLibre/Mapbox or using the react-map-gl wrapper, esri-gl has you covered.
344
+
345
+ ### Installation for React Projects
346
+
347
+ ```bash
348
+ # Core library
349
+ npm install esri-gl
350
+
351
+ # For React hooks and components
352
+ npm install react react-dom @types/react @types/react-dom
353
+
354
+ # For react-map-gl integration (recommended)
355
+ npm install react-map-gl mapbox-gl
356
+ # OR for MapLibre
357
+ npm install react-map-gl maplibre-gl
358
+ ```
359
+
360
+ ### React Hooks Pattern
361
+
362
+ Perfect for custom React components with full control over map lifecycle:
363
+
364
+ ```typescript
365
+ import React, { useState, useRef, useEffect } from 'react';
366
+ import { Map } from 'maplibre-gl';
367
+ import { useDynamicMapService, useIdentifyFeatures, useFeatureService } from 'esri-gl/react';
368
+
369
+ function CustomMapComponent() {
370
+ const mapRef = useRef<HTMLDivElement>(null);
371
+ const [map, setMap] = useState<Map | null>(null);
372
+
373
+ // Initialize MapLibre map
374
+ useEffect(() => {
375
+ if (!mapRef.current) return;
376
+ const mapInstance = new Map({
377
+ container: mapRef.current,
378
+ style: 'https://demotiles.maplibre.org/style.json',
379
+ center: [-95, 37],
380
+ zoom: 4
381
+ });
382
+ setMap(mapInstance);
383
+ return () => mapInstance.remove();
384
+ }, []);
385
+
386
+ // Use esri-gl React hooks
387
+ const { service: dynamicService, loading, error } = useDynamicMapService({
388
+ sourceId: 'usa-service',
389
+ map,
390
+ options: {
391
+ url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer',
392
+ layers: [0, 1, 2],
393
+ transparent: true
394
+ }
395
+ });
396
+
397
+ const { service: featureService } = useFeatureService({
398
+ sourceId: 'states-service',
399
+ map,
400
+ options: {
401
+ url: 'https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Census_States/FeatureServer/0',
402
+ useVectorTiles: true,
403
+ useBoundingBox: true
404
+ }
405
+ });
406
+
407
+ const { identify } = useIdentifyFeatures({
408
+ url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer',
409
+ tolerance: 3
410
+ });
411
+
412
+ // Handle map clicks for identify
413
+ useEffect(() => {
414
+ if (!map) return;
415
+ const handleClick = async (e: any) => {
416
+ const results = await identify({ lng: e.lngLat.lng, lat: e.lngLat.lat }, map);
417
+ console.log('Identify results:', results);
418
+ };
419
+ map.on('click', handleClick);
420
+ return () => map.off('click', handleClick);
421
+ }, [map, identify]);
422
+
423
+ return (
424
+ <div>
425
+ <div ref={mapRef} style={{ width: '100%', height: '500px' }} />
426
+ {loading && <div>Loading Esri services...</div>}
427
+ {error && <div>Error: {error.message}</div>}
428
+ </div>
429
+ );
430
+ }
431
+ ```
432
+
433
+ ### React Map GL Components (Recommended)
434
+
435
+ For the smoothest React experience with declarative layer management:
436
+
437
+ ```typescript
438
+ import React, { useState } from 'react';
439
+ import { Map } from 'react-map-gl/mapbox';
440
+ import {
441
+ EsriDynamicLayer,
442
+ EsriFeatureLayer,
443
+ EsriVectorTileLayer,
444
+ EsriImageLayer
445
+ } from 'esri-gl/react-map-gl';
446
+
447
+ function MapWithEsriLayers() {
448
+ const [viewState, setViewState] = useState({
449
+ longitude: -95,
450
+ latitude: 37,
451
+ zoom: 4
452
+ });
453
+
454
+ const [selectedStates, setSelectedStates] = useState<string[]>([]);
455
+
456
+ return (
457
+ <Map
458
+ {...viewState}
459
+ onMove={evt => setViewState(evt.viewState)}
460
+ mapStyle="mapbox://styles/mapbox/streets-v11"
461
+ style={{ width: '100%', height: '600px' }}
462
+ >
463
+ {/* Dynamic Map Service Layer */}
464
+ <EsriDynamicLayer
465
+ id="usa-demographics"
466
+ url="https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer"
467
+ layers={[0, 1, 2]}
468
+ layerDefs={{
469
+ 0: "POP2000 > 100000",
470
+ 1: "STATE_NAME IN ('California', 'Texas', 'New York')"
471
+ }}
472
+ opacity={0.8}
473
+ beforeId="waterway-label"
474
+ />
475
+
476
+ {/* Feature Service with Vector Tiles */}
477
+ <EsriFeatureLayer
478
+ id="us-states"
479
+ url="https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Census_States/FeatureServer/0"
480
+ useVectorTiles={true}
481
+ useBoundingBox={true}
482
+ where={selectedStates.length > 0 ? `STATE_NAME IN ('${selectedStates.join("','")}')` : undefined}
483
+ paint={{
484
+ 'fill-color': [
485
+ 'case',
486
+ ['in', ['get', 'STATE_NAME'], ['literal', selectedStates]],
487
+ '#ff6b6b',
488
+ '#627BC1'
489
+ ],
490
+ 'fill-opacity': 0.6,
491
+ 'fill-outline-color': '#ffffff'
492
+ }}
493
+ onClick={(feature) => {
494
+ const stateName = feature.properties?.STATE_NAME;
495
+ if (stateName) {
496
+ setSelectedStates(prev =>
497
+ prev.includes(stateName)
498
+ ? prev.filter(s => s !== stateName)
499
+ : [...prev, stateName]
500
+ );
501
+ }
502
+ }}
503
+ />
504
+
505
+ {/* Vector Tile Service */}
506
+ <EsriVectorTileLayer
507
+ id="world-imagery-labels"
508
+ url="https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/VectorTileServer"
509
+ beforeId="usa-demographics"
510
+ />
511
+
512
+ {/* Image Service for Analytical Data */}
513
+ <EsriImageLayer
514
+ id="elevation-hillshade"
515
+ url="https://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/ImageServer"
516
+ renderingRule={{
517
+ rasterFunction: "Hillshade",
518
+ rasterFunctionArguments: {
519
+ Azimuth: 315,
520
+ Altitude: 45
521
+ }
522
+ }}
523
+ opacity={0.5}
524
+ />
525
+ </Map>
526
+ );
527
+ }
528
+ ```
529
+
530
+ ### Why Choose React Integration?
531
+
532
+ #### React Hooks Benefits
533
+ - **🎛️ Full Control** - Direct access to map instance and service lifecycle
534
+ - **🔄 State Management** - Seamless integration with React state and effects
535
+ - **🎯 Custom Logic** - Perfect for complex interactions and custom components
536
+ - **📦 Lightweight** - Use only what you need
537
+
538
+ #### React Map GL Benefits
539
+ - **📋 Declarative** - Define layers as JSX components
540
+ - **🔄 Automatic Updates** - Props changes automatically update layers
541
+ - **🎨 Built-in Styling** - Direct paint and layout prop support
542
+ - **👆 Event Handling** - onClick, onHover events built-in
543
+ - **🏗️ Component Ecosystem** - Works with all react-map-gl features
544
+
545
+ ### TypeScript Support
546
+
547
+ Full TypeScript support with comprehensive type definitions:
548
+
549
+ ```typescript
550
+ import type {
551
+ DynamicMapServiceOptions,
552
+ FeatureServiceOptions,
553
+ IdentifyResult,
554
+ EsriLayerProps
555
+ } from 'esri-gl';
556
+ import type { MapRef } from 'react-map-gl/mapbox';
557
+
558
+ // Fully typed component props
559
+ interface MapComponentProps {
560
+ serviceUrl: string;
561
+ initialLayers?: number[];
562
+ onFeatureClick?: (feature: IdentifyResult) => void;
563
+ }
564
+
565
+ const TypedMapComponent: React.FC<MapComponentProps> = ({
566
+ serviceUrl,
567
+ initialLayers = [0],
568
+ onFeatureClick
569
+ }) => {
570
+ // Component implementation with full type safety
571
+ };
572
+ ```
573
+
574
+ See [REACT.md](REACT.md) for complete React integration documentation and advanced patterns.
575
+
285
576
  ## Advanced Features
286
577
 
287
578
  ### Dynamic Layer Management
@@ -332,14 +623,33 @@ const service = new FeatureService('optimized-source', map, {
332
623
  });
333
624
  ```
334
625
 
626
+ ### Authentication
627
+
628
+ ```typescript
629
+ // Token-based authentication (URL parameter)
630
+ const service = new DynamicMapService('secure-source', map, {
631
+ url: 'https://example.com/arcgis/rest/services/SecureService/MapServer',
632
+ token: 'your-auth-token'
633
+ });
634
+
635
+ // Update token dynamically
636
+ service.setToken('new-token');
637
+
638
+ // API Key authentication (X-Esri-Authorization header)
639
+ const featureService = new FeatureService('api-key-source', map, {
640
+ url: 'https://services.arcgis.com/.../FeatureServer/0',
641
+ apiKey: 'your-api-key' // Sent as X-Esri-Authorization: Bearer header
642
+ });
643
+ ```
644
+
335
645
  ## Development
336
646
 
337
647
  ### Build System
338
- - **Library Build**: Rollup with `@rollup/plugin-typescript` (UMD + ESM outputs)
339
- - **Type Declarations**: Consolidated in `dist/types/` directory
340
- - **Demo Development**: Vite dev server
648
+ - **Library Build**: Rollup with TypeScript, Babel, and Terser (UMD + ESM outputs)
649
+ - **Type Declarations**: Generated with rollup-plugin-dts in `dist/` directory
650
+ - **Demo Development**: Vite dev server with React and TypeScript
341
651
  - **Documentation**: Docusaurus build system
342
- - **Test Coverage**: 92.94% with 651 focused test cases
652
+ - **Test Coverage**: 717 comprehensive test cases across 31 test suites
343
653
 
344
654
  ### Development Commands
345
655
 
@@ -391,9 +701,13 @@ src/
391
701
  └── types.ts # TypeScript interfaces
392
702
 
393
703
  dist/
394
- ├── types/ # Consolidated TypeScript declarations
395
- ├── esri-gl.js # UMD build
396
- ├── esri-gl.esm.js # ESM build
704
+ ├── index.d.ts # Main TypeScript declarations
705
+ ├── react.d.ts # React integration declarations
706
+ ├── react-map-gl.d.ts # React Map GL declarations
707
+ ├── index.js # ESM build
708
+ ├── index.umd.js # UMD build
709
+ ├── esri-gl.esm.js # ESM build (legacy)
710
+ ├── esri-gl.js # UMD build (legacy)
397
711
  └── esri-gl.min.js # Minified UMD build
398
712
  ```
399
713
 
@@ -422,10 +736,12 @@ const options: FeatureServiceOptions = {
422
736
  };
423
737
  ```
424
738
 
425
- All type declarations are available in the `dist/types/` directory after building.
739
+ All type declarations are available in the `dist/` directory after building.
426
740
 
427
741
  ## Contributing
428
742
 
743
+ We welcome contributions! Please follow these steps:
744
+
429
745
  1. Fork the repository
430
746
  2. Create a feature branch: `git checkout -b feature/my-feature`
431
747
  3. Make changes and add tests
@@ -434,6 +750,17 @@ All type declarations are available in the `dist/types/` directory after buildin
434
750
  6. Push to branch: `git push origin feature/my-feature`
435
751
  7. Submit a pull request
436
752
 
753
+ ### Pre-commit Hooks
754
+
755
+ This project uses [Husky](https://typicode.github.io/husky/) to automatically run quality checks before each commit:
756
+
757
+ - **Formatting & Linting**: Automatically formats and lints staged files using Prettier and ESLint
758
+ - **Testing**: Runs the full test suite to ensure no regressions
759
+
760
+ The hooks are automatically installed when you run `npm install`. If you need to skip them (not recommended), you can use `git commit --no-verify`.
761
+
762
+ For more details, see [.husky/README.md](.husky/README.md).
763
+
437
764
  ## License
438
765
 
439
766
  MIT License - see [LICENSE](LICENSE) file for details.
@@ -444,3 +771,16 @@ MIT License - see [LICENSE](LICENSE) file for details.
444
771
  - **MapLibre GL JS** & **Mapbox GL JS** - Incredible WebGL mapping libraries
445
772
  - **Esri ArcGIS Platform** - Comprehensive GIS services and APIs
446
773
  - **[mapbox-gl-esri-sources](https://github.com/frontiersi/mapbox-gl-esri-sources/)** - Reference implementation for Esri service integration patterns
774
+ - **[mapbox-gl-arcgis-featureserver](https://github.com/rowanwins/mapbox-gl-arcgis-featureserver)** by **Rowan Winsemius** - The FeatureService implementation with PBF support is based on this excellent library. It provides efficient tile-based feature loading with Protocol Buffer Format (PBF) support for minimal payload size.
775
+
776
+ ## Fork Notice
777
+
778
+ This project originated as a fork of **[frontiersi/mapbox-gl-esri-sources](https://github.com/frontiersi/mapbox-gl-esri-sources/)**. It has been substantially refactored and expanded:
779
+
780
+ - Migrated to a service + task architecture similar to Esri Leaflet
781
+ - Added unified TypeScript typing and consolidated build outputs (ESM + UMD)
782
+ - Introduced additional services (Dynamic, Image, Vector Basemap Styles, Identify / Query tasks, smart FeatureService vector tile detection, etc.)
783
+ - Implemented a React/Vite demo suite and extended test coverage
784
+
785
+ All original credit for the foundational concept and early integration patterns goes to the maintainers of the upstream repository. If you need the simpler original implementation, or want to compare behavior, please visit the upstream project.
786
+