Git Product home page Git Product logo

firebase-functions-rate-limiter's Introduction

Firebase functions rate limiter

npm Code coverage License PRs Welcome

Q: How to limit rate of firebase function calls? A: Use firebase-functions-rate-limiter

Mission: limit number of calls per specified period of time

Key features:

  • Two backends: Realtime Database (efficient) or Firestore (convenient)
  • Easy: call single function, no configuration
  • Efficient: only a single call read call to database (or firestore), two calls if limit not exceeded and usage is recorded
  • Concurrent-safe: uses atomic transactions in both backends
  • Clean: Uses only one key (or collection in firestore backend), creates single document for each qualifier. Does not leave rubbish in your database.
  • Typescript typings included
  • No firebase configuration required. You do not have to create any indexes or rules.
  • .mock() factory to make functions testing easier
  • Works with NodeJS 12, 14, 16, 18

Installation

$ npm install --save firebase-functions-rate-limiter

Then:

import FirebaseFunctionsRateLimiter from "firebase-functions-rate-limiter";
// or
const { FirebaseFunctionsRateLimiter } = require("firebase-functions-rate-limiter");

Usage

Example 1: limit calls for everyone:

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { FirebaseFunctionsRateLimiter } from "firebase-functions-rate-limiter";

admin.initializeApp(functions.config().firebase);
const database = admin.database();

const limiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
    {
        name: "rate_limiter_collection",
        maxCalls: 2,
        periodSeconds: 15,
    },
    database,
);
exports.testRateLimiter = 
  functions.https.onRequest(async (req, res) => {
    await limiter.rejectOnQuotaExceededOrRecordUsage(); // will throw HttpsException with proper warning

    res.send("Function called");
});

You can use two functions: limiter.rejectOnQuotaExceededOrRecordUsage(qualifier?) will throw an functions.https.HttpsException when limit is exceeded while limiter.isQuotaExceededOrRecordUsage(qualifier?) gives you the ability to choose how to handle the situation.

Example 2: limit calls for each user separately (function called directly - please refer firebase docs on this topic):

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { FirebaseFunctionsRateLimiter } from "firebase-functions-rate-limiter";

admin.initializeApp(functions.config().firebase);
const database = admin.database();

const perUserlimiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
    {
        name: "per_user_limiter",
        maxCalls: 2,
        periodSeconds: 15,
    },
    database,
);

exports.authenticatedFunction = 
  functions.https.onCall(async (data, context) => {
    if (!context.auth || !context.auth.uid) {
        throw new functions.https.HttpsError(
            "failed-precondition",
            "Please authenticate",
        );
    }
    const uidQualifier = "u_" + context.auth.uid;
    const isQuotaExceeded = await perUserlimiter.isQuotaExceededOrRecordUsage(uidQualifier);
    if (isQuotaExceeded) {
        throw new functions.https.HttpsError(
            "failed-precondition",
            "Call quota exceeded for this user. Try again later",
        );
    }
  
    return { result: "Function called" };
});

Step-by-step

#1 Initialize admin app and get Realtime database object

admin.initializeApp(functions.config().firebase);
const database = admin.database();

#2 Create limiter object outside of the function scope and pass the configuration and Database object. Configuration options are listed below.

const someLimiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
    {
        name: "limiter_some",
        maxCalls: 10,
        periodSeconds: 60,
    },
    database,
);

#3 Inside the function call isQuotaExceededOrRecordUsage. This is an async function so not forget about await! The function will check if the limit was exceeded. If limit was not exceeded it will record this usage and return true. Otherwise, write will be only called if there are usage records that are older than the specified period and are about to being cleared.

exports.testRateLimiter = 
  functions.https.onRequest(async (req, res) => {
    const quotaExceeded = await limiter.isQuotaExceededOrRecordUsage();
    if (quotaExceeded) {
    	// respond with error
    } else {
      // continue
    }

#3 with qualifier. Optionally you can pass a qualifier to the function. A qualifier is a string that identifies a separate type of call. If you pass a qualifier, the limit will be recorded per each distinct qualifier and won't sum up.

exports.testRateLimiter = 
  functions.https.onRequest(async (req, res) => {
    const qualifier = "user_1";
    const quotaExceeded = await limiter.isQuotaExceededOrRecordUsage(qualifier);
    if (quotaExceeded) {
    	// respond with error
    } else {
      // continue
    }

Configuration

const configuration = {
  name: // a collection with this name will be created
  periodSeconds: // the length of test period in seconds
  maxCalls: // number of maximum allowed calls in the period
  debug: // boolean (default false)
};

Choose backend:

const limiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(configuration, database)
// or
const limiter = FirebaseFunctionsRateLimiter.withFirestoreBackend(configuration, firestore)
// or, for functions unit testing convenience:
const limiter = FirebaseFunctionsRateLimiter.mock()

Methods

  • isQuotaExceededOrRecordUsage(qualifier?: string) — Checks if quota was exceed. If not — it records the call time in the appropriate backend.

  • rejectOnQuotaExceededOrRecordUsage(qualifier?: string, errorFactory?: (configuration) => Error) — Checks if quota was exceed. If not — it records the call time in the appropriate backend and is rejected with functions.https.HttpsException. This particular exception can be caught when calling the firebase function directly (see https://firebase.google.com/docs/functions/callable). When errorFactory is provided, it is used to obtain error that is thrown in case of exceeded limit.

  • isQuotaAlreadyExceeded(qualifier?: string) — Checks if quota was exceed, but does not record a usage. If you use this, you must call isQuotaExceededOrRecordUsage() to record the usage.

  • getConfiguration() — Returns this rate limiter configuration.

  • isQuotaExceeded(qualifier?: string)deprecated: renamed to isQuotaExceededOrRecordUsage

  • rejectOnQuotaExceeded(qualifier?: string)deprecated: renamed to rejectOnQuotaExceededOrRecordUsage

Why is there no recordUsage() method?** This library uses a document-per-qualifier data model which requires a read call before the update call. Read-and-update is performed inside an atomic transaction in both backend. It would not be concurrency-safe if the read-and-update transaction was split into separate calls.

Firebase configuration

There is no configuration needed in the firebase. This library does not do document search, so you do not need indexes. Also, functions are executed in the firebase admin environment, so you do not have to specify any rules.

Need help?

Would like to help?

Warmly welcomed:

  • Bug reports via issues
  • Enhancement requests via via issues
  • Pull requests
  • Security reports to [email protected]

Made with ❤️ by Jędrzej Lewandowski.

firebase-functions-rate-limiter's People

Contributors

jblew avatar jondcallahan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

firebase-functions-rate-limiter's Issues

BUG: Multiple calls made at the same time are counting as 1 call

When performing some tests, calls done one after the other are "using a single token" because of them getting the exact same timestamp in seconds.

Using milliseconds for the timestamps or using a slightly different approach for registering the usage of 'tokens' should fix this issue.

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository with URL https://[secure]@github.com/Jblew/firebase-functions-rate-limiter.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment and make sure the repositoryUrl is configured with a valid Git URL.


Good luck with your project ✨

Your semantic-release bot 📦🚀

FEATURE - Cooldown penalty period after exceeding limit

For example, a user can only make 10 requests every 5 seconds. If a user exceeds the limit (11 calls in the 5 seconds window), they can be penalised (for example - one hour) before they are able to make requests again.

It appears your code is written in Typescript, which must be compiled before emulation

Hi, thanks for the package.

I have issue when running this with an emulator locally. This is my code

const admin = require("firebase-admin");
const functions = require('firebase-functions');
const FirebaseFunctionsRateLimiter = require("firebase-functions-rate-limiter");

const serviceAccount = require("service-account.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://firebase-url-here.firebaseio.com",
});

// const database = admin.database();
const firestore = admin.firestore();

const limiter = FirebaseFunctionsRateLimiter.withFirestoreBackend(
  {
    name: "rate_limiter_collection",
    maxCalls: 2,
    periodSeconds: 15,
  },
  firestore
);

exports.helloWorld = functions.https.onRequest(async (request, response) => {
  await limiter.rejectOnQuotaExceededOrRecordUsage();

  response.send("Hello from Firebase!");
});

When running firebase emulators:start then it gives me errors below:

⚠  TypeError: FirebaseFunctionsRateLimiter.withFirestoreBackend is not a function
    at Object.<anonymous> (/home/bolt/dev/console/firebase/functions/index.js:15:46)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at /usr/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:650:33
    at Generator.next (<anonymous>)
⚠  We were unable to load your functions code. (see above)
   - It appears your code is written in Typescript, which must be compiled before emulation.

I use javascript mode in my firebase setup.

Any idea for this? Thanks

Enhancement: check if quota exceeded without recording usage

If I understand correctly, isQuotaExceeded records a usage against the limiter's quota. Is/could there be a feature to check if the quota is exceeded without counting a usage against the quota? I would like to avoid an expensive operation if the quota is already exceeded without incrementing the usage. For example:

const perUserAuthFailsLimiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend({
    name: "perUserAuthFails_limiter",
    maxCalls: 5,
    periodSeconds: 60 * 60,
}, database);

exports.tryAuth = functions.https.onRequest(async (req, res) => {
    //...

    //aspirational feature enhancement: checkQuotaAlreadyExceeded() or something
    const quotaAlreadyExceeded = await authFailsLimiter.checkQuotaAlreadyExceeded(req.body.username);

    if (quotaAlreadyExceeded) {
        return res.status(429);
        //function execution stops and doesn't continue with unnecessary auth request
    }

    //I would like to avoid hitting the auth server if the quota is already exceeded, but this shouldn't count as an auth failure (since the user's password could have been correct)
    const isAuthenticated = await authenticateUser(req.body.username, req.body.password);
    if (!isAuthenticated) {
        const quotaExceeded = await perUserAuthFailsLimiter.isQuotaExceeded(req.body.username);
        if (quotaExceeded) {
            return res.status(429);
        } else {
            return res.status(200);
        }
    } else {
        return res.status(200);
    }

})

Explicitly add field "expireAt" on the limiter entries in Firestore

Motivation / Context

I'm using the firebase-functions-rate-limiter library, and I need the ability to automatically remove entries from Firestore that are no longer in use. Currently, the library does not provide a built-in mechanism to set an expireAt field for Firestore entries.

Description

I kindly request the addition of a feature that allows users to automatically create an expireAt field for Firestore entries when configuring the rate limiter, based on the provided periodSeconds value. This enhancement would simplify the management of rate limiter entries and enable automatic cleanup based on the defined expiration time.

Proposed Implementation:

When configuring the rate limiter, we are allowed to set a periodSeconds value, which defines the time span during which rate limiter entries are valid.

When a rate limiter entry is first created or checked, we need to automatically create an expireAt field in Firestore, calculated as the current timestamp plus the specified periodSeconds.

Additional context

Based on this field "expireAt", we can setup a TTL policy: https://firebase.google.com/docs/firestore/ttl

building from src TS

Getting errors when building whenever I import FirebaseFunctionsRateLimiter.

Any ideas?

code I use

export const rateLimiter =  async  (req: Request, res: Response, next: NextFunction) => {
    const someLimiter =   FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
        {
            name: "limiter_some",
            maxCalls: 10,
            periodSeconds: 60,
        },
        admin.database(),
    );
    const qualifier = "u_" + req.app.locals.user.uid;
    const quotaExceeded = await someLimiter.isQuotaExceededOrRecordUsage(qualifier);
    if (quotaExceeded) {
        // respond with error
        res.send("error")
    } else {
        next()

    }
};

Error i get from TS
image

Feature request: reset usage

Please add a feature to reset the usage of an identifier, for example to allow unlocking an account that was throttled for exceeding quota.

Definitions conflict

Description

Trying to add the package in my project, I'm getting build errors

node_modules/@google-cloud/firestore/types/firestore.d.ts:23:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: DocumentData, UpdateData, Firestore, GeoPoint, 
Transaction, BulkWriter, BulkWriterError, WriteBatch, SetOptions, WriteResult, DocumentReference, DocumentSnapshot, QueryDocumentSnapshot, OrderByDirection, WhereFilterOp, Query, QuerySnapshot, DocumentChangeType, CollectionReference, CollectionGroup, QueryPartition, FieldValue, FieldPath, Timestamp, BundleBuilder, v1beta1, v1, OK, CANCELLED, UNKNOWN, INVALID_ARGUMENT, DEADLINE_EXCEEDED, NOT_FOUND, ALREADY_EXISTS, PERMISSION_DENIED, RESOURCE_EXHAUSTED, FAILED_PRECONDITION, ABORTED, OUT_OF_RANGE, UNIMPLEMENTED, INTERNAL, UNAVAILABLE, DATA_LOSS, UNAUTHENTICATED, FirebaseFirestore
node_modules/firebase-functions-rate-limiter/node_modules/@google-cloud/firestore/types/firestore.d.ts:23:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: DocumentData, UpdateData, Firestore, GeoPoint, Transaction, BulkWriter, BulkWriterError, WriteBatch, SetOptions, WriteResult, DocumentReference, DocumentSnapshot, QueryDocumentSnapshot, OrderByDirection, WhereFilterOp, Query, QuerySnapshot, DocumentChangeType, CollectionReference, CollectionGroup, QueryPartition, FieldValue, FieldPath, Timestamp, BundleBuilder, v1beta1, v1, OK, CANCELLED, UNKNOWN, INVALID_ARGUMENT, DEADLINE_EXCEEDED, NOT_FOUND, ALREADY_EXISTS, PERMISSION_DENIED, RESOURCE_EXHAUSTED, FAILED_PRECONDITION, ABORTED, OUT_OF_RANGE, UNIMPLEMENTED, INTERNAL, UNAVAILABLE, DATA_LOSS, UNAUTHENTICATED, 
FirebaseFirestore

To Reproduce

  1. Firebase functions project, node 16
"firebase-admin": "^11.1.0",
"firebase-functions": "^4.0.0",
"firebase-functions-rate-limiter": "^3.9.1",
"typescript": "^4.8.4"
  1. npm run build

Environment

Expected Behavior

A successful build

Screenshots

image
image

Additional context

Error: The default Firebase app does not exist. when creating limiter object in non root file & outside of function scope

I'm initializing admin in my root functions file(index.js).
if I create a limiter object in root index.js file no error is thrown. However, in my case i'm trying to set a limiter in subfolder file i.e (api/emailsend.js)

If i try to create rateLimiter outside of the function and outside of root file where I initialized admin I the following error:
Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.

the error is due to me calling admin.firestore() inside this libs FirebaseFunctionsRateLimiter.withFirestoreBackend function. As it seems the admin.initializeApp({}) has not completed when rateLimiter is creation is invoked .

Any suggestions?

Please update deps

You're still on firebase-admin 9, which has a "high severity vulnerability" on node-forge as reported by npm audit:

# npm audit report

node-forge  <=1.2.1
Severity: high
Improper Verification of Cryptographic Signature in node-forge - https://github.com/advisories/GHSA-x4jg-mjrx-434g
Improper Verification of Cryptographic Signature in `node-forge` - https://github.com/advisories/GHSA-2r2c-g63r-vccr
Improper Verification of Cryptographic Signature in node-forge - https://github.com/advisories/GHSA-cfm4-qjh2-4765
Open Redirect in node-forge - https://github.com/advisories/GHSA-8fr3-hfg3-gpgp
Prototype Pollution in node-forge debug API. - https://github.com/advisories/GHSA-5rrq-pxf6-6jx5
URL parsing in node-forge could lead to undesired behavior. - https://github.com/advisories/GHSA-gf8q-jrpm-jvxq
No fix available
node_modules/firebase-functions-rate-limiter/node_modules/node-forge
  firebase-admin  5.0.0 - 10.0.1
  Depends on vulnerable versions of node-forge
  node_modules/firebase-functions-rate-limiter/node_modules/firebase-admin
    firebase-functions-rate-limiter  *
    Depends on vulnerable versions of firebase-admin
    node_modules/firebase-functions-rate-limiter

3 high severity vulnerabilities

Some issues need review, and may require choosing
a different dependency.

Best way for us to keep working with this is if you would kindly update to firebase-admin 10 etc. and send out a new release. Thanks!

Latest Firebase SDK preventing install

I am not able to resolve dependencies after the latest Firebase SDK released last week. Anybody else? I'm not super experienced with this so maybe my user error. The firebase-functions dependency is ^4.1.0 and Firebase is now 5.0.1

Is not working with firebase-admin 9.x.x

I updated my firebase-admin dependency to 9.1.1 and then I wasn't able to build my functions project because of the following errors:

node_modules/@google-cloud/firestore/types/firestore.d.ts:25:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: DocumentData, UpdateData, Firestore, GeoPoint, Transaction, WriteBatch, WriteResult, DocumentReference, DocumentSnapshot, QueryDocumentSnapshot, OrderByDirection, WhereFilterOp, Query, QuerySnapshot, DocumentChangeType, CollectionReference, FieldValue, FieldPath, Timestamp, v1beta1, v1, OK, CANCELLED, UNKNOWN, INVALID_ARGUMENT, DEADLINE_EXCEEDED, NOT_FOUND, ALREADY_EXISTS, PERMISSION_DENIED, RESOURCE_EXHAUSTED, FAILED_PRECONDITION, ABORTED, OUT_OF_RANGE, UNIMPLEMENTED, INTERNAL, UNAVAILABLE, DATA_LOSS, UNAUTHENTICATED, FirebaseFirestore

25 declare namespace FirebaseFirestore {
   ~~~~~~~

  node_modules/firebase-functions-rate-limiter/node_modules/@google-cloud/firestore/types/firestore.d.ts:23:1
    23 declare namespace FirebaseFirestore {
       ~~~~~~~
    Conflicts are in this file.

node_modules/firebase-functions-rate-limiter/node_modules/@google-cloud/firestore/types/firestore.d.ts:23:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: DocumentData, UpdateData, Firestore, GeoPoint, Transaction, WriteBatch, WriteResult, DocumentReference, DocumentSnapshot, QueryDocumentSnapshot, OrderByDirection, WhereFilterOp, Query, QuerySnapshot, 
DocumentChangeType, CollectionReference, FieldValue, FieldPath, Timestamp, v1beta1, v1, OK, CANCELLED, UNKNOWN, INVALID_ARGUMENT, DEADLINE_EXCEEDED, NOT_FOUND, ALREADY_EXISTS, PERMISSION_DENIED, RESOURCE_EXHAUSTED, FAILED_PRECONDITION, ABORTED, OUT_OF_RANGE, UNIMPLEMENTED, INTERNAL, UNAVAILABLE, DATA_LOSS, UNAUTHENTICATED, FirebaseFirestore

23 declare namespace FirebaseFirestore {
   ~~~~~~~

  node_modules/@google-cloud/firestore/types/firestore.d.ts:25:1
    25 declare namespace FirebaseFirestore {
       ~~~~~~~
    Conflicts are in this file.

node_modules/firebase-functions-rate-limiter/node_modules/@google-cloud/firestore/types/firestore.d.ts:155:5 - error TS2374: Duplicate string index signature.

155     [key: string]: any; // Accept other properties, such as GRPC settings.

The Firebase Admin Node SDK have:

  • Upgraded dependency on the @google-cloud/firestore package to v4.
  • Upgraded dependency on the @google-cloud/storage package to v5.

You referencing the firebase-admin v8 package in the dependencies which is causing these errors. I think that the firebase-admin package should be a peerDependency and not a dependency because 99.9% of the projects who are going to use this package will already use the firebase-admin package.

FR: Multiple rate limits

Thanks so much for this useful tool!

I would like to use say 2 accesses per 15 seconds limit as you have in the example code, plus a 250 accesses per 24 hours limit as well. That would hinder faster DOS-style abuse and slower scraper-style abuse as well, while still enabling normal human use.

What would be the best way to do this? I could create two limiters and use the same user key, but if I do that, should it be a limit of 2x250 (ie 500) because the accesses will be recorded twice on that key? I probably don't want to double up on keys and double my storage cost instead. Maybe you know a better way.

This example shows what a more advanced usage scenario would be, although the code isn't as refined as your library.

Also btw is there any way of limiting how many user accounts an IP address can create in a hour? There's a disabled flag on the account, and theres the onCreate trigger from firebase auth...but I don't see that it offers access to the ip address for me to use a limiter keyed on that...and I'd rather not use the REST API for auth.

Thanks for your assistance on this! Great work on this, code is exemplary.

Limiting by origin?

Is there any progress towards being able to limit by origin as opposed to everyone (Example 1) or user (Example 2)?

Does the limiter affect firebase reads/writes?

The problem with firebase as you might know is that there's really no way to stop users from abusing your db by spamming functions calls. Even if you do stop them, the fact that they still call them might result in a huge bill anyway, which is what really scares me and can put any business out.

So basically, my question is: do I have to be careful about billing anyway, even if I use this limiter?

Also... if I choose Firestore to save that data limit, then there will be a limit of 1 Mb per document, will it be handled by this library or by ourself ?

Thanks

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://registry.npmjs.org/.


Good luck with your project ✨

Your semantic-release bot 📦🚀

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.