flamesshield-sdk
Version:
Flames Shield Smart rate limiting for Firebase Cloud Functions to protect your services from excessive requests
105 lines (104 loc) • 4.79 kB
JavaScript
;
// index.ts
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.rateLimit = void 0;
const rate_limiter_1 = require("./rate_limiter");
const remote_1 = require("./remote");
const rate_limiting_enabled_1 = require("./rate_limiting_enabled");
const configuration_retriever_1 = require("./configuration_retriever");
const version_1 = require("./version"); // Import from the auto-generated version file
const checkAndUpdateQuota = (limiter) => __awaiter(void 0, void 0, void 0, function* () {
const apiKey = limiter.apiKey || process.env.API_KEY;
if (!apiKey) {
throw new Error('API key not provided');
}
if (!limiter.name) {
throw new Error('Function name not provided');
}
if (limiter.verbose) {
console.log(`[FlameShield] Checking quota for function: ${limiter.name}, max calls: ${limiter.maxCalls}, period: ${limiter.periodSeconds}s`);
}
const p = yield (0, remote_1.remotePost)({
functionName: limiter.name,
qualifier: limiter.qualifier,
maxCalls: limiter.maxCalls,
periodSeconds: limiter.periodSeconds,
version: version_1.VERSION // Use the hard-coded version from our provider
}, apiKey, limiter.remoteUrl, { verbose: limiter.verbose });
if (limiter.verbose) {
console.log(`[FlameShield] Quota check result: ${p ? 'exceeded' : 'within limits'}`);
}
return p;
});
class ConfigurationRetrieverSingleton {
constructor() { }
static getInstance(app) {
if (!ConfigurationRetrieverSingleton.instance) {
ConfigurationRetrieverSingleton.instance = new configuration_retriever_1.ConfigurationRetriever(app);
}
return ConfigurationRetrieverSingleton.instance;
}
}
const rateLimit = (struct) => __awaiter(void 0, void 0, void 0, function* () {
// Default verbose to false if not provided
const configuration = Object.assign(Object.assign({}, struct), { verbose: struct.verbose || false });
const functionName = configuration.name ||
process.env.FUNCTION_TARGET ||
process.env.K_SERVICE ||
process.env.FUNCTION_NAME;
if (!functionName) {
throw new Error('Function name not provided');
}
configuration.name = functionName;
if (configuration.verbose) {
console.log(`[FlameShield] Processing rate limit for function: ${functionName}`);
}
yield ConfigurationRetrieverSingleton.getInstance(configuration.app).load();
const rateLimit = new rate_limiting_enabled_1.RateLimitingEnabled(functionName, ConfigurationRetrieverSingleton.getInstance(configuration.app), { verbose: configuration.verbose });
if (configuration.verbose) {
console.log(`[FlameShield] Rate limiting enabled for ${functionName}: ${rateLimit.enabled}`);
}
if (!rateLimit.enabled) {
if (configuration.verbose) {
console.log(`[FlameShield] Rate limiting disabled, proceeding with function execution`);
}
return configuration.onSuccess();
}
const updatedQuota = () => {
return checkAndUpdateQuota(configuration);
};
// Pass the verbose option to the RateLimiter constructor
const limiter = new rate_limiter_1.RateLimiter(updatedQuota, { verbose: configuration.verbose });
if (configuration.verbose) {
console.log(`[FlameShield] Checking and updating quota`);
}
const quotaExceeded = yield limiter.checkAndUpdateQuota();
if (!quotaExceeded) {
if (configuration.verbose) {
console.log(`[FlameShield] Quota not exceeded, proceeding with function execution`);
}
return configuration.onSuccess();
}
else if (configuration.onFailure) {
if (configuration.verbose) {
console.log(`[FlameShield] Quota exceeded, executing failure handler`);
}
return configuration.onFailure();
}
else {
if (configuration.verbose) {
console.log(`[FlameShield] Quota exceeded, throwing error`);
}
throw new Error('Rate limit exceeded');
}
});
exports.rateLimit = rateLimit;