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

firebase-function-client-type-gen

v2.0.0

Published

generator firebase functions httpsOnCall function types

Downloads

91

Readme

About firebase-function-client-type-gen

Generator of client types of firebase functions derived from orginal firebase deploy definition object.

Get Started

npm i --save-dev firebase-function-client-type-gen proxyquire @types/proxyquire typescript
export const DUMMY_MOCKS = new Proxy<any>(
    () => DUMMY_MOCKS,
    {
        get(_, __): any {
            return DUMMY_MOCKS
        }
    }
)

export const MOCKS_BASE = {
    'firebase-functions': {
        region() {
            return DUMMY_MOCKS
        },
        config: () => {
            return {
            }
        },
        '@global': true,
        '@noCallThru': true
    },
    'firebase-admin': {
        apps: DUMMY_MOCKS,
        initializeApp: () => { return DUMMY_MOCKS },

        '@global': true,
        '@noCallThru': true
    },
}

export const MOCKS = new Proxy(MOCKS_BASE, {
    get(target, name) {
        const returnValue = target[name as keyof typeof MOCKS_BASE]
        return returnValue ?? DUMMY_MOCKS
    }
})
import * as functions from 'firebase-functions'

// You define two types in function definition file and they must be in a file include function declaration.
type RequestArgs = {
    id: string
}
type ResponseResult = {
    result: 'ok' | 'ng'
}

// You must export "only one const https onCall" in a file.
// If you export many httpsOnCall functions, it may happen unexpected result when mapping args and result types.'
export const includeTest = functions
    .region('asia-northeast1')
    .runWith({
        memory: '1GB'
    })
    .https.onCall((data: RequestArgs,_): ResponseResult => {
        return {
            result: 'ok'
        }
    })
import proxyquire from 'proxyquire'
import { MOCKS } from './mock'
import { outDefinitions } from 'firebase-function-client-type-gen'
import path from 'path'
import glob from 'glob'

const firebaseFunctionEntrypoint = proxyquire('../functions/index', MOCKS)

// Get document, or throw exception on error
try {
  const sources = glob.sync(path.resolve(__dirname, '../', 'functions/endpoints/**/*.ts'))
  // The symbolConfig determine what type should be read from your https onCall definition file as its args or result.
  // If you do not specify it, default is 'RequestArgs' and 'ResponseResult'
  const result = outDefinitions(sources, firebaseFunctionEntrypoint, {
    symbolConfig: {
      args: 'RequestArgs',
      result: 'ResponseResult'
    }
  })
  console.log(result)
  console.log('done');
} catch (e) {
  console.error(e);
}

Output like

export type FunctionDefinitions = {
    "includeTest": {
        args: { id: string; };
        result: { result: "ok" | "ng"; };
    };
    "includeTestShallow": {
        args: { id: number; };
        result: { result: "success" | "failed"; };
    };
    "includeTestComposite": {
        args: Record<any, any>;
        result: { result: "success" | "failed"; };
    };
};

export const functionsMap = {
    includeTest: {
        id: "nested-namespace-includeTest",
        region: "asia-northeast1"
    },
    includeTestShallow: {
        id: "nested-includeTestShallow",
        region: "asia-northeast1"
    },
    includeTestComposite: {
        id: "includeTestComposite",
        region: "asia-northeast1"
    }
};

See tests/index.ts code more detailed usage.

Then, you can get fully type safed functions client in frontend code, like this.

import { getFunctions, httpsCallable, HttpsCallable } from 'firebase/functions'
import { getApp } from 'firebase/app'

type IFunctionDefnitions = {
    [key: string]: {
        args: any,
        result: any
    }
}

type HttpsCallableFuntions<FunctionDefnitions extends IFunctionDefnitions> = {
    [functionName in keyof FunctionDefnitions]: HttpsCallable<FunctionDefnitions[functionName]['args'], FunctionDefnitions[functionName]['result']>
}

type HttpsCallableFuntionIds<FunctionDefnitions> = {
    [functionName in keyof FunctionDefnitions]: {
        id: string
        region?: string
    }
}

export function initializeFunctions<FunctionDefnitions extends IFunctionDefnitions>(functionNameObject: HttpsCallableFuntionIds<FunctionDefnitions>, app = getApp(), region = 'asia-northeast1'): HttpsCallableFuntions<FunctionDefnitions> {
  const functionDefinitions = Object.entries(functionNameObject)
  return functionDefinitions.reduce((current, [functionName, functionObj]) => {
    const functions = getFunctions(app, functionObj.region || region)
    return {
      ...current,
      [functionName]: httpsCallable(functions, functionObj.id),
    }
  }, {} as HttpsCallableFuntions<FunctionDefnitions>)
}

The template above can be generated by bin command,

npx gen-ffc ${outputpath:absolute or relative path}

and then, with your output type path, semi-automatically get type safe cliet.

// At your entrypoint file, import generated types from your generated types file.
import { FunctionDefinitions, functionsMap } from './functions-types'
import { initializeFunctions } from './outputpath'
const client = initializeFunctions<FunctionDefinitions>(functionsMap)
// Fully type-safed api call functions.
client.callSomethingReuest({...args})

Warning

  • This library for typescript firebase function users.
  • You mustn't define more than two firebase https functions in a file, they may cause bug.
  • Your args and result type must be included in the function definition file.
  • If you need to change region as basis as function, manually call const someCallable = httpsCallable(getFunction(getApp(), region), functionId) instead of initializeFunctions above.

LICENSE

MIT