@jobsearch-works/firestore-models 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # firestore-models
2
+
3
+ A shared library for standardizing Firestore document schemas and paths across multiple projects. This library provides:
4
+
5
+ - Standardized document models and interfaces
6
+ - Consistent path builders for Firestore collections and documents
7
+ - Type-safe access to Firestore data
8
+ - Shared validation and transformation utilities
9
+
10
+ ## Purpose
11
+
12
+ This library serves as a single source of truth for Firestore data structures across different applications. By centralizing the schema definitions, it:
13
+
14
+ - Ensures consistency in data structure across projects
15
+ - Reduces duplication of model definitions
16
+ - Provides type safety when working with Firestore data
17
+ - Makes it easier to maintain and update schemas across all applications
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @jsw/firestore-models
23
+ # or
24
+ yarn add @jsw/firestore-models
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Import the models and path builders in your application:
30
+
31
+ ```typescript
32
+ import { User, userPath } from "@jsw/firestore-models";
33
+
34
+ // Use the type-safe model
35
+ const user: User = {
36
+ id: "123",
37
+ name: "John Doe",
38
+ email: "john@example.com",
39
+ };
40
+
41
+ // Use the path builder
42
+ const userDocPath = userPath("123"); // returns 'users/123'
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ When adding new models or modifying existing ones:
48
+
49
+ 1. Update the TypeScript interfaces
50
+ 2. Add corresponding path builders
51
+ 3. Update any validation or transformation utilities
52
+ 4. Update this documentation
53
+ 5. Ensure backward compatibility when possible
54
+
55
+ ## License
56
+
57
+ MIT
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generic type for all model interfaces
3
+ */
4
+ export interface BaseModel {
5
+ id?: string;
6
+ createdAt?: Date | string;
7
+ updatedAt?: Date | string;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace VacancySuggestion {
3
+ /**
4
+ * Represents a job vacancy suggestion for a client
5
+ */
6
+ interface Model extends BaseModel {
7
+ clientId: string;
8
+ vacancyId: string;
9
+ vacancyCompany: string;
10
+ vacancyPosition: string;
11
+ status: string;
12
+ createdAt: Date | string;
13
+ updatedAt?: Date | string;
14
+ }
15
+ const collection: (clientId: string) => string;
16
+ const document: (clientId: string, suggestionId: string) => string;
17
+ const formatSummary: (suggestion: VacancySuggestion.Model) => string;
18
+ const createNew: (clientId: string, vacancyId: string, vacancyCompany: string, vacancyPosition: string, status?: string) => VacancySuggestion.Model;
19
+ }
@@ -0,0 +1,18 @@
1
+ export var VacancySuggestion;
2
+ (function (VacancySuggestion) {
3
+ VacancySuggestion.collection = (clientId) => `clients/${clientId}/vacancySuggestions`;
4
+ VacancySuggestion.document = (clientId, suggestionId) => `clients/${clientId}/vacancySuggestions/${suggestionId}`;
5
+ VacancySuggestion.formatSummary = (suggestion) => {
6
+ return `${suggestion.vacancyPosition} at ${suggestion.vacancyCompany} (${suggestion.status})`;
7
+ };
8
+ VacancySuggestion.createNew = (clientId, vacancyId, vacancyCompany, vacancyPosition, status = "new") => {
9
+ return {
10
+ clientId,
11
+ vacancyId,
12
+ vacancyCompany,
13
+ vacancyPosition,
14
+ status,
15
+ createdAt: new Date().toISOString(),
16
+ };
17
+ };
18
+ })(VacancySuggestion || (VacancySuggestion = {}));
@@ -0,0 +1,40 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace Application {
3
+ /**
4
+ * Represents a job application
5
+ */
6
+ interface Model extends BaseModel {
7
+ vacancyId: string;
8
+ clientId: string;
9
+ status: "new" | "submitted" | "interviewing" | "accepted" | "rejected" | "withdrawn" | "applying" | "suggested" | "approved";
10
+ coverLetter?: string;
11
+ resume?: string;
12
+ company?: string;
13
+ position?: string;
14
+ location?: string;
15
+ jobId?: string;
16
+ advertisingUrl?: string;
17
+ applicationUrl?: string;
18
+ applicationDomain?: string;
19
+ advertisingDomain?: string;
20
+ description?: string;
21
+ fullPageText?: string;
22
+ }
23
+ const collection: (clientId: string) => string;
24
+ const document: (clientId: string, applicationId: string) => string;
25
+ const formatSummary: (application: Application.Model) => string;
26
+ const formatDate: (date: Date | string) => string;
27
+ const createNew: (clientId: string, vacancyId: string, vacancyData?: {
28
+ company?: string;
29
+ position?: string;
30
+ location?: string;
31
+ jobId?: string;
32
+ advertisingUrl?: string;
33
+ applicationUrl?: string;
34
+ applicationDomain?: string;
35
+ advertisingDomain?: string;
36
+ description?: string;
37
+ fullPageText?: string;
38
+ }) => Application.Model;
39
+ const updateStatus: (application: Application.Model, newStatus: Application.Model["status"]) => Application.Model;
40
+ }
@@ -0,0 +1,37 @@
1
+ export var Application;
2
+ (function (Application) {
3
+ Application.collection = (clientId) => `clients/${clientId}/applications`;
4
+ Application.document = (clientId, applicationId) => `clients/${clientId}/applications/${applicationId}`;
5
+ Application.formatSummary = (application) => {
6
+ return `${application.position} at ${application.company} (${application.status})`;
7
+ };
8
+ Application.formatDate = (date) => {
9
+ const dateObj = date instanceof Date ? date : new Date(date);
10
+ return dateObj.toLocaleDateString();
11
+ };
12
+ Application.createNew = (clientId, vacancyId, vacancyData = {}) => {
13
+ return {
14
+ clientId,
15
+ vacancyId,
16
+ status: "new",
17
+ company: vacancyData.company,
18
+ position: vacancyData.position,
19
+ location: vacancyData.location,
20
+ jobId: vacancyData.jobId,
21
+ advertisingUrl: vacancyData.advertisingUrl,
22
+ applicationUrl: vacancyData.applicationUrl,
23
+ applicationDomain: vacancyData.applicationDomain,
24
+ advertisingDomain: vacancyData.advertisingDomain,
25
+ description: vacancyData.description,
26
+ fullPageText: vacancyData.fullPageText,
27
+ createdAt: new Date().toISOString(),
28
+ };
29
+ };
30
+ Application.updateStatus = (application, newStatus) => {
31
+ return {
32
+ ...application,
33
+ status: newStatus,
34
+ updatedAt: new Date().toISOString(),
35
+ };
36
+ };
37
+ })(Application || (Application = {}));
@@ -0,0 +1,31 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ interface FirestoreTimestamp {
3
+ seconds: number;
4
+ nanoseconds: number;
5
+ _firestore_timestamp?: boolean;
6
+ }
7
+ /**
8
+ * AuthUser interface - replaces the old class-based model
9
+ */
10
+ export interface AuthUser extends BaseModel {
11
+ email: string;
12
+ displayName?: string;
13
+ photoURL?: string;
14
+ lastSignIn?: Date | string;
15
+ emailVerified?: boolean;
16
+ }
17
+ export declare const AuthUserCollectionPath = "users";
18
+ export declare const getAuthUserDocumentPath: (userId: string) => string;
19
+ export declare const AuthUserUtils: {
20
+ getTimestampFields: () => string[];
21
+ isFirestoreTimestamp: (value: any) => value is FirestoreTimestamp;
22
+ fromFirebaseUser: (user: any) => AuthUser;
23
+ formatDates: (user: AuthUser) => {
24
+ lastSignIn: string;
25
+ createdAt: string;
26
+ updatedAt?: string;
27
+ };
28
+ toFirestore: (user: AuthUser) => Record<string, any>;
29
+ fromFirestore: (data: Record<string, any>) => AuthUser;
30
+ };
31
+ export {};
@@ -0,0 +1,80 @@
1
+ // Path constants
2
+ export const AuthUserCollectionPath = "users";
3
+ export const getAuthUserDocumentPath = (userId) => `users/${userId}`;
4
+ // Helper utilities for working with AuthUser
5
+ export const AuthUserUtils = {
6
+ // Get timestamp fields for AuthUser
7
+ getTimestampFields: () => [],
8
+ // Check if value is a Firestore timestamp
9
+ isFirestoreTimestamp: (value) => {
10
+ return (typeof value === "object" &&
11
+ value !== null &&
12
+ ("seconds" in value || "_firestore_timestamp" in value));
13
+ },
14
+ // Create from Firebase user object
15
+ fromFirebaseUser: (user) => {
16
+ return {
17
+ id: user.uid,
18
+ email: user.email,
19
+ displayName: user.displayName,
20
+ photoURL: user.photoURL,
21
+ emailVerified: user.emailVerified,
22
+ lastSignIn: new Date().toISOString(), // Current timestamp for new logins
23
+ createdAt: new Date().toISOString(),
24
+ };
25
+ },
26
+ // Convert dates to display format
27
+ formatDates: (user) => {
28
+ const formatDate = (dateValue) => {
29
+ if (!dateValue)
30
+ return "N/A";
31
+ const date = typeof dateValue === "string" ? new Date(dateValue) : dateValue;
32
+ return date.toLocaleString();
33
+ };
34
+ return {
35
+ lastSignIn: formatDate(user.lastSignIn),
36
+ createdAt: formatDate(user.createdAt),
37
+ updatedAt: user.updatedAt ? formatDate(user.updatedAt) : undefined,
38
+ };
39
+ },
40
+ // Convert AuthUser to format for storage
41
+ toFirestore: (user) => {
42
+ // Create a copy of the object without the id field
43
+ const { id, ...data } = user;
44
+ // Ensure dates are in ISO string format
45
+ if (data.lastSignIn && data.lastSignIn instanceof Date) {
46
+ data.lastSignIn = data.lastSignIn.toISOString();
47
+ }
48
+ if (data.createdAt && data.createdAt instanceof Date) {
49
+ data.createdAt = data.createdAt.toISOString();
50
+ }
51
+ if (data.updatedAt && data.updatedAt instanceof Date) {
52
+ data.updatedAt = data.updatedAt.toISOString();
53
+ }
54
+ else {
55
+ // Add standard updatedAt timestamp to all documents
56
+ data.updatedAt = new Date().toISOString();
57
+ }
58
+ return data;
59
+ },
60
+ // Convert from Firestore data to AuthUser
61
+ fromFirestore: (data) => {
62
+ // Convert any timestamp fields
63
+ const processedData = { ...data };
64
+ // Process each timestamp field
65
+ const timestampFields = [];
66
+ timestampFields.forEach((field) => {
67
+ if (data[field]) {
68
+ if (AuthUserUtils.isFirestoreTimestamp(data[field])) {
69
+ // Convert Firestore timestamp to Date
70
+ processedData[field] = new Date(data[field].seconds * 1000).toISOString();
71
+ }
72
+ else if (typeof data[field] === "string") {
73
+ // Keep ISO string as is
74
+ processedData[field] = data[field];
75
+ }
76
+ }
77
+ });
78
+ return processedData;
79
+ },
80
+ };
@@ -0,0 +1,13 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace Client {
3
+ interface Model extends BaseModel {
4
+ name: string;
5
+ email: string;
6
+ status: "active" | "inactive";
7
+ resume?: string;
8
+ }
9
+ const collection: () => string;
10
+ const document: (clientId: string) => string;
11
+ const formatClient: (client: Client.Model) => string;
12
+ const createNew: (name: string, email: string) => Client.Model;
13
+ }
@@ -0,0 +1,16 @@
1
+ export var Client;
2
+ (function (Client) {
3
+ Client.collection = () => "clients";
4
+ Client.document = (clientId) => `clients/${clientId}`;
5
+ Client.formatClient = (client) => {
6
+ return `${client.name} (${client.email}) - ${client.status}`;
7
+ };
8
+ Client.createNew = (name, email) => {
9
+ return {
10
+ name,
11
+ email,
12
+ status: "active",
13
+ createdAt: new Date().toISOString(),
14
+ };
15
+ };
16
+ })(Client || (Client = {}));
@@ -0,0 +1,25 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace ClientData {
3
+ /**
4
+ * Represents a user's personal data.
5
+ */
6
+ interface Model extends BaseModel {
7
+ firstName: string;
8
+ lastName: string;
9
+ middleName: string;
10
+ preferredName: string;
11
+ email: string;
12
+ phone: string;
13
+ address: string;
14
+ city: string;
15
+ state: string;
16
+ zip: string;
17
+ country: string;
18
+ linkedIn?: string;
19
+ countryPhoneCode?: string;
20
+ }
21
+ const collection: () => string;
22
+ const document: (clientDataId: string) => string;
23
+ const formatClientData: (clientData: ClientData.Model) => string;
24
+ const createNew: (firstName: string, lastName: string, email: string, phone: string, address: string, city: string, state: string, zip: string, country: string) => ClientData.Model;
25
+ }
@@ -0,0 +1,24 @@
1
+ export var ClientData;
2
+ (function (ClientData) {
3
+ ClientData.collection = () => "clientData";
4
+ ClientData.document = (clientDataId) => `clientData/${clientDataId}`;
5
+ ClientData.formatClientData = (clientData) => {
6
+ return `${clientData.firstName} ${clientData.lastName} (${clientData.email})`;
7
+ };
8
+ ClientData.createNew = (firstName, lastName, email, phone, address, city, state, zip, country) => {
9
+ return {
10
+ firstName,
11
+ lastName,
12
+ middleName: "",
13
+ preferredName: "",
14
+ email,
15
+ phone,
16
+ address,
17
+ city,
18
+ state,
19
+ zip,
20
+ country,
21
+ createdAt: new Date().toISOString(),
22
+ };
23
+ };
24
+ })(ClientData || (ClientData = {}));
@@ -0,0 +1,18 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace ClientLogin {
3
+ /**
4
+ * Represents login credentials for a client website
5
+ */
6
+ interface Model extends BaseModel {
7
+ userId: string;
8
+ url: string;
9
+ domain: string;
10
+ username?: string;
11
+ password: string;
12
+ email?: string;
13
+ }
14
+ const collection: (userId: string) => string;
15
+ const document: (userId: string, domain: string) => string;
16
+ const formatClientLogin: (clientLogin: ClientLogin.Model) => string;
17
+ const createNew: (userId: string, url: string, domain: string, password: string, username?: string, email?: string) => ClientLogin.Model;
18
+ }
@@ -0,0 +1,19 @@
1
+ export var ClientLogin;
2
+ (function (ClientLogin) {
3
+ ClientLogin.collection = (userId) => `clientLogins/${userId}`;
4
+ ClientLogin.document = (userId, domain) => `clientLogins/${userId}/logins/${domain}`;
5
+ ClientLogin.formatClientLogin = (clientLogin) => {
6
+ return `${clientLogin.domain} (${clientLogin.username || clientLogin.email || "no username"})`;
7
+ };
8
+ ClientLogin.createNew = (userId, url, domain, password, username, email) => {
9
+ return {
10
+ userId,
11
+ url,
12
+ domain,
13
+ password,
14
+ username,
15
+ email,
16
+ createdAt: new Date().toISOString(),
17
+ };
18
+ };
19
+ })(ClientLogin || (ClientLogin = {}));
@@ -0,0 +1,34 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ /**
3
+ * QuestionData interface defines the core data fields for a generic question.
4
+ */
5
+ export interface QuestionData {
6
+ question: string;
7
+ options: string[];
8
+ }
9
+ /**
10
+ * Question interface - extends BaseModelInterface and includes QuestionData
11
+ */
12
+ export interface Question extends BaseModel, QuestionData {
13
+ }
14
+ export interface ApplicationQuestion {
15
+ questionText: string;
16
+ type: "text";
17
+ answer?: string;
18
+ }
19
+ /**
20
+ * Represents ApplicationQuestion data including its Firestore document ID.
21
+ */
22
+ export type ApplicationQuestionDocument = ApplicationQuestion & {
23
+ id: string;
24
+ };
25
+ /**
26
+ * Represents a question-answer pair stored centrally for a client.
27
+ * Assumes structure in clients/{clientId}/questions collection.
28
+ */
29
+ export interface ClientQuestionAnswerPair {
30
+ id?: string;
31
+ questionText: string;
32
+ answer: string;
33
+ createdAt?: Date;
34
+ }
@@ -0,0 +1 @@
1
+ export {};
File without changes
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // import { BaseModel } from "../BaseModel";
3
+ // /**
4
+ // * ClientLogin interface - represents login credentials for a client website
5
+ // */
6
+ // export interface ClientLogin extends BaseModel {
7
+ // userId: string;
8
+ // url: string;
9
+ // username?: string;
10
+ // password: string;
11
+ // email?: string;
12
+ // createdAt: Date | string;
13
+ // updatedAt?: Date | string;
14
+ // }
15
+ // // Helper functions for ClientLogin collections
16
+ // export const getClientLoginCollectionPath = (userId: string) =>
17
+ // ClientLoginPaths.collection(userId);
18
+ // export const getClientLoginDocumentPath = (userId: string, loginId: string) =>
19
+ // ClientLoginPaths.document(userId, loginId);
20
+ // // Helper utilities for working with ClientLogins
21
+ // export const ClientLoginUtils = {
22
+ // // Format dates for display
23
+ // formatDates: (
24
+ // login: ClientLogin
25
+ // ): { createdAt: string; updatedAt: string } => {
26
+ // const createdDate =
27
+ // login.createdAt instanceof Date
28
+ // ? login.createdAt
29
+ // : new Date(login.createdAt);
30
+ // const updatedDate = login.updatedAt
31
+ // ? login.updatedAt instanceof Date
32
+ // ? login.updatedAt
33
+ // : new Date(login.updatedAt)
34
+ // : createdDate;
35
+ // return {
36
+ // createdAt: createdDate.toLocaleDateString(),
37
+ // updatedAt: updatedDate.toLocaleDateString(),
38
+ // };
39
+ // },
40
+ // // Create a new login with defaults
41
+ // createNew: (
42
+ // userId: string,
43
+ // url: string,
44
+ // password: string,
45
+ // username?: string
46
+ // ): ClientLogin => {
47
+ // return {
48
+ // userId,
49
+ // url,
50
+ // username,
51
+ // password,
52
+ // createdAt: new Date().toISOString(),
53
+ // };
54
+ // },
55
+ // // Get display name for a login (e.g. for UI lists)
56
+ // getDisplayName: (login: ClientLogin): string => {
57
+ // return `${login.url} (${login.username || "no username"})`;
58
+ // },
59
+ // };
@@ -0,0 +1,15 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ /**
3
+ * UserQuestionData interface defines the core data fields for a user question.
4
+ */
5
+ export interface UserQuestionData {
6
+ userId: string;
7
+ question: string;
8
+ answer: string;
9
+ options: string[];
10
+ }
11
+ /**
12
+ * UserQuestion interface - extends BaseModel and includes UserQuestionData
13
+ */
14
+ export interface UserQuestion extends BaseModel, UserQuestionData {
15
+ }
@@ -0,0 +1,37 @@
1
+ export {};
2
+ // Remove the old class definition and path methods
3
+ /*
4
+ export class UserQuestion extends FirestoreModel {
5
+ userId!: string
6
+ question!: string
7
+ answer!: string
8
+ options!: string[]
9
+
10
+ constructor(data: { id?: string } & UserQuestionData) {
11
+ super(data)
12
+ if (!data.options) {
13
+ // Default options logic needs to move to creation site
14
+ // this.options = []
15
+ }
16
+ }
17
+
18
+ static buildPath(userId: string, id?: string): string {
19
+ let path = `users/${userId}/questions`
20
+ return id ? `${path}/${id}` : path
21
+ }
22
+
23
+ getDocPath(): string {
24
+ if (!this.id) throw new Error('Cannot get document path without an ID')
25
+ if (!this.userId) throw new Error('Missing userId for doc path')
26
+ return UserQuestion.buildPath(this.userId, this.id)
27
+ }
28
+
29
+ getColPath(): string {
30
+ if (!this.userId) throw new Error('Missing userId for col path')
31
+ return UserQuestion.buildPath(this.userId)
32
+ }
33
+ }
34
+ */
35
+ // Add helper path functions (assuming UserQuestionPaths exists)
36
+ // export const getUserQuestionCollectionPath = (userId: string) => UserQuestionPaths.collection(userId);
37
+ // export const getUserQuestionDocumentPath = (userId: string, questionId: string) => UserQuestionPaths.document(userId, questionId);
@@ -0,0 +1,24 @@
1
+ import { BaseModel } from "../BaseModel";
2
+ export declare namespace Vacancy {
3
+ /**
4
+ * Represents a job vacancy
5
+ */
6
+ interface Model extends BaseModel {
7
+ company: string;
8
+ position: string;
9
+ location: string;
10
+ description: string;
11
+ advertisingUrl: string;
12
+ applicationUrl: string;
13
+ applicationDomain: string;
14
+ advertisingDomain: string;
15
+ fullPageText: string;
16
+ jobId: string;
17
+ suggestedTo?: string[];
18
+ }
19
+ const collection: () => string;
20
+ const document: (vacancyId: string) => string;
21
+ const formatSummary: (vacancy: Vacancy.Model) => string;
22
+ const formatDate: (date: Date | string) => string;
23
+ const createNew: (company: string, position: string, location: string, description: string, advertisingUrl: string, applicationUrl: string, applicationDomain: string, advertisingDomain: string, fullPageText: string, jobId: string) => Vacancy.Model;
24
+ }
@@ -0,0 +1,27 @@
1
+ export var Vacancy;
2
+ (function (Vacancy) {
3
+ Vacancy.collection = () => "vacancies";
4
+ Vacancy.document = (vacancyId) => `vacancies/${vacancyId}`;
5
+ Vacancy.formatSummary = (vacancy) => {
6
+ return `${vacancy.position} at ${vacancy.company} (${vacancy.location})`;
7
+ };
8
+ Vacancy.formatDate = (date) => {
9
+ const dateObj = date instanceof Date ? date : new Date(date);
10
+ return dateObj.toLocaleDateString();
11
+ };
12
+ Vacancy.createNew = (company, position, location, description, advertisingUrl, applicationUrl, applicationDomain, advertisingDomain, fullPageText, jobId) => {
13
+ return {
14
+ company,
15
+ position,
16
+ location,
17
+ description,
18
+ advertisingUrl,
19
+ applicationUrl,
20
+ applicationDomain,
21
+ advertisingDomain,
22
+ fullPageText,
23
+ jobId,
24
+ createdAt: new Date().toISOString(),
25
+ };
26
+ };
27
+ })(Vacancy || (Vacancy = {}));
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@jobsearch-works/firestore-models",
3
+ "version": "1.0.0",
4
+ "description": "A shared library for standardizing Firestore document schemas and paths across multiple projects",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepare": "npm run build",
13
+ "test": "vitest",
14
+ "lint": "eslint ./src",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/jobsearch-works/firestore-models"
20
+ },
21
+ "keywords": [
22
+ "firestore",
23
+ "typescript",
24
+ "schema",
25
+ "models",
26
+ "firebase",
27
+ "shared",
28
+ "types"
29
+ ],
30
+ "author": "JobSearch Works",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "zod": "^3.22.2"
34
+ },
35
+ "peerDependencies": {
36
+ "firebase": "^10.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
40
+ "@typescript-eslint/parser": "^6.0.0",
41
+ "eslint": "^8.56.0",
42
+ "typescript": "^5.3.3",
43
+ "tsup": "^7.2.0",
44
+ "vitest": "^1.2.2",
45
+ "@vitest/coverage-v8": "^1.2.2"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ }
50
+ }