JSPM

@aiwa/firekit

1.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 11
  • Score
    100M100P100Q43189F
  • License MIT

AIWA's managed Firebase SDK for multi-tenant applications

Package Exports

  • @aiwa/firekit

Readme

Firekit 🔥

AIWA's managed Firebase SDK for multi-tenant applications. Zero configuration, complete isolation.

Features

  • Zero Config - Automatic Firebase initialization from AIWA backend
  • 🔒 Multi-Tenant Isolation - Each app is completely isolated via collection paths
  • 🔐 Built-in Auth - Email/password authentication with custom claims
  • Real-time Updates - Live data subscriptions
  • 🎯 Type-Safe - Full TypeScript support
  • 🚀 Edge-Ready - Works with Vercel Edge Functions
  • 🔐 Secure - Firebase credentials managed server-side, never exposed to users

How It Works

  1. Your app calls createDatabase({ projectId })
  2. Firekit validates projectId with AIWA backend
  3. Backend returns userId, appId, and Firebase credentials
  4. Firekit initializes with returned credentials
  5. All data isolated to /users/{userId}/apps/{appId}/data/

Security: Firebase credentials stay on AIWA's servers. User apps never see them.

Installation

npm install @aiwa/firekit
# or
pnpm add @aiwa/firekit
# or
yarn add @aiwa/firekit

Environment Variables

Add to your .env.local:

NEXT_PUBLIC_PROJECT_ID=your-project-id

That's it. Firebase credentials are automatically retrieved from AIWA's secure backend.

Quick Start

import { createDatabase, createAuth } from '@aiwa/firekit'

// Initialize database (multi-tenant isolated)
const db = await createDatabase({
  projectId: process.env.NEXT_PUBLIC_PROJECT_ID!,
})

// Initialize auth
const auth = await createAuth({
  projectId: process.env.NEXT_PUBLIC_PROJECT_ID!,
})

Database Operations

Create

const post = await db.create('posts', {
  title: 'Hello World',
  content: 'My first post',
  published: true,
})

Read

// Get single document
const post = await db.read('posts', 'post-id')

// Get all documents
const posts = await db.getAll('posts')

// Query with filters
const publishedPosts = await db.query('posts', {
  where: [{ field: 'published', operator: '==', value: true }],
  orderBy: { field: 'createdAt', direction: 'desc' },
  limit: 10,
})

Update

await db.update('posts', 'post-id', {
  title: 'Updated Title',
})

Delete

await db.delete('posts', 'post-id')

Real-time Subscriptions

const unsubscribe = db.subscribe('posts', (posts) => {
  console.log('Posts updated:', posts)
})

// Clean up when done
unsubscribe()

Authentication

Sign Up

const { user, token } = await auth.signUp(
  'user@example.com',
  'password123',
  'John Doe', // optional display name
)

Sign In

const { user, token } = await auth.signIn('user@example.com', 'password123')

Sign Out

await auth.signOut()

Auth State Listener

const unsubscribe = auth.onAuthStateChanged((user) => {
  if (user) {
    console.log('Signed in:', user.email)
  } else {
    console.log('Signed out')
  }
})

Password Reset

await auth.resetPassword('user@example.com')

React Example

'use client'

import { createDatabase, createAuth } from 'firekit'
import { useEffect, useState } from 'react'

const db = createDatabase({
  userId: process.env.NEXT_PUBLIC_AIWA_USER_ID!,
  appId: process.env.NEXT_PUBLIC_AIWA_APP_ID!,
})

const auth = createAuth({
  appId: process.env.NEXT_PUBLIC_AIWA_APP_ID!,
})

export default function TodoApp() {
  const [user, setUser] = useState(null)
  const [todos, setTodos] = useState([])

  // Auth listener
  useEffect(() => {
    return auth.onAuthStateChanged(setUser)
  }, [])

  // Real-time todos subscription
  useEffect(() => {
    if (!user) return

    return db.subscribe(
      'todos',
      setTodos,
      {
        where: [{ field: 'userId', operator: '==', value: user.uid }],
        orderBy: { field: '_createdAt', direction: 'desc' },
      },
    )
  }, [user])

  const addTodo = async (title: string) => {
    await db.create('todos', {
      title,
      completed: false,
      userId: user.uid,
    })
  }

  const toggleTodo = async (id: string, completed: boolean) => {
    await db.update('todos', id, { completed })
  }

  if (!user) return <SignInForm />

  return <TodoList todos={todos} onAdd={addTodo} onToggle={toggleTodo} />
}

Multi-Tenant Isolation

Firekit automatically isolates data using collection paths:

/users/{userId}/apps/{appId}/data/{collection}/{docId}

Example:

  • User A's app: /users/user-a/apps/app-123/data/posts/post-1
  • User B's app: /users/user-b/apps/app-456/data/posts/post-1

Complete isolation - User A's app users cannot access User B's app data.

Security Rules

Firekit enforces security via Firebase Security Rules with custom claims:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId}/apps/{appId}/data/{collection}/{document=**} {
      // AIWA user (app owner) has full access
      allow read, write: if request.auth.token.userId == userId;

      // App end-users have access based on appId
      allow read, write: if request.auth.token.appId == appId
                         && request.auth != null;
    }
  }
}

Error Handling

import { FirekitDatabaseError, FirekitAuthError } from 'firekit'

try {
  await db.create('posts', { title: 'Hello' })
} catch (error) {
  if (error instanceof FirekitDatabaseError) {
    console.error('Database error:', error.message, error.code)
  }
}

try {
  await auth.signIn('email', 'password')
} catch (error) {
  if (error instanceof FirekitAuthError) {
    console.error('Auth error:', error.message, error.code)
  }
}

API Reference

Database Methods

  • create(collection, data) - Create document
  • set(collection, id, data, merge?) - Set document with ID
  • read(collection, id) - Read single document
  • query(collection, options?) - Query documents
  • getAll(collection) - Get all documents
  • update(collection, id, data) - Update document
  • delete(collection, id) - Delete document
  • subscribe(collection, callback, options?) - Real-time subscription
  • subscribeToDoc(collection, id, callback) - Single document subscription
  • batchCreate(collection, items) - Batch create
  • count(collection, options?) - Count documents

Auth Methods

  • signUp(email, password, displayName?) - Register user
  • signIn(email, password) - Sign in user
  • signOut() - Sign out
  • resetPassword(email) - Send reset email
  • updateProfile(data) - Update profile
  • updateEmail(email) - Update email
  • updatePassword(password) - Update password
  • onAuthStateChanged(callback) - Listen to auth changes
  • getIdToken(forceRefresh?) - Get ID token
  • isAuthenticated() - Check auth status

License

Apache-2.0