clefbase 1.3.7 → 1.3.8

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/dist/cli.js CHANGED
@@ -34523,7 +34523,7 @@ async function runSitesList(cwd = process.cwd()) {
34523
34523
  }
34524
34524
 
34525
34525
  // package.json
34526
- var version = "1.3.7";
34526
+ var version = "1.3.8";
34527
34527
 
34528
34528
  // src/cli/index.ts
34529
34529
  var program2 = new Command();
@@ -0,0 +1,62 @@
1
+ import { HttpClient } from "../http";
2
+ import type { ClefbaseDocument } from "../types";
3
+ /**
4
+ * Atomic multi-document writer.
5
+ *
6
+ * @example
7
+ * const batch = db.batch();
8
+ *
9
+ * // set — full overwrite (no merge)
10
+ * batch.set(db.collection("users").doc("u1"), { name: "Alice", role: "admin" });
11
+ *
12
+ * // update — merge patch (same as doc.update())
13
+ * batch.update(db.collection("posts").doc("p1"), { views: FieldValue.increment(1) });
14
+ *
15
+ * // delete a document
16
+ * batch.delete(db.collection("sessions").doc("s9"));
17
+ *
18
+ * await batch.commit();
19
+ */
20
+ export declare class WriteBatch {
21
+ private readonly http;
22
+ private readonly _ops;
23
+ private _committed;
24
+ constructor(http: HttpClient);
25
+ /** Number of operations staged so far. */
26
+ get size(): number;
27
+ private _assertNotCommitted;
28
+ /**
29
+ * Stage a full overwrite for the given document reference.
30
+ * Equivalent to `ref.set(data)`.
31
+ */
32
+ set<T extends ClefbaseDocument>(ref: {
33
+ collectionPath: string;
34
+ id: string;
35
+ }, data: Omit<T, "_id" | "_createdAt" | "_updatedAt">): this;
36
+ /**
37
+ * Stage a merge-patch update for the given document reference.
38
+ * Equivalent to `ref.update(data)`.
39
+ * Supports FieldValue sentinels.
40
+ */
41
+ update<T extends ClefbaseDocument>(ref: {
42
+ collectionPath: string;
43
+ id: string;
44
+ }, data: Partial<Omit<T, "_id" | "_createdAt" | "_updatedAt">>): this;
45
+ /**
46
+ * Stage a document deletion.
47
+ * Equivalent to `ref.delete()`.
48
+ */
49
+ delete(ref: {
50
+ collectionPath: string;
51
+ id: string;
52
+ }): this;
53
+ /**
54
+ * Execute all staged operations atomically.
55
+ * After commit() the batch is sealed — calling commit() again throws.
56
+ *
57
+ * @example
58
+ * await batch.commit();
59
+ */
60
+ commit(): Promise<void>;
61
+ }
62
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/db/batch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA6BjD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAU;IAIT,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,UAAU,CAAS;gBAEE,IAAI,EAAE,UAAU;IAE7C,0CAA0C;IAC1C,IAAI,IAAI,IAAI,MAAM,CAA6B;IAE/C,OAAO,CAAC,mBAAmB;IAM3B;;;OAGG;IACH,GAAG,CAAC,CAAC,SAAS,gBAAgB,EAC5B,GAAG,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAC3C,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,YAAY,GAAG,YAAY,CAAC,GACjD,IAAI;IAYP;;;;OAIG;IACH,MAAM,CAAC,CAAC,SAAS,gBAAgB,EAC/B,GAAG,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAC3C,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAC1D,IAAI;IAYP;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAUzD;;;;;;OAMG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ9B"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WriteBatch = void 0;
4
+ /**
5
+ * Atomic multi-document writer.
6
+ *
7
+ * @example
8
+ * const batch = db.batch();
9
+ *
10
+ * // set — full overwrite (no merge)
11
+ * batch.set(db.collection("users").doc("u1"), { name: "Alice", role: "admin" });
12
+ *
13
+ * // update — merge patch (same as doc.update())
14
+ * batch.update(db.collection("posts").doc("p1"), { views: FieldValue.increment(1) });
15
+ *
16
+ * // delete a document
17
+ * batch.delete(db.collection("sessions").doc("s9"));
18
+ *
19
+ * await batch.commit();
20
+ */
21
+ class WriteBatch {
22
+ constructor(http) {
23
+ this.http = http;
24
+ this._ops = [];
25
+ this._committed = false;
26
+ }
27
+ /** Number of operations staged so far. */
28
+ get size() { return this._ops.length; }
29
+ _assertNotCommitted() {
30
+ if (this._committed) {
31
+ throw new Error("WriteBatch: cannot add operations after commit()");
32
+ }
33
+ }
34
+ /**
35
+ * Stage a full overwrite for the given document reference.
36
+ * Equivalent to `ref.set(data)`.
37
+ */
38
+ set(ref, data) {
39
+ this._assertNotCommitted();
40
+ this._ops.push({
41
+ type: "set",
42
+ collectionPath: ref.collectionPath,
43
+ id: ref.id,
44
+ data: data,
45
+ merge: false,
46
+ });
47
+ return this;
48
+ }
49
+ /**
50
+ * Stage a merge-patch update for the given document reference.
51
+ * Equivalent to `ref.update(data)`.
52
+ * Supports FieldValue sentinels.
53
+ */
54
+ update(ref, data) {
55
+ this._assertNotCommitted();
56
+ this._ops.push({
57
+ type: "update",
58
+ collectionPath: ref.collectionPath,
59
+ id: ref.id,
60
+ data: data,
61
+ merge: true,
62
+ });
63
+ return this;
64
+ }
65
+ /**
66
+ * Stage a document deletion.
67
+ * Equivalent to `ref.delete()`.
68
+ */
69
+ delete(ref) {
70
+ this._assertNotCommitted();
71
+ this._ops.push({
72
+ type: "delete",
73
+ collectionPath: ref.collectionPath,
74
+ id: ref.id,
75
+ });
76
+ return this;
77
+ }
78
+ /**
79
+ * Execute all staged operations atomically.
80
+ * After commit() the batch is sealed — calling commit() again throws.
81
+ *
82
+ * @example
83
+ * await batch.commit();
84
+ */
85
+ async commit() {
86
+ this._assertNotCommitted();
87
+ this._committed = true;
88
+ if (this._ops.length === 0)
89
+ return;
90
+ await this.http.post("/batch", { operations: this._ops });
91
+ }
92
+ }
93
+ exports.WriteBatch = WriteBatch;
94
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/db/batch.ts"],"names":[],"mappings":";;;AA8BA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,UAAU;IAIrB,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;QAH5B,SAAI,GAAc,EAAE,CAAC;QAC9B,eAAU,GAAG,KAAK,CAAC;IAEqB,CAAC;IAEjD,0CAA0C;IAC1C,IAAI,IAAI,KAAa,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvC,mBAAmB;QACzB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,GAAG,CACD,GAA2C,EAC3C,IAAkD;QAElD,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACb,IAAI,EAAY,KAAK;YACrB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,EAAE,EAAc,GAAG,CAAC,EAAE;YACtB,IAAI,EAAY,IAA+B;YAC/C,KAAK,EAAW,KAAK;SACtB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,MAAM,CACJ,GAA2C,EAC3C,IAA2D;QAE3D,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACb,IAAI,EAAY,QAAQ;YACxB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,EAAE,EAAc,GAAG,CAAC,EAAE;YACtB,IAAI,EAAY,IAA+B;YAC/C,KAAK,EAAW,IAAI;SACrB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,GAA2C;QAChD,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACb,IAAI,EAAY,QAAQ;YACxB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,EAAE,EAAc,GAAG,CAAC,EAAE;SACvB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM;QACV,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEnC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF;AAnFD,gCAmFC"}
@@ -1,6 +1,10 @@
1
1
  import { HttpClient } from "../http";
2
+ import { WriteBatch } from "./batch";
3
+ import { Transaction } from "./transaction";
2
4
  import type { ClefbaseDocument, QueryResult, WhereClause } from "../types";
3
5
  export type { WhereClause, WhereValue } from "../types";
6
+ export { WriteBatch } from "./batch";
7
+ export { Transaction, runTransaction } from "./transaction";
4
8
  /**
5
9
  * A typed reference to a single document.
6
10
  *
@@ -16,11 +20,14 @@ export declare class DocumentReference<T extends ClefbaseDocument = ClefbaseDocu
16
20
  readonly collectionPath: string;
17
21
  readonly id: string;
18
22
  constructor(http: HttpClient, collectionPath: string, id: string);
23
+ /** Fully-qualified path string, e.g. "posts/p1" or "posts/p1/comments/c1". */
24
+ get path(): string;
19
25
  /** Fetch this document. Returns null when it does not exist. */
20
26
  get(): Promise<T | null>;
21
27
  /**
22
28
  * Patch this document (merge by default).
23
29
  * Pass `{ merge: false }` to fully replace the document.
30
+ * Supports FieldValue sentinels — they are serialized by JSON.stringify.
24
31
  */
25
32
  update(data: Partial<Omit<T, "_id" | "_createdAt" | "_updatedAt">>, opts?: {
26
33
  merge?: boolean;
@@ -39,6 +46,20 @@ export declare class DocumentReference<T extends ClefbaseDocument = ClefbaseDocu
39
46
  collection<S extends ClefbaseDocument = ClefbaseDocument>(name: string): CollectionReference<S>;
40
47
  /** @deprecated Use .collection() — kept for backwards compat */
41
48
  subcollection<S extends ClefbaseDocument = ClefbaseDocument>(name: string): CollectionReference<S>;
49
+ /**
50
+ * Subscribe to real-time updates for this document.
51
+ * Returns an unsubscribe function.
52
+ * Requires the server to support SSE at GET /<collection>/<id>/stream.
53
+ *
54
+ * @example
55
+ * const unsub = ref.onSnapshot((doc) => {
56
+ * if (doc) console.log("Updated:", doc);
57
+ * else console.log("Deleted");
58
+ * });
59
+ * // later:
60
+ * unsub();
61
+ */
62
+ onSnapshot(callback: (doc: T | null) => void, onError?: (err: Error) => void): () => void;
42
63
  }
43
64
  /**
44
65
  * A chainable query builder.
@@ -65,9 +86,10 @@ export declare class Query<T extends ClefbaseDocument = ClefbaseDocument> {
65
86
  /**
66
87
  * Filter by field values or operators.
67
88
  * Multiple calls are AND-merged.
89
+ * Supports dot-notation for nested fields: `where({ "address.city": "London" })`
68
90
  */
69
91
  where(clauses: WhereClause): this;
70
- /** Sort by a field. */
92
+ /** Sort by a field. Supports dot-notation: `orderBy("meta.score", "desc")` */
71
93
  orderBy(field: string, dir?: "asc" | "desc"): this;
72
94
  /** Cap results (server max: 500). */
73
95
  limit(n: number): this;
@@ -82,6 +104,36 @@ export declare class Query<T extends ClefbaseDocument = ClefbaseDocument> {
82
104
  get(): Promise<T[]>;
83
105
  /** @alias get() */
84
106
  getDocs(): Promise<T[]>;
107
+ /**
108
+ * Count matching documents without fetching their data.
109
+ *
110
+ * @example
111
+ * const total = await db.collection("orders").where({ status: "pending" }).count();
112
+ */
113
+ count(): Promise<number>;
114
+ /**
115
+ * Fetch a single matching document (first result).
116
+ * Returns null when no document matches.
117
+ *
118
+ * @example
119
+ * const admin = await db.collection("users").where({ role: "admin" }).findOne();
120
+ */
121
+ findOne(): Promise<T | null>;
122
+ /**
123
+ * Iterate over all matching documents in pages, calling `callback` for
124
+ * each page. Useful for large datasets you don't want to load at once.
125
+ *
126
+ * @example
127
+ * await db.collection("logs")
128
+ * .where({ level: "error" })
129
+ * .orderBy("_createdAt")
130
+ * .forEach(async (page) => {
131
+ * for (const doc of page) await process(doc);
132
+ * }, { pageSize: 100 });
133
+ */
134
+ forEach(callback: (docs: T[]) => Promise<void> | void, opts?: {
135
+ pageSize?: number;
136
+ }): Promise<void>;
85
137
  }
86
138
  /**
87
139
  * A reference to a collection (or subcollection path).
@@ -107,23 +159,90 @@ export declare class CollectionReference<T extends ClefbaseDocument = ClefbaseDo
107
159
  offset?: number;
108
160
  }): Promise<QueryResult<T>>;
109
161
  }
162
+ /**
163
+ * Query across ALL collections (and subcollections) that share the same name.
164
+ *
165
+ * @example
166
+ * // Find all comments across every post
167
+ * const allComments = await db
168
+ * .collectionGroup("comments")
169
+ * .where({ approved: true })
170
+ * .orderBy("_createdAt", "desc")
171
+ * .limit(50)
172
+ * .getDocs();
173
+ */
174
+ export declare class CollectionGroup<T extends ClefbaseDocument = ClefbaseDocument> extends Query<T> {
175
+ constructor(http: HttpClient, collectionId: string);
176
+ }
110
177
  /**
111
178
  * Top-level database service. Obtain via `getDatabase(app)`.
112
179
  *
113
180
  * @example
114
181
  * const db = getDatabase(app);
182
+ *
183
+ * // Document reads / writes
115
184
  * const post = await db.collection("posts").doc("p1").get();
116
- * const user = await db.getDoc("users", "uid-123");
185
+ * await db.collection("posts").doc("p1").update({ views: FieldValue.increment(1) });
186
+ *
187
+ * // Atomic batch write
188
+ * const batch = db.batch();
189
+ * batch.update(db.collection("counters").doc("hits"), { n: FieldValue.increment(1) });
190
+ * batch.delete(db.collection("sessions").doc("expired-id"));
191
+ * await batch.commit();
192
+ *
193
+ * // Transaction (read-then-write)
194
+ * await db.runTransaction(async (tx) => {
195
+ * const doc = await tx.get(db.collection("wallets").doc(id));
196
+ * tx.update(db.collection("wallets").doc(id), { balance: (doc?.balance as number ?? 0) + 10 });
197
+ * });
117
198
  */
118
199
  export declare class Database {
119
200
  private readonly http;
120
201
  constructor(http: HttpClient);
121
202
  collection<T extends ClefbaseDocument = ClefbaseDocument>(name: string): CollectionReference<T>;
203
+ /**
204
+ * Query across ALL collections that share `collectionId`, regardless of
205
+ * where they are nested in the document tree.
206
+ *
207
+ * @example
208
+ * const allLikes = await db.collectionGroup("likes").where({ userId: uid }).getDocs();
209
+ */
210
+ collectionGroup<T extends ClefbaseDocument = ClefbaseDocument>(collectionId: string): CollectionGroup<T>;
122
211
  getDoc<T extends ClefbaseDocument = ClefbaseDocument>(collectionName: string, id: string): Promise<T | null>;
123
212
  addDoc<T extends ClefbaseDocument = ClefbaseDocument>(collectionName: string, data: Omit<T, "_id" | "_createdAt" | "_updatedAt">): Promise<T>;
124
213
  updateDoc<T extends ClefbaseDocument = ClefbaseDocument>(collectionName: string, id: string, data: Partial<Omit<T, "_id" | "_createdAt" | "_updatedAt">>, opts?: {
125
214
  merge?: boolean;
126
215
  }): Promise<T>;
127
216
  deleteDoc(collectionName: string, id: string): Promise<void>;
217
+ /**
218
+ * Fetch a document by its full slash-separated path string.
219
+ *
220
+ * @example
221
+ * const comment = await db.doc("posts/p1/comments/c1");
222
+ */
223
+ doc<T extends ClefbaseDocument = ClefbaseDocument>(path: string): Promise<T | null>;
224
+ /**
225
+ * Create an atomic WriteBatch. Stage operations with `batch.set()`,
226
+ * `batch.update()`, `batch.delete()`, then call `batch.commit()`.
227
+ *
228
+ * @example
229
+ * const batch = db.batch();
230
+ * batch.set(db.collection("users").doc("u1"), { name: "Alice" });
231
+ * batch.update(db.collection("counters").doc("users"), { total: FieldValue.increment(1) });
232
+ * await batch.commit();
233
+ */
234
+ batch(): WriteBatch;
235
+ /**
236
+ * Execute a transaction — reads are consistent, writes are atomic.
237
+ *
238
+ * @example
239
+ * await db.runTransaction(async (tx) => {
240
+ * const wallet = await tx.get(db.collection("wallets").doc(userId));
241
+ * if ((wallet?.credits as number ?? 0) < cost) throw new Error("Insufficient credits");
242
+ * tx.update(db.collection("wallets").doc(userId), { credits: (wallet!.credits as number) - cost });
243
+ * tx.update(db.collection("items").doc(itemId), { ownerId: userId });
244
+ * });
245
+ */
246
+ runTransaction<T = void>(updateFn: (tx: Transaction) => Promise<T>): Promise<T>;
128
247
  }
129
248
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
package/dist/db/index.js CHANGED
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Database = exports.CollectionReference = exports.Query = exports.DocumentReference = void 0;
3
+ exports.Database = exports.CollectionGroup = exports.CollectionReference = exports.Query = exports.DocumentReference = exports.runTransaction = exports.Transaction = exports.WriteBatch = void 0;
4
+ const batch_1 = require("./batch");
5
+ const transaction_1 = require("./transaction");
6
+ var batch_2 = require("./batch");
7
+ Object.defineProperty(exports, "WriteBatch", { enumerable: true, get: function () { return batch_2.WriteBatch; } });
8
+ var transaction_2 = require("./transaction");
9
+ Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return transaction_2.Transaction; } });
10
+ Object.defineProperty(exports, "runTransaction", { enumerable: true, get: function () { return transaction_2.runTransaction; } });
4
11
  // ─── DocumentReference ────────────────────────────────────────────────────────
5
12
  /**
6
13
  * A typed reference to a single document.
@@ -18,6 +25,10 @@ class DocumentReference {
18
25
  this.collectionPath = collectionPath;
19
26
  this.id = id;
20
27
  }
28
+ /** Fully-qualified path string, e.g. "posts/p1" or "posts/p1/comments/c1". */
29
+ get path() {
30
+ return `${this.collectionPath}/${this.id}`;
31
+ }
21
32
  /** Fetch this document. Returns null when it does not exist. */
22
33
  async get() {
23
34
  try {
@@ -32,6 +43,7 @@ class DocumentReference {
32
43
  /**
33
44
  * Patch this document (merge by default).
34
45
  * Pass `{ merge: false }` to fully replace the document.
46
+ * Supports FieldValue sentinels — they are serialized by JSON.stringify.
35
47
  */
36
48
  async update(data, opts) {
37
49
  const merge = opts?.merge ?? true;
@@ -59,6 +71,36 @@ class DocumentReference {
59
71
  subcollection(name) {
60
72
  return this.collection(name);
61
73
  }
74
+ /**
75
+ * Subscribe to real-time updates for this document.
76
+ * Returns an unsubscribe function.
77
+ * Requires the server to support SSE at GET /<collection>/<id>/stream.
78
+ *
79
+ * @example
80
+ * const unsub = ref.onSnapshot((doc) => {
81
+ * if (doc) console.log("Updated:", doc);
82
+ * else console.log("Deleted");
83
+ * });
84
+ * // later:
85
+ * unsub();
86
+ */
87
+ onSnapshot(callback, onError) {
88
+ const url = `${this.http.getBaseUrl()}/${this.collectionPath}/${this.id}/stream`;
89
+ const es = new globalThis.EventSource(url);
90
+ es.onmessage = (event) => {
91
+ try {
92
+ const data = JSON.parse(event.data);
93
+ callback(data);
94
+ }
95
+ catch (err) {
96
+ onError?.(err);
97
+ }
98
+ };
99
+ es.onerror = () => {
100
+ onError?.(new Error("DocumentReference.onSnapshot: SSE connection error"));
101
+ };
102
+ return () => es.close();
103
+ }
62
104
  }
63
105
  exports.DocumentReference = DocumentReference;
64
106
  // ─── Query ────────────────────────────────────────────────────────────────────
@@ -84,12 +126,13 @@ class Query {
84
126
  /**
85
127
  * Filter by field values or operators.
86
128
  * Multiple calls are AND-merged.
129
+ * Supports dot-notation for nested fields: `where({ "address.city": "London" })`
87
130
  */
88
131
  where(clauses) {
89
132
  this._filter = { ...this._filter, ...clauses };
90
133
  return this;
91
134
  }
92
- /** Sort by a field. */
135
+ /** Sort by a field. Supports dot-notation: `orderBy("meta.score", "desc")` */
93
136
  orderBy(field, dir = "asc") {
94
137
  this._sort = { field, dir };
95
138
  return this;
@@ -125,6 +168,69 @@ class Query {
125
168
  async getDocs() {
126
169
  return this.get();
127
170
  }
171
+ /**
172
+ * Count matching documents without fetching their data.
173
+ *
174
+ * @example
175
+ * const total = await db.collection("orders").where({ status: "pending" }).count();
176
+ */
177
+ async count() {
178
+ const body = {
179
+ filter: Object.keys(this._filter).length > 0 ? this._filter : undefined,
180
+ limit: 500,
181
+ offset: 0,
182
+ };
183
+ const result = await this.http.post(`/${this.path}/count`, body);
184
+ // Fallback: if server doesn't have /count, use the total from /query
185
+ if ("count" in result)
186
+ return result.count;
187
+ return result.total;
188
+ }
189
+ /**
190
+ * Fetch a single matching document (first result).
191
+ * Returns null when no document matches.
192
+ *
193
+ * @example
194
+ * const admin = await db.collection("users").where({ role: "admin" }).findOne();
195
+ */
196
+ async findOne() {
197
+ const prev = this._limit;
198
+ this._limit = 1;
199
+ const docs = await this.get();
200
+ this._limit = prev;
201
+ return docs[0] ?? null;
202
+ }
203
+ /**
204
+ * Iterate over all matching documents in pages, calling `callback` for
205
+ * each page. Useful for large datasets you don't want to load at once.
206
+ *
207
+ * @example
208
+ * await db.collection("logs")
209
+ * .where({ level: "error" })
210
+ * .orderBy("_createdAt")
211
+ * .forEach(async (page) => {
212
+ * for (const doc of page) await process(doc);
213
+ * }, { pageSize: 100 });
214
+ */
215
+ async forEach(callback, opts) {
216
+ const pageSize = opts?.pageSize ?? 100;
217
+ let offset = 0;
218
+ while (true) {
219
+ const body = {
220
+ filter: Object.keys(this._filter).length > 0 ? this._filter : undefined,
221
+ sort: this._sort,
222
+ limit: pageSize,
223
+ offset,
224
+ };
225
+ const result = await this.http.post(`/${this.path}/query`, body);
226
+ if (result.data.length === 0)
227
+ break;
228
+ await callback(result.data);
229
+ offset += result.data.length;
230
+ if (result.data.length < pageSize)
231
+ break;
232
+ }
233
+ }
128
234
  }
129
235
  exports.Query = Query;
130
236
  // ─── CollectionReference ──────────────────────────────────────────────────────
@@ -161,22 +267,68 @@ class CollectionReference extends Query {
161
267
  }
162
268
  }
163
269
  exports.CollectionReference = CollectionReference;
270
+ // ─── CollectionGroup ──────────────────────────────────────────────────────────
271
+ /**
272
+ * Query across ALL collections (and subcollections) that share the same name.
273
+ *
274
+ * @example
275
+ * // Find all comments across every post
276
+ * const allComments = await db
277
+ * .collectionGroup("comments")
278
+ * .where({ approved: true })
279
+ * .orderBy("_createdAt", "desc")
280
+ * .limit(50)
281
+ * .getDocs();
282
+ */
283
+ class CollectionGroup extends Query {
284
+ constructor(http, collectionId) {
285
+ // The server exposes collection-group queries at a special path
286
+ super(http, `__group__/${collectionId}`);
287
+ }
288
+ }
289
+ exports.CollectionGroup = CollectionGroup;
164
290
  // ─── Database ─────────────────────────────────────────────────────────────────
165
291
  /**
166
292
  * Top-level database service. Obtain via `getDatabase(app)`.
167
293
  *
168
294
  * @example
169
295
  * const db = getDatabase(app);
296
+ *
297
+ * // Document reads / writes
170
298
  * const post = await db.collection("posts").doc("p1").get();
171
- * const user = await db.getDoc("users", "uid-123");
299
+ * await db.collection("posts").doc("p1").update({ views: FieldValue.increment(1) });
300
+ *
301
+ * // Atomic batch write
302
+ * const batch = db.batch();
303
+ * batch.update(db.collection("counters").doc("hits"), { n: FieldValue.increment(1) });
304
+ * batch.delete(db.collection("sessions").doc("expired-id"));
305
+ * await batch.commit();
306
+ *
307
+ * // Transaction (read-then-write)
308
+ * await db.runTransaction(async (tx) => {
309
+ * const doc = await tx.get(db.collection("wallets").doc(id));
310
+ * tx.update(db.collection("wallets").doc(id), { balance: (doc?.balance as number ?? 0) + 10 });
311
+ * });
172
312
  */
173
313
  class Database {
174
314
  constructor(http) {
175
315
  this.http = http;
176
316
  }
317
+ // ─── Collection / document accessors ───────────────────────────────────────
177
318
  collection(name) {
178
319
  return new CollectionReference(this.http, name);
179
320
  }
321
+ /**
322
+ * Query across ALL collections that share `collectionId`, regardless of
323
+ * where they are nested in the document tree.
324
+ *
325
+ * @example
326
+ * const allLikes = await db.collectionGroup("likes").where({ userId: uid }).getDocs();
327
+ */
328
+ collectionGroup(collectionId) {
329
+ return new CollectionGroup(this.http, collectionId);
330
+ }
331
+ // ─── Convenience document helpers ──────────────────────────────────────────
180
332
  async getDoc(collectionName, id) {
181
333
  return this.collection(collectionName).doc(id).get();
182
334
  }
@@ -189,6 +341,49 @@ class Database {
189
341
  async deleteDoc(collectionName, id) {
190
342
  return this.collection(collectionName).doc(id).delete();
191
343
  }
344
+ /**
345
+ * Fetch a document by its full slash-separated path string.
346
+ *
347
+ * @example
348
+ * const comment = await db.doc("posts/p1/comments/c1");
349
+ */
350
+ async doc(path) {
351
+ const parts = path.split("/").filter(Boolean);
352
+ if (parts.length < 2 || parts.length % 2 !== 0) {
353
+ throw new Error(`db.doc(): path must have an even number of segments (collection/id), got "${path}"`);
354
+ }
355
+ const id = parts.pop();
356
+ const collectionPath = parts.join("/");
357
+ return new DocumentReference(this.http, collectionPath, id).get();
358
+ }
359
+ // ─── Atomic writes ─────────────────────────────────────────────────────────
360
+ /**
361
+ * Create an atomic WriteBatch. Stage operations with `batch.set()`,
362
+ * `batch.update()`, `batch.delete()`, then call `batch.commit()`.
363
+ *
364
+ * @example
365
+ * const batch = db.batch();
366
+ * batch.set(db.collection("users").doc("u1"), { name: "Alice" });
367
+ * batch.update(db.collection("counters").doc("users"), { total: FieldValue.increment(1) });
368
+ * await batch.commit();
369
+ */
370
+ batch() {
371
+ return new batch_1.WriteBatch(this.http);
372
+ }
373
+ /**
374
+ * Execute a transaction — reads are consistent, writes are atomic.
375
+ *
376
+ * @example
377
+ * await db.runTransaction(async (tx) => {
378
+ * const wallet = await tx.get(db.collection("wallets").doc(userId));
379
+ * if ((wallet?.credits as number ?? 0) < cost) throw new Error("Insufficient credits");
380
+ * tx.update(db.collection("wallets").doc(userId), { credits: (wallet!.credits as number) - cost });
381
+ * tx.update(db.collection("items").doc(itemId), { ownerId: userId });
382
+ * });
383
+ */
384
+ async runTransaction(updateFn) {
385
+ return (0, transaction_1.runTransaction)(this.http, updateFn);
386
+ }
192
387
  }
193
388
  exports.Database = Database;
194
389
  //# sourceMappingURL=index.js.map