firestore-schema-kit 1.0.0 → 2.1.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.
@@ -0,0 +1,184 @@
1
+ import { addDoc, collection, deleteDoc as _deleteDoc, doc, getDoc as _getDoc, getDocs as _getDocs, onSnapshot as _onSnapshot, query, runTransaction as _runTransaction, setDoc as _setDoc, updateDoc as _updateDoc, writeBatch, } from 'firebase/firestore';
2
+ function assertSchema(schema, opName) {
3
+ if (!schema || typeof schema !== 'object' || schema._type !== 'CollectionSchema') {
4
+ throw new TypeError(`${opName}: first argument must be a CollectionSchema from defineCollection(). ` +
5
+ `Got: ${typeof schema}`);
6
+ }
7
+ }
8
+ function resolveDocRef(db, schema, idOrRef) {
9
+ if (typeof idOrRef === 'string') {
10
+ return doc(db, schema._name, idOrRef);
11
+ }
12
+ if (idOrRef && typeof idOrRef.path === 'string') {
13
+ return idOrRef;
14
+ }
15
+ throw new TypeError(`Expected a document ID (string) or DocumentReference, got: ${typeof idOrRef}`);
16
+ }
17
+ function collectionRef(db, schema) {
18
+ return collection(db, schema._name);
19
+ }
20
+ function docToData(snapshot) {
21
+ if (!snapshot.exists())
22
+ return null;
23
+ return { id: snapshot.id, ...snapshot.data() };
24
+ }
25
+ function snapshotToArray(querySnapshot) {
26
+ return querySnapshot.docs.map((docSnapshot) => ({
27
+ id: docSnapshot.id,
28
+ ...docSnapshot.data(),
29
+ }));
30
+ }
31
+ function shouldValidatePartial(options) {
32
+ const hasMergeFlag = 'merge' in options && Boolean(options.merge);
33
+ const hasMergeFields = 'mergeFields' in options && Array.isArray(options.mergeFields);
34
+ return hasMergeFlag || hasMergeFields;
35
+ }
36
+ export function initFirestoreSchema(db) {
37
+ if (!db)
38
+ throw new Error('initFirestoreSchema: db (Firestore instance) is required');
39
+ async function createDoc(schema, data) {
40
+ assertSchema(schema, 'createDoc');
41
+ const validated = schema.validate(data);
42
+ const ref = await addDoc(collectionRef(db, schema), validated);
43
+ return ref;
44
+ }
45
+ async function setDoc(schema, idOrRef, data, options = {}) {
46
+ assertSchema(schema, 'setDoc');
47
+ const ref = resolveDocRef(db, schema, idOrRef);
48
+ const validated = shouldValidatePartial(options)
49
+ ? schema.validatePartial(data)
50
+ : schema.validate(data);
51
+ await _setDoc(ref, validated, options);
52
+ }
53
+ async function updateDoc(schema, idOrRef, data) {
54
+ assertSchema(schema, 'updateDoc');
55
+ const ref = resolveDocRef(db, schema, idOrRef);
56
+ const validated = schema.validatePartial(data);
57
+ await _updateDoc(ref, validated);
58
+ }
59
+ async function deleteDoc(schema, idOrRef) {
60
+ assertSchema(schema, 'deleteDoc');
61
+ const ref = resolveDocRef(db, schema, idOrRef);
62
+ await _deleteDoc(ref);
63
+ }
64
+ async function getDoc(schema, idOrRef) {
65
+ assertSchema(schema, 'getDoc');
66
+ const ref = resolveDocRef(db, schema, idOrRef);
67
+ const snapshot = await _getDoc(ref);
68
+ return docToData(snapshot);
69
+ }
70
+ async function getDocs(schema, ...constraints) {
71
+ assertSchema(schema, 'getDocs');
72
+ const ref = collectionRef(db, schema);
73
+ const q = constraints.length ? query(ref, ...constraints) : ref;
74
+ const snapshot = await _getDocs(q);
75
+ return snapshotToArray(snapshot);
76
+ }
77
+ function getDocRef(schema, id) {
78
+ assertSchema(schema, 'getDocRef');
79
+ return doc(db, schema._name, id);
80
+ }
81
+ function getCollectionRef(schema) {
82
+ assertSchema(schema, 'getCollectionRef');
83
+ return collectionRef(db, schema);
84
+ }
85
+ function onDocSnapshot(schema, idOrRef, callback, onError) {
86
+ assertSchema(schema, 'onDocSnapshot');
87
+ const ref = resolveDocRef(db, schema, idOrRef);
88
+ return _onSnapshot(ref, (snapshot) => callback(docToData(snapshot)), onError);
89
+ }
90
+ function onCollectionSnapshot(schema, callback, ...constraints) {
91
+ assertSchema(schema, 'onCollectionSnapshot');
92
+ const ref = collectionRef(db, schema);
93
+ const q = constraints.length ? query(ref, ...constraints) : ref;
94
+ return _onSnapshot(q, (snapshot) => callback(snapshotToArray(snapshot)));
95
+ }
96
+ function createBatch() {
97
+ const batch = writeBatch(db);
98
+ const schemaBatch = {
99
+ create(schema, data) {
100
+ assertSchema(schema, 'batch.create');
101
+ const validated = schema.validate(data);
102
+ const ref = doc(collectionRef(db, schema));
103
+ batch.set(ref, validated);
104
+ return ref;
105
+ },
106
+ set(schema, idOrRef, data, options = {}) {
107
+ assertSchema(schema, 'batch.set');
108
+ const ref = resolveDocRef(db, schema, idOrRef);
109
+ const validated = shouldValidatePartial(options)
110
+ ? schema.validatePartial(data)
111
+ : schema.validate(data);
112
+ batch.set(ref, validated, options);
113
+ return schemaBatch;
114
+ },
115
+ update(schema, idOrRef, data) {
116
+ assertSchema(schema, 'batch.update');
117
+ const ref = resolveDocRef(db, schema, idOrRef);
118
+ const validated = schema.validatePartial(data);
119
+ batch.update(ref, validated);
120
+ return schemaBatch;
121
+ },
122
+ delete(schema, idOrRef) {
123
+ assertSchema(schema, 'batch.delete');
124
+ const ref = resolveDocRef(db, schema, idOrRef);
125
+ batch.delete(ref);
126
+ return schemaBatch;
127
+ },
128
+ commit() {
129
+ return batch.commit();
130
+ },
131
+ };
132
+ return schemaBatch;
133
+ }
134
+ async function runTransaction(updateFn) {
135
+ return _runTransaction(db, async (firestoreTx) => {
136
+ const transaction = {
137
+ async get(schema, idOrRef) {
138
+ assertSchema(schema, 'transaction.get');
139
+ const ref = resolveDocRef(db, schema, idOrRef);
140
+ const snapshot = await firestoreTx.get(ref);
141
+ return docToData(snapshot);
142
+ },
143
+ set(schema, idOrRef, data, options = {}) {
144
+ assertSchema(schema, 'transaction.set');
145
+ const ref = resolveDocRef(db, schema, idOrRef);
146
+ const validated = shouldValidatePartial(options)
147
+ ? schema.validatePartial(data)
148
+ : schema.validate(data);
149
+ firestoreTx.set(ref, validated, options);
150
+ return transaction;
151
+ },
152
+ update(schema, idOrRef, data) {
153
+ assertSchema(schema, 'transaction.update');
154
+ const ref = resolveDocRef(db, schema, idOrRef);
155
+ const validated = schema.validatePartial(data);
156
+ firestoreTx.update(ref, validated);
157
+ return transaction;
158
+ },
159
+ delete(schema, idOrRef) {
160
+ assertSchema(schema, 'transaction.delete');
161
+ const ref = resolveDocRef(db, schema, idOrRef);
162
+ firestoreTx.delete(ref);
163
+ return transaction;
164
+ },
165
+ };
166
+ return updateFn(transaction);
167
+ });
168
+ }
169
+ return {
170
+ createDoc,
171
+ setDoc,
172
+ updateDoc,
173
+ deleteDoc,
174
+ getDoc,
175
+ getDocs,
176
+ getDocRef,
177
+ getCollectionRef,
178
+ onDocSnapshot,
179
+ onCollectionSnapshot,
180
+ createBatch,
181
+ runTransaction,
182
+ };
183
+ }
184
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../operations.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "firestore-schema-kit",
3
- "version": "1.0.0",
4
- "main": "index.js",
5
- "exports": "./index.js",
3
+ "version": "2.1.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
6
12
  "type": "module",
7
13
  "scripts": {
14
+ "build": "tsc -p tsconfig.json",
15
+ "typecheck": "tsc -p tsconfig.json --noEmit",
8
16
  "test": "echo \"Error: no test specified\" && exit 1"
9
17
  },
18
+ "files": [
19
+ "dist",
20
+ "readme.md"
21
+ ],
10
22
  "keywords": [],
11
23
  "author": "Bonanza Narayan",
12
24
  "license": "ISC",
@@ -20,8 +32,12 @@
20
32
  },
21
33
  "homepage": "https://github.com/BonanzaNarayan/firebase-schema#readme",
22
34
  "dependencies": {
23
- "firebase": "^12.11.0",
24
35
  "zod": "^4.3.6"
25
36
  },
26
- "devDependencies": {}
37
+ "peerDependencies": {
38
+ "firebase": "^12.11.0"
39
+ },
40
+ "devDependencies": {
41
+ "typescript": "^6.0.2"
42
+ }
27
43
  }
package/readme.md CHANGED
@@ -9,7 +9,9 @@ Zod handles validation internally. You never touch Zod directly.
9
9
  ## Install
10
10
 
11
11
  ```bash
12
- npm install zod firebase
12
+ npm install firestore-schema-kit
13
+ pnpm add firestore-schema-kit
14
+ bun add firestore-schema-kit
13
15
  ```
14
16
 
15
17
  Copy `src/` into your project (e.g. `lib/firebase-schema/`).
package/collection.js DELETED
@@ -1,98 +0,0 @@
1
- import { z } from 'zod'
2
- import { s } from './fields.js'
3
-
4
- // ─── Schema Validation Error ───────────────────────────────────────────────────
5
-
6
- export class SchemaValidationError extends Error {
7
- constructor(collectionName, zodError) {
8
- const issues = zodError.issues
9
- .map((i) => ` • ${i.path.join('.')}: ${i.message}`)
10
- .join('\n')
11
-
12
- super(`[${collectionName}] Schema validation failed:\n${issues}`)
13
- this.name = 'SchemaValidationError'
14
- this.collection = collectionName
15
- this.issues = zodError.issues
16
- }
17
- }
18
-
19
- // ─── defineCollection ─────────────────────────────────────────────────────────
20
-
21
- /**
22
- * Define a typed Firestore collection with schema validation.
23
- *
24
- * @param {string} collectionName - Firestore collection path (e.g. 'users', 'posts/comments')
25
- * @param {(s: SchemaBuilder) => Record<string, BaseField>} builder - Field definition callback
26
- * @returns {CollectionSchema}
27
- *
28
- * @example
29
- * export const usersSchema = defineCollection('users', (s) => ({
30
- * name: s.string().min(1),
31
- * email: s.string().email(),
32
- * age: s.number().optional(),
33
- * role: s.enum(['admin', 'user']).default('user'),
34
- * createdAt: s.timestamp(),
35
- * }))
36
- */
37
- export function defineCollection(collectionName, builder) {
38
- if (typeof collectionName !== 'string' || !collectionName.trim()) {
39
- throw new Error('defineCollection: collectionName must be a non-empty string')
40
- }
41
- if (typeof builder !== 'function') {
42
- throw new Error('defineCollection: builder must be a function')
43
- }
44
-
45
- // Call builder with the schema builder (s)
46
- const fieldDefs = builder(s)
47
-
48
- if (!fieldDefs || typeof fieldDefs !== 'object') {
49
- throw new Error('defineCollection: builder must return an object of field definitions')
50
- }
51
-
52
- // Convert field definitions → Zod schema shape
53
- const zodShape = {}
54
- for (const [key, field] of Object.entries(fieldDefs)) {
55
- if (typeof field?.toZod !== 'function') {
56
- throw new Error(
57
- `defineCollection [${collectionName}]: field "${key}" is not a valid schema field. ` +
58
- `Use s.string(), s.number(), etc.`
59
- )
60
- }
61
- zodShape[key] = field.toZod()
62
- }
63
-
64
- const zodSchema = z.object(zodShape)
65
- const zodPartialSchema = zodSchema.partial()
66
-
67
- return {
68
- // ── Metadata ────────────────────────────────────────────────────────────
69
- _name: collectionName,
70
- _fieldDefs: fieldDefs,
71
- _type: 'CollectionSchema',
72
-
73
- // ── Validation ──────────────────────────────────────────────────────────
74
-
75
- /** Full validation — use for createDoc / setDoc */
76
- validate(data) {
77
- const result = zodSchema.safeParse(data)
78
- if (!result.success) throw new SchemaValidationError(collectionName, result.error)
79
- return result.data
80
- },
81
-
82
- /** Partial validation — use for updateDoc (only validates fields present in data) */
83
- validatePartial(data) {
84
- const result = zodPartialSchema.safeParse(data)
85
- if (!result.success) throw new SchemaValidationError(collectionName, result.error)
86
- return result.data
87
- },
88
-
89
- /** Safe (non-throwing) full validation */
90
- safeParse(data) {
91
- const result = zodSchema.safeParse(data)
92
- if (!result.success) {
93
- return { success: false, error: new SchemaValidationError(collectionName, result.error) }
94
- }
95
- return { success: true, data: result.data }
96
- },
97
- }
98
- }
package/fields.js DELETED
@@ -1,245 +0,0 @@
1
- import { z } from 'zod'
2
-
3
- // ─── Base Field ───────────────────────────────────────────────────────────────
4
-
5
- class BaseField {
6
- constructor() {
7
- this._optional = false
8
- this._nullable = false
9
- this._hasDefault = false
10
- this._defaultVal = undefined
11
- }
12
-
13
- optional() {
14
- this._optional = true
15
- return this
16
- }
17
-
18
- nullable() {
19
- this._nullable = true
20
- return this
21
- }
22
-
23
- default(val) {
24
- this._hasDefault = true
25
- this._defaultVal = val
26
- return this
27
- }
28
-
29
- // Subclasses implement this — returns a raw Zod schema with no optional/default wrapping
30
- _baseZod() {
31
- throw new Error(`_baseZod() not implemented on ${this.constructor.name}`)
32
- }
33
-
34
- // Builds the final Zod schema, applying nullable → default → optional in the correct order
35
- toZod() {
36
- let schema = this._baseZod()
37
- if (this._nullable) schema = schema.nullable()
38
- if (this._hasDefault) schema = schema.default(this._defaultVal)
39
- if (this._optional) schema = schema.optional()
40
- return schema
41
- }
42
- }
43
-
44
- // ─── String ───────────────────────────────────────────────────────────────────
45
-
46
- export class StringField extends BaseField {
47
- constructor() {
48
- super()
49
- this._min = null
50
- this._max = null
51
- this._email = false
52
- this._url = false
53
- this._uuid = false
54
- this._regex = null
55
- }
56
-
57
- min(n) { this._min = n; return this }
58
- max(n) { this._max = n; return this }
59
- email() { this._email = true; return this }
60
- url() { this._url = true; return this }
61
- uuid() { this._uuid = true; return this }
62
- regex(r) { this._regex = r; return this }
63
-
64
- _baseZod() {
65
- let schema = z.string()
66
- if (this._min !== null) schema = schema.min(this._min)
67
- if (this._max !== null) schema = schema.max(this._max)
68
- if (this._email) schema = schema.email()
69
- if (this._url) schema = schema.url()
70
- if (this._uuid) schema = schema.uuid()
71
- if (this._regex !== null) schema = schema.regex(this._regex)
72
- return schema
73
- }
74
- }
75
-
76
- // ─── Number ───────────────────────────────────────────────────────────────────
77
-
78
- export class NumberField extends BaseField {
79
- constructor() {
80
- super()
81
- this._min = null
82
- this._max = null
83
- this._int = false
84
- this._positive = false
85
- this._negative = false
86
- }
87
-
88
- min(n) { this._min = n; return this }
89
- max(n) { this._max = n; return this }
90
- int() { this._int = true; return this }
91
- positive() { this._positive = true; return this }
92
- negative() { this._negative = true; return this }
93
-
94
- _baseZod() {
95
- let schema = this._int ? z.number().int() : z.number()
96
- if (this._min !== null) schema = schema.min(this._min)
97
- if (this._max !== null) schema = schema.max(this._max)
98
- if (this._positive) schema = schema.positive()
99
- if (this._negative) schema = schema.negative()
100
- return schema
101
- }
102
- }
103
-
104
- // ─── Boolean ──────────────────────────────────────────────────────────────────
105
-
106
- export class BooleanField extends BaseField {
107
- _baseZod() {
108
- return z.boolean()
109
- }
110
- }
111
-
112
- // ─── Timestamp ────────────────────────────────────────────────────────────────
113
- // Accepts: JS Date, Firestore Timestamp, serverTimestamp() sentinel
114
-
115
- export class TimestampField extends BaseField {
116
- _baseZod() {
117
- return z.custom(
118
- (val) => {
119
- if (!val) return false
120
- // JS Date
121
- if (val instanceof Date) return true
122
- // Firestore Timestamp (has toDate method)
123
- if (typeof val.toDate === 'function') return true
124
- // serverTimestamp() sentinel — has _methodName internally
125
- if (typeof val === 'object' && '_methodName' in val) return true
126
- return false
127
- },
128
- { message: 'Expected a Date, Firestore Timestamp, or serverTimestamp()' }
129
- )
130
- }
131
- }
132
-
133
- // ─── Array ────────────────────────────────────────────────────────────────────
134
-
135
- export class ArrayField extends BaseField {
136
- constructor(itemField) {
137
- super()
138
- this._itemField = itemField
139
- this._min = null
140
- this._max = null
141
- }
142
-
143
- min(n) { this._min = n; return this }
144
- max(n) { this._max = n; return this }
145
-
146
- _baseZod() {
147
- let schema = z.array(this._itemField.toZod())
148
- if (this._min !== null) schema = schema.min(this._min)
149
- if (this._max !== null) schema = schema.max(this._max)
150
- return schema
151
- }
152
- }
153
-
154
- // ─── Map (nested object) ──────────────────────────────────────────────────────
155
-
156
- export class MapField extends BaseField {
157
- constructor(shape) {
158
- super()
159
- this._shape = shape
160
- }
161
-
162
- _baseZod() {
163
- const zodShape = {}
164
- for (const [key, field] of Object.entries(this._shape)) {
165
- zodShape[key] = field.toZod()
166
- }
167
- return z.object(zodShape)
168
- }
169
- }
170
-
171
- // ─── Enum ─────────────────────────────────────────────────────────────────────
172
-
173
- export class EnumField extends BaseField {
174
- constructor(values) {
175
- super()
176
- this._values = values
177
- }
178
-
179
- _baseZod() {
180
- return z.enum(this._values)
181
- }
182
- }
183
-
184
- // ─── Literal ──────────────────────────────────────────────────────────────────
185
-
186
- export class LiteralField extends BaseField {
187
- constructor(value) {
188
- super()
189
- this._value = value
190
- }
191
-
192
- _baseZod() {
193
- return z.literal(this._value)
194
- }
195
- }
196
-
197
- // ─── Reference (Firestore DocumentReference) ──────────────────────────────────
198
-
199
- export class ReferenceField extends BaseField {
200
- _baseZod() {
201
- return z.custom(
202
- (val) => val && typeof val.path === 'string' && typeof val.id === 'string',
203
- { message: 'Expected a Firestore DocumentReference' }
204
- )
205
- }
206
- }
207
-
208
- // ─── Union ────────────────────────────────────────────────────────────────────
209
-
210
- export class UnionField extends BaseField {
211
- constructor(fields) {
212
- super()
213
- this._fields = fields
214
- }
215
-
216
- _baseZod() {
217
- const schemas = this._fields.map((f) => f.toZod())
218
- return z.union(schemas)
219
- }
220
- }
221
-
222
- // ─── Any (escape hatch) ───────────────────────────────────────────────────────
223
-
224
- export class AnyField extends BaseField {
225
- _baseZod() {
226
- return z.any()
227
- }
228
- }
229
-
230
- // ─── Schema Builder (s) ───────────────────────────────────────────────────────
231
- // This is what gets passed into the defineCollection callback
232
-
233
- export const s = {
234
- string: () => new StringField(),
235
- number: () => new NumberField(),
236
- boolean: () => new BooleanField(),
237
- timestamp: () => new TimestampField(),
238
- array: (itemField) => new ArrayField(itemField),
239
- map: (shape) => new MapField(shape),
240
- enum: (values) => new EnumField(values),
241
- literal: (value) => new LiteralField(value),
242
- reference: () => new ReferenceField(),
243
- union: (fields) => new UnionField(fields),
244
- any: () => new AnyField(),
245
- }
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- export { s } from './fields.js'
2
- export { defineCollection, SchemaValidationError } from './collection.js'
3
- export { initFirestoreSchema } from './operations.js'