npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@firestore-rules/cli

v0.1.16

Published

> TODO: description

Downloads

19

Readme

@firestore-rules/cli

CLI library for automatic generation of Firestore rules.

Install

yarn add -D @firestore-rules/cli
# or npm add @firestore-rules/cli --save-dev

Usage

Create Firestore Rules Model

create ./src/firestore-rules.ts

// ./src/firestore-rules.ts

import { FirestoreRulesModel, type, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  get path() {
    return '/databases/{database}/documents'
  }
  get isAuthenticated() {
    return this.defineFunc(op.ne(this.ctx.request.auth, new type.Null()))
  }
  get isMe() {
    const uid = this.args('uid')
    return this.defineFunc(
      op.and(
        this.isAuthenticated.call([]),
        op.eq(uid, this.ctx.request.auth.uid)
      )
    )
  }

  get userCollection() {
    const self = this
    return this.defineModel(
      class extends FirestoreRulesModel {
        get path() {
          return '/users/{uid}'
        }
        get() {
          return self.isMe.call([this.variables.uid])
        }
        create() {
          return self.isAuthenticated.call([])
        }
        update() {
          return self.isMe.call([this.variables.uid])
        }
      }
    )
  }
}

Then run the following command

yarn firestore-rules
# or ./node_modules/.bin/firestore-rules

Then you will get the following firestore.rules

// !!! DO NOT EDIT !!!
// This file is generated by @firestore-rules/cli
rules_version = "2";
service cloud.firestore {
  match /databases/{database}/documents {
    function isAuthenticated() {
      return (request.auth != null);
    }
    function isMe(uid) {
      return (isAuthenticated() && (uid == request.auth.uid));
    }
    match /users/{uid} {
      allow get: if isMe(uid);
      allow create: if isAuthenticated();
      allow update: if isMe(uid);
    }
  }
}

Options

There are several ways to specify the options

  • "firestore-rules" in package.json
  • .firestore-rulesrc (both json or yaml format is ok)
  • .firestore-rulesrc.{json,yaml,yml,js,cjs}
  • firestore-rules.config.{js,cjs}

See cosmiconfig for other specification methods.

Option Properties

rulesPath: string # path to firestore-rules file. (default is './src/firestore-rules.ts')
typescript: boolean # if you do not use typescript, turn off. (default is true)
tsconfigPath: string # path to your tsconfig file. (default is './tsconfig.json')
outputPath: string # path to generate file. (default is 'firestore.rules')
backupFile: boolean # if you don't want to create backup file, turn off. (default is true)
formatOption: # options for formatter
  indent: tab or space # indent type. (default is space)
  indentSize: number # indent size. (default is 2)
  lineLength: number # Maximum length of a line. (* Currently under development)

rulesPath

Specify the path of the entry file to be read by cli.

Default is ./src/firestore-rules.ts.

typescript

Set to true if you want to use Typescript.

Default is true.

tsconfigPath

If you use TypeScript, you should provide valid tscondif file.

Default is ./tsconfig.json

outputPath

Specify the path of the file to output.

Default is firestore.rules.

backupFile

Set to true if you want the original rule to be backed up when generating the file.

Default is true.

The name of the file to be backed up will be outputPath + '.backup'.

formatOption

Options to be passed to @firestore-rules/formatter.

Check @firestore-rules/formatter for details

Writing Style

1. Export default class that extends FirestoreRulesModel

import { FirestoreRulesModel } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  // ...
}

Define a getter named path

The returned value will be the value to apply to the match statement in firestore.rules.

// ...
export default class extends FirestoreRulesModel {
  get path() {
    return '/databases/{database}/documents'
  }
}

Define a function with no arguments

You can use a method called defineFunc.

You can use this.ctx to refer to a global value such as request.

The literal and op that can be imported from @firestore-rules/cli contain all types and operators except for the Bytes type

import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  /*
   * function isAuthenticated() {
   *   return (request.auth != null);
   * }
   */
  get isAuthenticated() {
    return this.defineFunc(
      op.ne(this.ctx.request.auth, new literal.FirestoreRulesLiteralNull())
    )
  }
}

Define a function with arguments

You can use a method called defineFunc, too.

Arguments can be defined by using the arg method.

Also, if you want to use a predefined function, you can use this.<funcName>.call(). The first argument of the call should be the argument to be passed to the function. isAuthenticated does not require any argument, so it will pass an empty array

import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  /*
   * function isMe(uid) {
   *   return (isAuthenticated() && (uid == request.auth.uid));
   * }
   */
  get isMe() {
    const uid = this.args('uid') // create argument
    return this.defineFunc(
      op.and(
        this.isAuthenticated.call([]), // call defined function
        op.eq(uid, this.ctx.request.auth.uid)
      )
    )
  }
}

Nesting match statements

You can use the defineModel method to nest match expressions.

The argument should be clsass as well as the class you are default export.

It is also a good idea to replace the this reference with a variable such as self so that it can be used again.

import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  get userCollection() {
    const self = this
    return this.defineModel(
      class extends FirestoreRulesModel {
        // ...
      }
    )
  }
}

Similarly, define the path

Define the path in the same way as you did for /databases/{database}/documents.

import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  get userCollection() {
    const self = this
    return this.defineModel(
      class extends FirestoreRulesModel {
        get path() {
          return '/users/{uid}'
        }
      }
    )
  }
}

Declare the permit conditions

Permission conditions can be specified by overriding the get, list, create, update, and delete methods.

Also, the document ID (uid in this example) will be automatically associated with this.variables.uid.

Since we just used self, we can also call functions in the parent hierarchy from self.

The isMe function needs an argument, so let's give it one.

import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'

export default class extends FirestoreRulesModel {
  /*
   * match /users/{uid} {
   *   allow get: if isMe(uid);
   *   allow create: if isAuthenticated();
   *   allow update: if isMe(uid);
   * }
   */
  get userCollection() {
    const self = this
    return this.defineModel(
      class extends FirestoreRulesModel {
        get path() {
          return '/users/{uid}'
        }
        get() {
          return self.isMe.call([this.variables.uid])
        }
        create() {
          return self.isAuthenticated.call([])
        }
        update() {
          return self.isMe.call([this.variables.uid])
        }
      }
    )
  }
}

Others

If you have any questions, please open an Issue!