maplibre-gl-js-amplify
Version:
MapLibre Plugin to Support Amplify Geo Integration
137 lines (136 loc) • 7.35 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMap = void 0;
const core_1 = require("@aws-amplify/core");
const utils_1 = require("@aws-amplify/core/internals/utils");
const geo_1 = require("@aws-amplify/geo");
const maplibre_gl_1 = require("maplibre-gl");
const utils_2 = require("./utils");
/**
* An object for encapsulating an Amplify Geo transform request and Amplify credentials
* @class AmplifyMapLibreRequest
* @param {ICredentials} currentCredentials Amplify credentials used for signing transformRequests
* @param {String} region AWS region
* @return {AmplifyMapLibreRequest} `this`
*
*/
class AmplifyMapLibreRequest {
constructor(currentCredentials, region) {
this.refreshCredentials = () => __awaiter(this, void 0, void 0, function* () {
try {
this.credentials = (yield (0, core_1.fetchAuthSession)()).credentials;
}
catch (e) {
// eslint-disable-next-line no-console
console.error(`Failed to refresh credentials: ${e}`);
throw e;
}
});
this.refreshCredentialsWithRetry = () => __awaiter(this, void 0, void 0, function* () {
try {
const MAX_DELAY_MS = 5 * 60 * 1000; // 5 minutes
yield (0, utils_1.jitteredExponentialRetry)(this.refreshCredentials, [], MAX_DELAY_MS);
// Refresh credentials on a timer because HubEvents do not trigger on credential refresh currently
this.activeTimeout && clearTimeout(this.activeTimeout);
// Refresh credentials when expiration time is later than now
if (this.credentials.expiration.getTime() > new Date().getTime()) {
const expiration = new Date(this.credentials.expiration);
const timeout = expiration.getTime() - new Date().getTime() - 10000; // Adds a 10 second buffer time before the next refresh
this.activeTimeout = window.setTimeout(this.refreshCredentialsWithRetry, Math.min(timeout, 3600000) // Set timeout to an hour if we somehow don't have a value for timeout
);
}
}
catch (e) {
// eslint-disable-next-line no-console
console.error(`Failed to refresh credentials: ${e}`);
}
});
/**
* A callback function that can be passed to a maplibre map object that is run before the map makes a request for an external URL. This transform request is used to sign the request with AWS Sigv4 Auth. [https://maplibre.org/maplibre-gl-js-docs/api/map/](https://maplibre.org/maplibre-gl-js-docs/api/map/)
* @param {string} url
* @param {string} resourceType
* @returns {RequestParameters} [https://maplibre.org/maplibre-gl-js-docs/api/properties/#requestparameters](https://maplibre.org/maplibre-gl-js-docs/api/properties/#requestparameters)
*/
this.transformRequest = (url, resourceType) => {
let styleUrl = url;
if (resourceType === 'Style' && !url.includes('://')) {
if (this.region == undefined) {
throw new Error('AWS region for map is undefined. Please verify that the region is set in aws-exports.js or that you are providing an AWS region parameter to createMap');
}
styleUrl = `https://maps.geo.${this.region}.amazonaws.com/maps/v0/maps/${url}/style-descriptor`;
}
const urlObject = new URL(styleUrl);
if (urlObject.hostname.endsWith('.amazonaws.com')) {
// only sign AWS requests (with the signature as part of the query string)
urlObject.searchParams.append('x-amz-user-agent', encodeURIComponent((0, utils_2.urlEncodePeriods)(getAmplifyUserAgentString())));
return {
url: utils_1.Signer.signUrl(urlObject.href, {
access_key: this.credentials.accessKeyId,
secret_key: this.credentials.secretAccessKey,
session_token: this.credentials.sessionToken,
}),
};
}
};
this.credentials = currentCredentials;
this.region = region;
this.activeTimeout = null;
this.refreshCredentialsWithRetry();
core_1.Hub.listen('auth', (data) => {
switch (data.payload.event) {
// This was removed from v6 but will be added back before GA
case 'signedIn':
case 'signedOut':
case 'tokenRefresh':
this.refreshCredentialsWithRetry();
break;
}
});
}
}
exports.default = AmplifyMapLibreRequest;
_a = AmplifyMapLibreRequest;
AmplifyMapLibreRequest.createMapLibreMap = (options) => __awaiter(void 0, void 0, void 0, function* () {
const { region, mapConstructor = maplibre_gl_1.Map } = options, maplibreOption = __rest(options, ["region", "mapConstructor"]);
const defaultMap = geo_1.Geo.getDefaultMap();
const amplifyRequest = new AmplifyMapLibreRequest((yield (0, core_1.fetchAuthSession)()).credentials, region || defaultMap.region);
const transformRequest = amplifyRequest.transformRequest;
const map = new mapConstructor(Object.assign(Object.assign({}, maplibreOption), { style: options.style || defaultMap.mapName, // Amplify uses the name of the map in the maplibre style field,
transformRequest }));
return map;
});
const createMap = (options) => __awaiter(void 0, void 0, void 0, function* () {
return AmplifyMapLibreRequest.createMapLibreMap(options);
});
exports.createMap = createMap;
// TODO - Delete this and import from @aws-amplify/core when it is released
function getAmplifyUserAgentString() {
const userAgent = (0, utils_1.getAmplifyUserAgent)();
if (userAgent && typeof userAgent === 'object') {
return userAgent
.map(([agentKey, agentValue]) => `${agentKey}/${agentValue}`)
.join(' ');
}
return userAgent;
}