@fabricelements/shared-helpers is a TypeScript helper library for Firebase and
Google Cloud backend projects. It packages reusable, well-tested utilities —
Firestore access helpers, media/image processing, phone-number validation,
Pub/Sub event handling, BigQuery backups, and string/regex utilities — so that
FabricElements Cloud Functions services can share a single, consistent
foundation.
The package is published as a pure ESM module and is consumed both from NPM and directly from GitHub.
This repository is a publishable NPM library that targets the serverless
Google Cloud / Firebase ecosystem. The authored TypeScript in src/ is compiled
to JavaScript + type declarations in lib/ (the main, module, and types
fields, plus the exports map, all point at ./lib), which is the artifact
shipped to consumers.
The helpers are designed to run inside Firebase Cloud Functions (Node.js runtime) and to interact with the surrounding cloud services:
- Cloud Firestore, Cloud Storage, and the Realtime Database for
application data and assets (security rules live in
firestore.rules,storage.rules, anddatabase.rules.json). - Cloud Pub/Sub for event-driven messaging (
pubSubEvent). - BigQuery for analytics backups and cleanup (
backup,cleaner). - Cloud Storage +
sharpfor on-the-fly image resizing/transformation (Media). - Firebase Authentication for user lifecycle helpers (
User).
A companion sample Firebase Cloud Functions app lives under functions/ and
consumes the library locally via a file:.. dependency, demonstrating real
triggers, controllers, and media handlers (including the media-open HTTPS
function wired into Hosting rewrites in firebase.json).
- Target runtime: Node.js
>=22(seeenginesinpackage.json). - Language: TypeScript
^6, emitted as ES2020 ESM. - Default Firebase project alias:
fabricelements(see.firebaserc).
The package entry point (src/index.ts) re-exports the following helpers.
Subpath exports ./user and ./media are also exposed via package.json.
| Helper | Source | Purpose |
|---|---|---|
apiRequest |
src/api-request.ts | Call a Firebase project's base API. |
backup |
src/backup.ts | Custom backup from Firestore to BigQuery. |
checkNumber |
src/check-number.ts | Validate and format phone numbers. |
cleaner |
src/cleaner.ts | BigQuery database cleanup. |
FirestoreHelper |
src/firestore-helper.ts | Google Cloud Firestore access helpers. |
global |
src/global.ts | Basic and reusable helpers. |
hashId |
src/hash-id.ts | Generate a random hash id (4+ characters). |
messageQueueSpeed |
src/message-queue-speed.ts | Compute safe message dispatch throughput (Twilio rate limits). |
pubSubEvent |
src/pubsub-event.ts | Google Cloud Pub/Sub event helper. |
replaceMessageText |
src/replace-message-text.ts | Replace message text with custom keys. |
specialCharToRegular |
src/special-char-to-regular.ts | Convert special characters to regular GSM characters. |
strings |
src/strings.ts | String transformation utilities (e.g. snake_case → camelCase). |
validateUrl |
src/validate-url.ts | Validate URL strings and strip embedded whitespace. |
regex |
src/regex.ts | Shared regular expressions (email, media content types, etc.). |
interfaces |
src/interfaces.ts | Shared TypeScript interfaces and types. |
Media (./media) |
src/media.ts | Image/media processing with sharp and Cloud Storage. |
User (./user) |
src/user.ts | Firebase Auth/Firestore user helpers. |
| Area | Details |
|---|---|
| Language | TypeScript ^6.0.3, compiled to ES2020 ESM ("type": "module", module/moduleResolution: Node16, strict: true, declaration: true). |
| Runtime | Node.js >=22 (see engines in package.json). |
| Firebase | firebase-admin ^13.10.0, firebase-functions ^7.2.5. |
| Google Cloud | @google-cloud/bigquery ^8.3.1, @google-cloud/bigquery-storage ^5.1.1, @google-cloud/pubsub ^5.3.0. |
| Media | sharp ^0.34.5 for image resizing/transformation. |
| Utilities | libphonenumber-js ^1.13.5, lodash ^4.18.1, node-fetch ^3.3.2. |
| Database / storage engines | Cloud Firestore, Cloud Storage, and Realtime Database (rules in firestore.rules, storage.rules, database.rules.json); analytics/queue via BigQuery and Pub/Sub. |
| Linting | ESLint ^10.4.1 via flat config (eslint.config.js) using typescript-eslint recommended + stylistic presets. |
| Testing | Vitest ^4.1.8 (globals enabled, node environment). |
| Configuration patterns | Compiler settings in tsconfig.json (rootDir: src, outDir: lib, declarations + source maps); test compiler config in tsconfig.test.json; Firebase services and emulator ports in firebase.json; default project alias in .firebaserc. |
These are the directories you actually develop in. Source of truth is always
src/ (and functions/src/ for the sample app).
shared-helpers/
├── src/ # Authored TypeScript helpers — the public API (re-exported from src/index.ts)
├── test/ # Vitest unit tests; mirrors src/ (one *.test.ts per helper)
├── functions/
│ └── src/ # Sample/consumer Firebase Cloud Functions app
│ ├── index.ts # Initializes the Admin SDK and re-exports the function modules
│ ├── app.ts # Controllers — aggregate/re-export the media & user function modules
│ ├── user/ # Triggers — Firebase Auth onCreate/onDelete listeners and user actions
│ ├── media/ # Media Cloud Functions, including the `open` HTTPS resize function
│ └── helpers/ # Shared variables/config for the sample functions app
├── lib/ # 🔴 AUTO-GENERATED BUILD OUTPUT — never edit (see notice below)
├── firebase.json # Firebase services config + local Emulator Suite ports
├── .firebaserc # Default Firebase project alias (fabricelements)
├── tsconfig.json # Library compiler config (rootDir: src, outDir: lib, Node16 modules)
├── tsconfig.test.json # Test compiler config used by Vitest
├── vitest.config.ts # Vitest runner configuration
└── eslint.config.js # Flat ESLint config (typescript-eslint: recommended + stylistic)
Caution
The lib/ directory (and any other build-output directory) is an
immutable, auto-generated build target produced by tsc
(npm run compile). It is wiped and regenerated on every build — the clear
script runs rm -rf ./lib first — so any manual change is silently destroyed.
- NEVER edit, create, or delete files in
/lib. - NEVER read
/libor use it as development/AI context — the source of > truth is alwayssrc/. - Make all changes in
src/only, and refresh the compiled output solely > by runningnpm run build.
The compiler excludes lib (tsconfig.json) and ESLint ignores it
(eslint.config.js).
Fresh onboarding for a new developer:
npm installnpm run build is the only sanctioned way to refresh lib/. It clears the
previous output, lints, then compiles (clear → lint → compile):
npm run buildTo keep the TypeScript compiler running and recompiling on every change, use watch mode:
npm run build:watchYou can also run the individual steps directly:
npm run lint # eslint (use `npm run lint:fix` to auto-fix)
npm run compile # tsc -p ./tsconfig.jsonThe build is required because consumers — and the sample
functions/app, which imports the package viafile:..— load the compiled output fromlib/.
The local Emulator Suite is configured in firebase.json (Auth, Functions,
Firestore, Realtime Database, Hosting, Pub/Sub, Storage, plus the Emulator UI):
firebase emulators:start| Emulator | Port |
|---|---|
| Authentication | 9099 |
| Functions | 5001 |
| Firestore | 8080 |
| Realtime Database | 9000 |
| Hosting | 5000 |
| Pub/Sub | 8085 |
| Storage | 9199 |
| Emulator UI | 4000 |
Unit tests are written with Vitest (do not introduce Jest or Mocha/Chai) and
live in test/, mirroring the src/ hierarchy precisely — each module
src/<path>/<name>.ts has a matching test/<path>/<name>.test.ts. Vitest
collects test/**/*.test.ts and test/**/*.spec.ts (see vitest.config.ts) and
runs against the node environment.
Run the full suite once (CI-friendly):
npm testRe-run automatically on file changes during development:
npm run test:watchYou can also invoke Vitest directly:
npx vitest run # single run
npx vitest # watch modeTests must never perform real network requests or touch live external APIs or real cloud instances — all I/O must be intercepted:
- Stub external clients with
vi.mock+vi.hoisted(every variable referenced inside avi.mockfactory must be declared viavi.hoisted). Mock@google-cloud/pubsub,@google-cloud/bigquery,@google-cloud/bigquery-storage,firebase-adminsub-modules,node-fetch, and thefirebase-functions/v2logger. Reset state withvi.clearAllMocks()inbeforeEachandvi.restoreAllMocks()inafterEach. Follow the established pattern intest/pubsub-event.test.ts. - Cloud Functions: drive and track execution with the official
firebase-functions-testSDK. - Data assertions: either run against the local Firebase Emulators (ports in
firebase.json) or heavily stub thefirebase-adminSDK to intercept Firestore / Realtime Database reads and writes — never hit real Firestore/RTDB. - Import the module under test through its
.jsspecifier (e.g.import pubSubEvent from '../src/pubsub-event.js';), per theNode16resolution rule.
Before considering a change complete, run all three — they must pass:
npm run lint
npm run build
npm testThis repository is heavily optimized for AI-assisted workflows with GitHub
Copilot. The authoritative rule manual for both human and AI contributors is
.github/copilot-instructions.md — review it
before contributing.
Before submitting a Pull Request, ensure your AI chat assistant is grounded in that instruction file so generated code stays consistent with our standards. In particular:
- Strict typing. Code compiles under
strict: true. Use precise type declarations; never use banned JSDoc type wrappers likeFunctionorObject— prefer exact shapes (e.g.Record<string, unknown>, an explicit interface, or a concrete function signature). - Google-style TypeScript JSDoc. All exported functions, methods, interfaces,
and namespaces carry multi-line
/** ... */blocks (no///or single-line//docs) with a capitalized summary sentence, explicit@param {type} name - descriptionmapping,@returns/@returndocumentation, and@throws {Error} ...where applicable. Mark optional params with brackets (@param {number} [length]). - No redundant or banned native type strings, and respect the linter's tag
preference (
returns→return). - Preserve URLs & links inside comments — never rewrite, line-wrap, or remove
markdown links or external URLs (
max-lenis configured withignoreCommentsandignoreUrls). - Architecture rules. Use
async/await(not raw.then()/.catch()chains); keep Firebase triggers thin and delegate to independently testable domain logic; validate and shape data before any database write. - Never read or edit
/libas context (see the blacklist notice above), and do not modifysrc/solely to make code easier to test.
From NPM:
npm i @fabricelements/shared-helpers --saveOr from GitHub:
npm i github:FabricElements/shared-helpers --saveImport only what you need:
import {FirestoreHelper, pubSubEvent} from "@fabricelements/shared-helpers";Or import everything:
import * as sharedHelpers from "@fabricelements/shared-helpers";Subpath modules are also available:
import {User} from "@fabricelements/shared-helpers/user";
import {Media} from "@fabricelements/shared-helpers/media";Please check CONTRIBUTING.
Released under the BSD 3-Clause License.