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 🙏

© 2026 – Pkg Stats / Ryan Hefner

mushroomjs

v1.2.0

Published

Mushroom js driver

Readme

Install

npm install mushroomjs

or

yarn add mushroomjs

Import

Simple

import mushroom from "mushroomjs";

Builder

import { Filter, Sort, Project } from 'mushroomjs';

Full

import mushroom, {
    defineAsyncResource,
    defineAsyncView,
    fireEvent,
    createRestfulAsyncFunction,

    IdType,

    IMushroom,
    Mushroom,

    MushroomRequest,
    MushroomRequestSetting,
    MushroomRestfulRequest,
    MushroomResponse,

    MushroomResourceBase,
    MushroomListResource,
    MushroomFindByIdResource,
    MushroomCreateResource,
    MushroomBatchCreateResource,
    MushroomUpdateResource,
    MushroomBatchUpdateResource,
    MushroomPartialUpdateResource,
    MushroomDeleteResource,
    MushroomBatchDeleteResource,
    MushroomExtensibleResource,

    MushroomError
} from 'mushroomjs';

Define resource

Defination

Create a typescript defination script. Ex: api.ts

import mushroom, {
    defineAsyncResource,

    IMushroom,

    MushroomRequest,
    MushroomRequestSetting,

    MushroomResourceBase,
    MushroomListResource,
    MushroomCountResource,
    MushroomFindByIdResource,
    MushroomCreateResource,
    MushroomBatchCreateResource,
    MushroomUpdateResource,
    MushroomBatchUpdateResource,
    MushroomPartialUpdateResource,
    MushroomDeleteResource,
    MushroomBatchDeleteResource,

    MushroomListResponse,
    MushroomCountResponse
} from "mushroomjs";

interface Foo {
    id?: string,
    x?: number,
    y?: boolean
}

interface FooCustomFunctionRequest extends MushroomRequest {
    params: {
        f1: boolean,
        f2?: string
    },
    body: {
        a: string,
        b?: number
    }
}

interface FooCustomFunctionResult {
    u: string,
    v: number
}

interface FooCustomFunction {
    customFunctionAsync(request: FooCustomFunctionRequest): Promise<MushroomResponse<FooCustomFunctionResult>>
}

interface FooViewSampleParameters {
    param1: string,
    param2?: number;
}

interface FooViewSampleItemResult {
    v1: IdType,
    v2: boolean,
    v3?: number
}

interface FooViewSample {
    views: {
        sampleAsync(viewParams: FooViewSampleParameters, settings?: MushroomRequestSetting): Promise<MushroomResponse<FooViewSampleItemResult[]>>
    }
}

defineAsyncResource<Foo>({
    name: "foo",
    actions: {
        findMany: { 
            clientCache: false, // false means disabled cache
            paging: "limitOffset",
            includeTotal: true
        }, 
        findById: { 
            clientCache: true // false means disabled cache
        },
        createOne: {},
        createMany: {},
        updateOne: {},
        updateMany: {},
        updatePartially: {},
        deleteOne: {},
        deleteMany: {},
        _raw_http_method_customFunction: {}
    },
    views: {
        sample: { clientCache: true }
    }
});

mushroom.$using("your absolute root API URL");

interface MushroomApi extends IMushroom {
    foo: MushroomResourceBase & MushroomListResource<Foo> & MushroomCountResource, & MushroomFindByIdResource<Foo> & MushroomCreateResource<Foo> & MushroomBatchCreateResource<Foo> & MushroomUpdateResource<Foo> & MushroomBatchUpdateResource<Foo> & MushroomPartialUpdateResource<Foo> & MushroomDeleteResource & MushroomBatchDeleteResource & FooCustomFunction & FooViewSample
}

export default mushroom as MushroomApi;

Usage

import mushroom from "./api"

async function example() {
    await mushroom.foo.listAsync();
    await mushroom.foo.getAllAsync();
    await mushroom.foo.countAsync();
    await mushroom.foo.findByIdAsync({id: yourId});
    let newId = await mushroom.foo.createAsync(fooInstance);
    let newIds = await mushroom.foo.batchCreateAsync(fooInstances);
    await mushroom.foo.updateAsync(fooInstance);
    await mushroom.foo.batchUpdateAsync(fooInstances);
    await mushroom.foo.partialUpdateAsync(fooInstance);
    await mushroom.foo.deleteAsync(id);
    await mushroom.foo.batchDeleteAsync(ids);
    await muuhroom.foo.customFunction({ params: {f1: true}, body: {a: 10} });
    let result = await mushroom.foo.views.sample({param1: "abc", param2: 1});
}

Customize headers or/and params of common action

mushroom.foo.createAsync(fooInstance, {
    extra: {
        headers: {
            // your custom headers
        },
        params: {
            // your custom params
        }
    }
});

[Advanced] Call as prefer role

To specify the role of user, use field preferRole of second parameter. Eg:

The current user has 2 roles Admin and User, api foo.list supports both roles and Admin is in higher priority, to switch to User role, please follow this example:

mushroom.foo.listAsync(arg, {
    preferRole: 'User'
});

[Advanced] Raw request body for customized API

In some special APIs, request data is required in other than JSON format. In this case, use isRawData to tell mushroomjs. Eg:

// Request body in BINARY format
mushroom.foo.specialApiAsync({
    body: file, // File
    settings: {
        isRawData: true,
        extra: {
            headers: {
                'Content-Type': 'image/jpeg' // change to the MIME type of your file or use octet/stream for general case
            }
        }
        
    }
});


// Request body in FORMDATA format
mushroom.foo.specialApiAsync({
    body: formdata, // FormData
    settings: {
        isRawData: true
    }
});

[Advanced] Text response and Blob response

In some special APIs, response data is not in JSON format. In this case, please do not use response.result, use response.resultAsText(): string or response.resultAsBlob(): Blob instead. Ex:

const response = await mushroom.foo.specialApiAsync(/*parameters here if any*/);
const text = response.resultAsText();

Define global view

Global view defination

Create a typescript defination script. Ex: api.ts

import mushroom, {
    defineAsyncView,
    IMushroom,
    MushroomRequestSetting
} from "mushroomjs";

interface SampleViewParameters {
    param1: string,
    param2?: number;
}

interface SampleViewItemResult {
    v1: IdType,
    v2: boolean,
    v3?: number
}

interface SampleView {
    sampleAsync(viewParams: SampleViewParameters, settings?: MushroomRequestSetting): Promise<MushroomResponse<SampleViewItemResult[]>>
}

defineAsyncView("sample", { clientCache: true });

mushroom.$using("your absolute root API URL");

interface MushroomApi extends IMushroom {
    $view: SampleView
}

export default mushroom as MushroomApi;

Global view usage

import mushroom from "./api"

async function example() {
    let result = await mushroom.$views.sample({
        param1: "abc", 
        param2: 1
    });
}

Event

Register event handler

import mushroom, { MushroomRestfulRequest, MushroomRequest, MushroomError } from "mushroomjs";

mushroom._on("eventName", fnEventHandler);

Remove event handler

mushroom._unbindEvent("eventName"); // remove all event handlers of 'eventName' event
mushroom._unbindEvent("eventName", fnEventHandler); // remove specific event handler of 'eventName' event

Reflection

mushroom._hasEvent("eventName"); // return true if eventName has handler(s)

Built-in events

On request begining

mushroom._on("beginRequest", (args: BeginMushroomRequestHandlerArguments) => {});

Affter request ended

mushroom._on("endRequest", (args: EndMushroomRequestHandlerArguments) => {});

Before sending request

mushroom._on("beforeSend", (request: MushroomRestfulRequest, rawRequest: MushroomRequest) => {});

Switch to online state

mushroom._on("online", () => {});

Fall to offline state

mushroom._on("offline", () => {});

API URL

mushroom.$using(rootApiUrl); // set root API URL
let url = mushroom.$using(); // get current root API URL

[Advanced] Settings for each request

preferRole

See Call as prefer role

override cache settings

To override global cache age, see Request level at Cache age

override global request timeout

To override global request timeout

mushroom.foo.listAsync(arg, {
    timeout: 3000, // timeout after 3000 miliseconds or 3 seconds
});

inject events for each request

mushroom.foo.listAsync(arg, {
    beforeSend: (request, rawRequest) => {}
});

abort request

To abort a request, use AbortController in setting. Ex:

const abortController = new AbortController();
setTimeout(() => abortController.abort(), 500);
try {
    const res = await mushroom.foo.listAsync({}, {
        abortController: abortController
    });
    console.log(res);
}
catch (e) {
    console.error(e);
}

Custom methods:

const abortController = new AbortController();
setTimeout(() => abortController.abort(), 500);
try {
    const res = await mushroom.foo.barAsync({
        settings: {
            abortController: abortController
        }
    });
    console.log(res);
}
catch (e) {
    console.error(e);
}

Caching

By default, mushroom js driver supports client cache for 2 methods listAsync and findByIdAsync if actions.findMany.clientCache == true, actions.findById.clientCache == true

Please see Defination at Define resource.

Mushroom js driver only supports client cache for request which is GET method.

Invalid cache

Clear resource cache

mushroom.foo.invalidCache();

Clear cache by url

mushroom.$cache.invalid(url) // url: string - a RESTful url will be invalid cache

Clear cache by pattern

mushroom.$cache.invalid(pattern) // pattern: RegEx - a regular expression of RESTful urls will be invalid cache

Clear all cache

mushroom.$cache.invalid()

Cache age

Global level

mushroom.$setting.set("request.cache.age", ms); // set global cache age value (in milisecond)

Request level

let result1 = await mushroom.foo.listAsync({ }, {
    cacheAge: 5000 // cache in 5 seconds
});

let result2 = await mushroom.foo.findByIdAsync({
    id: "your id"
}, {
    cacheAge: 10000 // cache in 10 seconds
});

let result = await mushroom.foo.customMethodAsync({ }, {
    cacheAge: 15000 // cache in 15 seconds
});

Settings

Setting global cache age

mushroom.$setting.set("request.cache.age", 300000); // default: 5 minutes

Setting global request timeout

mushroom.$setting.set("request.timeout", timeout_in_ms); // default: undefined (mean: depending on each browser/system)

Setting common HTTP methods

mushroom.$setting.set("request.common_methods", ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]);

Setting flags

Log generic information

mushroom.$setting.set("diagnostic.log_info", true); // default: false

Warning on slow connection

mushroom.$setting.set("diagnostic.warning_slow_connection", true); // default: false

Slow connection info will be outputed at console.

mushroom.$setting.set("diagnostic.slow_connection_milliseconds", 2000); // default: 2 seconds

Slow connection if an API was requested that took more than diagnostic.slow_connection_milliseconds

Log request

mushroom.$setting.set("diagnostic.log_request", true); // default: false

Log response

mushroom.$setting.set("diagnostic.log_response", true); // default: false

Log cache hit

mushroom.$setting.set("diagnostic.log_cache_hit", true); // default: false

For NodeJS

Required addition dependency: node-fetch

Custom extension

Custom extension defination

mushroom.$ext = mushroom.$ext || {};
mushroom.$ext.method1Async = ... // see Defination of Custom method above

Custom extension usage

await mushroom.$ext.method1Async(1, 2, 3);

Builders

Filter builder

Usage

import { Filter } from 'mushroomjs';

let filter : IBuilder;

// create filter here

mushroom.foo.listAsync({
    filters: filter.build()
})

eq

filter = Filter.eq("x", 10); // x=10

ne

filter = Filter.ne("x", 10); // x!=10

lt

filter = Filter.lt("x", 10); // x<10

lte

filter = Filter.lte("x", 10); // x<=10

gt

filter = Filter.gt("x", 10); // x>10

gte

filter = Filter.gte("x", 10); // x>=10

min

Alias of gte

filter = Filter.min("x", 10); // x>=10

max

Alias of lte

filter = Filter.max("x", 10); // x<=10

in

filter = Filter.in("x", [1, 2, 3]); // x:in:1,2,3

nin

filter = Filter.nin("x", [1, 2, 3]); // x:nin:1,2,3

all

filter = Filter.all("x", [1, 2, 3]); // x:all:1,2,3

like

filter = Filter.like("x", "%abc%"); // x:like:%abc%   (% will be url-encoded to %25)

regex

Without options

filter = Filter.regex("x", /ab[cd]/); // x:regex:ab[cd]
filter = Filter.regex("x", "ab[cd]"); // x:regex:ab[cd]

With options

filter = Filter.regex("x", /ab[cd]/i); // x:regex_i:ab[cd]
filter = Filter.regex("x", "ab[cd]", "i"); // x:regex_i:ab[cd]

filter = Filter.regex("x", /ab[cd]/m); // x:regex_m:ab[cd]
filter = Filter.regex("x", "ab[cd]", "m"); // x:regex_m:ab[cd]

filter = Filter.regex("x", /ab[cd]/im); // x:regex_im:ab[cd]
filter = Filter.regex("x", "ab[cd]", "im"); // x:regex_im:ab[cd]

elementMatch

filter = Filter.elementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:elemMatch:y=10,z>3

nelementMatch

filter = Filter.nelementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:nelemMatch:y=10,z>3

size

filter = Filter.size("x", 4); // x:size:4

isNull

filter = Filter.isNull("x"); // x:is_null:true
filter = Filter.isNull("x", false); // x:is_null:false

and

filter = Filter.and([Filter.eq("y", 10),  Filter.gt("z", 3)]); // y=10&z>3
filter = Filter.and(Filter.eq("y", 10),  Filter.gt("z", 3)); // y=10&z>3

or

filter = Filter.or([Filter.eq("y", 10),  Filter.gt("z", 3)]); // y=10|z>3
filter = Filter.or(Filter.eq("y", 10),  Filter.gt("z", 3)); // y=10|z>3

empty

filter = Filter.empty(); // empty string

filter chain

filter = Filter.eq("a", 1).lt("b", 2); // a=1&b<2
filter = Filter.eq("a", 1).lt("b", 2).or(Filter.eq("c", 3).gte("d", 4)); // :and:a=1,b=2|:and:c=3,d=4
filter = Filter.eq("a", 1).lt("b", 2).and(Filter.or(Filter.eq("c", 3), Filter.gte("d", 4))); // a=1&b=2&c=3|d=4
filter = Filter.empty().eq("a", 1); // a=1

toArray

filters = Filter.eq("a", 1).lt("b", 2).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).or("b", 2).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.elementMatch("x", [Filter.eq("a", 1), Filter.lt("b", 2)]).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]

asArray

filters = Filter.eq("a", 1).lt("b", 2).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).or("b", 2).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.elementMatch("x", [Filter.eq("a", 1), Filter.lt("b", 2)]).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).asArray() // Error

variables

filters = Filter.eq("d", Filter.variables.now()) // d=$$now
filters = Filter.eq("d", Filter.variables.today()) // d=$$today
filters = Filter.eq("d", Filter.variables.userId()) // d=$$user_id
filters = Filter.eq("ip", Filter.variables.userIp()) // ip=$$user_ip
filters = Filter.eq("d", Filter.variables.nowAdd(5, 'hour')) // d=$$now+5hours
filters = Filter.eq("d", Filter.variables.todayAdd(2, 'week')) // d=$$today+2weeks
filters = Filter.in("company_id", Filter.variables.fromName<string>('company_id')) // company_id=$$company_id
filters = Filter.in("number", Filter.variables.fromName<number[]>('my_numbers')) // number:in:$$my_numbers

Sort builder

Usage

import { Sort } from 'mushroomjs';

let sort : IBuilder;

// create sort here

mushroom.foo.listAsync({
    sort: sort.build()
})

ascending

sort = Sort.ascending("x"); // x

descending

sort = Sort.descending("x"); // -x

thenByAscending

sort = Sort.ascending("x").thenByAscending("y"); // x,y

thenByDescending

sort = Sort.ascending("x").thenByDescending("y"); // x,-y

Project builder

Usage

import { Project } from 'mushroomjs';

let project : IBuilder;

// create project here

mushroom.foo.listAsync({
    fields: project.build()
})

include

project = Project.include("x"); // x

project = Project.include("x", "y"); // x,y
project = Project.include("x").include("y"); // x,y

Release notes

1.2.0

New features:

  • Add new setting to specify the common HTTP methods (not need to use header X-HTTP-Method-Override): request.common_methods
  • Add new rest object field in MushroomRestfulRequest to customize fetch
  • Allow to customize request headers and params of common actions (such as findById, list, create...)
  • Support raw request data
  • Support variables in filter builder

1.1.1

Fix bug:

  • Get wrong result when using nested and filter in FilterBuilder

1.1.0

New features:

  • Support Typescript
  • Support NodeJS
  • Support Abort request
  • Support softDelete
  • Support preferRole for request
  • Support channel for vn_text
  • Add builders (Filter, Sort, Project)
  • Add new settings for log actions, such as diagnostic.log_info, diagnostic.log_cache_hit
  • Add new methods countAsync, getAllAsync for resource
  • Add new methods resultAsBlob, resultAsText for reponse.

Fix bugs:

  • iOS: missing escape url for filter
  • Missing headers which were passed in each api call time
  • Wrong in some cases when call api deleteAsync and batchDeleteAsync