clefbase 1.3.6 → 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/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
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":";;;AAUA,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,MAAa,iBAAiB;IAC5B,YACmB,IAAgB,EACjB,cAAsB,EACtB,EAAU;QAFT,SAAI,GAAJ,IAAI,CAAY;QACjB,mBAAc,GAAd,cAAc,CAAQ;QACtB,OAAE,GAAF,EAAE,CAAQ;IACzB,CAAC;IAEJ,gEAAgE;IAChE,KAAK,CAAC,GAAG;QACP,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAI,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,IAAK,GAA2B,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAC7D,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CACV,IAA2D,EAC3D,IAA0B;QAE1B,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAClB,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,UAAU,MAAM,CAAC,KAAK,CAAC,EAAE,EAC3D,IAAI,CACL,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,KAAK,CAAC,GAAG,CAAC,IAAkD;QAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAClB,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,cAAc,EAChD,IAAI,CACL,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CACR,IAAY;QAEZ,OAAO,IAAI,mBAAmB,CAC5B,IAAI,CAAC,IAAI,EACT,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,CAC5C,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,aAAa,CACX,IAAY;QAEZ,OAAO,IAAI,CAAC,UAAU,CAAI,IAAI,CAAC,CAAC;IAClC,CAAC;CACF;AAnED,8CAmEC;AAED,iFAAiF;AAEjF;;;;;;;;;;GAUG;AACH,MAAa,KAAK;IAMhB,YACqB,IAAgB,EAChB,IAAY;QADZ,SAAI,GAAJ,IAAI,CAAY;QAChB,SAAI,GAAJ,IAAI,CAAQ;QAPvB,YAAO,GAA4B,EAAE,CAAC;QAEtC,WAAM,GAAG,EAAE,CAAC;QACZ,YAAO,GAAG,CAAC,CAAC;IAKnB,CAAC;IAEJ;;;OAGG;IACH,KAAK,CAAC,OAAoB;QACxB,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAI,OAAmC,EAAE,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uBAAuB;IACvB,OAAO,CAAC,KAAa,EAAE,MAAsB,KAAK;QAChD,IAAI,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,CAAS;QACb,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6CAA6C;IAC7C,MAAM,CAAC,CAAS;QACd,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,GAAiB;YACzB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YACvE,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,MAAM,EAAE,IAAI,CAAC,OAAO;SACrB,CAAC;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAiB,IAAI,IAAI,CAAC,IAAI,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG;QACP,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC;IACnC,CAAC;IAED,mBAAmB;IACnB,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC;CACF;AA7DD,sBA6DC;AAED,iFAAiF;AAEjF;;;;;;;;GAQG;AACH,MAAa,mBAEX,SAAQ,KAAQ;IAChB,YAAY,IAAgB,EAAE,IAAY;QACxC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,kEAAkE;IAClE,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,iBAAiB,CAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,GAAG,CAAC,IAAkD;QAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAI,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,IAA0C;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;QACjC,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAiB,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF;AA3BD,kDA2BC;AAED,iFAAiF;AAEjF;;;;;;;GAOG;AACH,MAAa,QAAQ;IACnB,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,UAAU,CACR,IAAY;QAEZ,OAAO,IAAI,mBAAmB,CAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,MAAM,CACV,cAAsB,EACtB,EAAU;QAEV,OAAO,IAAI,CAAC,UAAU,CAAI,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,MAAM,CACV,cAAsB,EACtB,IAAkD;QAElD,OAAO,IAAI,CAAC,UAAU,CAAI,cAAc,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,SAAS,CACb,cAAsB,EACtB,EAAU,EACV,IAA2D,EAC3D,IAA0B;QAE1B,OAAO,IAAI,CAAC,UAAU,CAAI,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,cAAsB,EAAE,EAAU;QAChD,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1D,CAAC;CACF;AAnCD,4BAmCC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ import { HttpClient } from "../http";
2
+ import type { ClefbaseDocument } from "../types";
3
+ type TxWriteOp = {
4
+ type: "set" | "update" | "delete";
5
+ collectionPath: string;
6
+ id: string;
7
+ data?: Record<string, unknown>;
8
+ merge?: boolean;
9
+ };
10
+ /**
11
+ * Handle passed to your transaction callback.
12
+ * Accumulates reads and writes, then flushes them in a single atomic request.
13
+ */
14
+ export declare class Transaction {
15
+ private readonly http;
16
+ /** @internal */
17
+ readonly _reads: {
18
+ collectionPath: string;
19
+ id: string;
20
+ }[];
21
+ /** @internal */
22
+ readonly _writes: TxWriteOp[];
23
+ private _writesStarted;
24
+ constructor(http: HttpClient);
25
+ /**
26
+ * Read a document inside the transaction.
27
+ * Must be called before any write operation.
28
+ *
29
+ * @example
30
+ * const user = await tx.get(db.collection("users").doc("u1"));
31
+ */
32
+ get<T extends ClefbaseDocument>(ref: {
33
+ collectionPath: string;
34
+ id: string;
35
+ }): Promise<T | null>;
36
+ /**
37
+ * Stage a full overwrite inside the transaction.
38
+ *
39
+ * @example
40
+ * tx.set(db.collection("users").doc("u1"), { name: "Alice", role: "admin" });
41
+ */
42
+ set<T extends ClefbaseDocument>(ref: {
43
+ collectionPath: string;
44
+ id: string;
45
+ }, data: Omit<T, "_id" | "_createdAt" | "_updatedAt">): this;
46
+ /**
47
+ * Stage a merge-patch update inside the transaction.
48
+ * Supports FieldValue sentinels.
49
+ *
50
+ * @example
51
+ * tx.update(db.collection("posts").doc("p1"), { views: FieldValue.increment(1) });
52
+ */
53
+ update<T extends ClefbaseDocument>(ref: {
54
+ collectionPath: string;
55
+ id: string;
56
+ }, data: Partial<Omit<T, "_id" | "_createdAt" | "_updatedAt">>): this;
57
+ /**
58
+ * Stage a document deletion inside the transaction.
59
+ *
60
+ * @example
61
+ * tx.delete(db.collection("sessions").doc("s9"));
62
+ */
63
+ delete(ref: {
64
+ collectionPath: string;
65
+ id: string;
66
+ }): this;
67
+ }
68
+ /**
69
+ * Execute an atomic transaction.
70
+ *
71
+ * Your callback receives a `Transaction` handle. Call `tx.get()` to read
72
+ * documents, then `tx.set()` / `tx.update()` / `tx.delete()` to stage writes.
73
+ * The SDK sends all writes in one atomic request after your callback resolves.
74
+ *
75
+ * The callback may be retried on contention — keep it free of side effects.
76
+ *
77
+ * @example
78
+ * await db.runTransaction(async (tx) => {
79
+ * const counter = await tx.get(db.collection("stats").doc("global"));
80
+ * const current = (counter?.total as number) ?? 0;
81
+ * tx.update(db.collection("stats").doc("global"), { total: current + 1 });
82
+ * });
83
+ *
84
+ * @example
85
+ * // Transfer credits atomically
86
+ * await db.runTransaction(async (tx) => {
87
+ * const from = await tx.get(db.collection("wallets").doc(fromId));
88
+ * const to = await tx.get(db.collection("wallets").doc(toId));
89
+ * if (!from || (from.credits as number) < amount) throw new Error("Insufficient credits");
90
+ * tx.update(db.collection("wallets").doc(fromId), { credits: (from.credits as number) - amount });
91
+ * tx.update(db.collection("wallets").doc(toId), { credits: ((to?.credits as number) ?? 0) + amount });
92
+ * });
93
+ */
94
+ export declare function runTransaction<T = void>(http: HttpClient, updateFn: (tx: Transaction) => Promise<T>): Promise<T>;
95
+ export {};
96
+ //# sourceMappingURL=transaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/db/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAsBjD,KAAK,SAAS,GAAG;IACf,IAAI,EAAY,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAc,MAAM,CAAC;IACvB,IAAI,CAAC,EAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,KAAK,CAAC,EAAU,OAAO,CAAC;CACzB,CAAC;AAEF;;;GAGG;AACH,qBAAa,WAAW;IAQV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAPjC,gBAAgB;IAChB,QAAQ,CAAC,MAAM,EAAG;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAChE,gBAAgB;IAChB,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,CAAM;IAEnC,OAAO,CAAC,cAAc,CAAS;gBAEF,IAAI,EAAE,UAAU;IAE7C;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,SAAS,gBAAgB,EAClC,GAAG,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAC1C,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAgBpB;;;;;OAKG;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;;;;;;OAMG;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;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAS1D;AAID;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,IAAI,EAC3C,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAaZ"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Transaction = void 0;
4
+ exports.runTransaction = runTransaction;
5
+ /**
6
+ * Handle passed to your transaction callback.
7
+ * Accumulates reads and writes, then flushes them in a single atomic request.
8
+ */
9
+ class Transaction {
10
+ constructor(http) {
11
+ this.http = http;
12
+ /** @internal */
13
+ this._reads = [];
14
+ /** @internal */
15
+ this._writes = [];
16
+ this._writesStarted = false;
17
+ }
18
+ /**
19
+ * Read a document inside the transaction.
20
+ * Must be called before any write operation.
21
+ *
22
+ * @example
23
+ * const user = await tx.get(db.collection("users").doc("u1"));
24
+ */
25
+ async get(ref) {
26
+ if (this._writesStarted) {
27
+ throw new Error("Transaction: all tx.get() calls must come before any write (set/update/delete).");
28
+ }
29
+ this._reads.push({ collectionPath: ref.collectionPath, id: ref.id });
30
+ try {
31
+ return await this.http.get(`/${ref.collectionPath}/${ref.id}`);
32
+ }
33
+ catch (err) {
34
+ if (err.status === 404)
35
+ return null;
36
+ throw err;
37
+ }
38
+ }
39
+ /**
40
+ * Stage a full overwrite inside the transaction.
41
+ *
42
+ * @example
43
+ * tx.set(db.collection("users").doc("u1"), { name: "Alice", role: "admin" });
44
+ */
45
+ set(ref, data) {
46
+ this._writesStarted = true;
47
+ this._writes.push({
48
+ type: "set",
49
+ collectionPath: ref.collectionPath,
50
+ id: ref.id,
51
+ data: data,
52
+ merge: false,
53
+ });
54
+ return this;
55
+ }
56
+ /**
57
+ * Stage a merge-patch update inside the transaction.
58
+ * Supports FieldValue sentinels.
59
+ *
60
+ * @example
61
+ * tx.update(db.collection("posts").doc("p1"), { views: FieldValue.increment(1) });
62
+ */
63
+ update(ref, data) {
64
+ this._writesStarted = true;
65
+ this._writes.push({
66
+ type: "update",
67
+ collectionPath: ref.collectionPath,
68
+ id: ref.id,
69
+ data: data,
70
+ merge: true,
71
+ });
72
+ return this;
73
+ }
74
+ /**
75
+ * Stage a document deletion inside the transaction.
76
+ *
77
+ * @example
78
+ * tx.delete(db.collection("sessions").doc("s9"));
79
+ */
80
+ delete(ref) {
81
+ this._writesStarted = true;
82
+ this._writes.push({
83
+ type: "delete",
84
+ collectionPath: ref.collectionPath,
85
+ id: ref.id,
86
+ });
87
+ return this;
88
+ }
89
+ }
90
+ exports.Transaction = Transaction;
91
+ // ─── runTransaction ───────────────────────────────────────────────────────────
92
+ /**
93
+ * Execute an atomic transaction.
94
+ *
95
+ * Your callback receives a `Transaction` handle. Call `tx.get()` to read
96
+ * documents, then `tx.set()` / `tx.update()` / `tx.delete()` to stage writes.
97
+ * The SDK sends all writes in one atomic request after your callback resolves.
98
+ *
99
+ * The callback may be retried on contention — keep it free of side effects.
100
+ *
101
+ * @example
102
+ * await db.runTransaction(async (tx) => {
103
+ * const counter = await tx.get(db.collection("stats").doc("global"));
104
+ * const current = (counter?.total as number) ?? 0;
105
+ * tx.update(db.collection("stats").doc("global"), { total: current + 1 });
106
+ * });
107
+ *
108
+ * @example
109
+ * // Transfer credits atomically
110
+ * await db.runTransaction(async (tx) => {
111
+ * const from = await tx.get(db.collection("wallets").doc(fromId));
112
+ * const to = await tx.get(db.collection("wallets").doc(toId));
113
+ * if (!from || (from.credits as number) < amount) throw new Error("Insufficient credits");
114
+ * tx.update(db.collection("wallets").doc(fromId), { credits: (from.credits as number) - amount });
115
+ * tx.update(db.collection("wallets").doc(toId), { credits: ((to?.credits as number) ?? 0) + amount });
116
+ * });
117
+ */
118
+ async function runTransaction(http, updateFn) {
119
+ const tx = new Transaction(http);
120
+ const result = await updateFn(tx);
121
+ // Flush all writes atomically (reads already happened inline above)
122
+ if (tx._writes.length > 0) {
123
+ await http.post("/transaction", {
124
+ reads: tx._reads,
125
+ writes: tx._writes,
126
+ });
127
+ }
128
+ return result;
129
+ }
130
+ //# sourceMappingURL=transaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/db/transaction.ts"],"names":[],"mappings":";;;AA8JA,wCAgBC;AA/ID;;;GAGG;AACH,MAAa,WAAW;IAQtB,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;QAP7C,gBAAgB;QACP,WAAM,GAA8C,EAAE,CAAC;QAChE,gBAAgB;QACP,YAAO,GAAgB,EAAE,CAAC;QAE3B,mBAAc,GAAG,KAAK,CAAC;IAEiB,CAAC;IAEjD;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CACP,GAA2C;QAE3C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAErE,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAI,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,IAAK,GAA2B,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAC7D,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,GAAG,CACD,GAA2C,EAC3C,IAAkD;QAElD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAChB,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;;;;;;OAMG;IACH,MAAM,CACJ,GAA2C,EAC3C,IAA2D;QAE3D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAChB,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;;;;;OAKG;IACH,MAAM,CAAC,GAA2C;QAChD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAChB,IAAI,EAAY,QAAQ;YACxB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,EAAE,EAAc,GAAG,CAAC,EAAE;SACvB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA7FD,kCA6FC;AAED,iFAAiF;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACI,KAAK,UAAU,cAAc,CAClC,IAAgB,EAChB,QAAyC;IAEzC,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,CAAC;IAElC,oEAAoE;IACpE,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YAC9B,KAAK,EAAG,EAAE,CAAC,MAAM;YACjB,MAAM,EAAE,EAAE,CAAC,OAAO;SACnB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,93 @@
1
+ export type FieldValueType = "increment" | "decrement" | "serverTimestamp" | "delete" | "arrayUnion" | "arrayRemove";
2
+ /**
3
+ * Opaque sentinel returned by every FieldValue factory.
4
+ * Never construct this directly — use the static helpers on FieldValue.
5
+ */
6
+ export declare class FieldValueSentinel {
7
+ readonly _type: FieldValueType;
8
+ readonly _value?: number | unknown[] | undefined;
9
+ /** @internal discriminator so library code can detect sentinels */
10
+ readonly __fieldValue: true;
11
+ /** @internal */
12
+ constructor(_type: FieldValueType, _value?: number | unknown[] | undefined);
13
+ /**
14
+ * Serialize to the wire format the Clefbase server expects.
15
+ * Called automatically by JSON.stringify.
16
+ */
17
+ toJSON(): object;
18
+ toString(): string;
19
+ }
20
+ /**
21
+ * Atomic field-level sentinels for database writes.
22
+ *
23
+ * @example
24
+ * import { FieldValue } from "clefbase";
25
+ *
26
+ * await db.collection("posts").doc("p1").update({
27
+ * views: FieldValue.increment(1),
28
+ * score: FieldValue.decrement(0.5),
29
+ * publishedAt: FieldValue.serverTimestamp(),
30
+ * draftField: FieldValue.deleteField(),
31
+ * tags: FieldValue.arrayUnion("featured", "trending"),
32
+ * oldTags: FieldValue.arrayRemove("draft"),
33
+ * });
34
+ */
35
+ export declare const FieldValue: {
36
+ /**
37
+ * Atomically increment a numeric field by `delta` (default 1).
38
+ * Creates the field with value `delta` if it does not yet exist.
39
+ *
40
+ * @example
41
+ * await ref.update({ views: FieldValue.increment(1) });
42
+ * await ref.update({ balance: FieldValue.increment(9.99) });
43
+ */
44
+ readonly increment: (delta?: number) => FieldValueSentinel;
45
+ /**
46
+ * Atomically decrement a numeric field by `delta` (default 1).
47
+ * Sugar for increment(-delta).
48
+ *
49
+ * @example
50
+ * await ref.update({ lives: FieldValue.decrement(1) });
51
+ */
52
+ readonly decrement: (delta?: number) => FieldValueSentinel;
53
+ /**
54
+ * Set the field to the server's current timestamp (ISO 8601 string).
55
+ * Avoids clock-skew issues by using the server clock instead of the client.
56
+ *
57
+ * @example
58
+ * await ref.update({ lastSeen: FieldValue.serverTimestamp() });
59
+ */
60
+ readonly serverTimestamp: () => FieldValueSentinel;
61
+ /**
62
+ * Remove this field from the document entirely.
63
+ * Only valid inside `.update()` — not `.set()`.
64
+ *
65
+ * @example
66
+ * await ref.update({ tempToken: FieldValue.deleteField() });
67
+ */
68
+ readonly deleteField: () => FieldValueSentinel;
69
+ /**
70
+ * Add one or more items to an array field, ignoring duplicates.
71
+ * Creates the field as a new array if it does not yet exist.
72
+ *
73
+ * @example
74
+ * await ref.update({ roles: FieldValue.arrayUnion("editor", "moderator") });
75
+ */
76
+ readonly arrayUnion: (...items: unknown[]) => FieldValueSentinel;
77
+ /**
78
+ * Remove one or more items from an array field (all matching occurrences).
79
+ * No-ops silently if the item or field does not exist.
80
+ *
81
+ * @example
82
+ * await ref.update({ roles: FieldValue.arrayRemove("moderator") });
83
+ */
84
+ readonly arrayRemove: (...items: unknown[]) => FieldValueSentinel;
85
+ /**
86
+ * Type-guard — returns true if `value` is any FieldValue sentinel.
87
+ *
88
+ * @example
89
+ * if (FieldValue.isSentinel(val)) console.log(val._type);
90
+ */
91
+ readonly isSentinel: (value: unknown) => value is FieldValueSentinel;
92
+ };
93
+ //# sourceMappingURL=field_value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field_value.d.ts","sourceRoot":"","sources":["../src/field_value.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,WAAW,GACX,iBAAiB,GACjB,QAAQ,GACR,YAAY,GACZ,aAAa,CAAC;AAElB;;;GAGG;AACH,qBAAa,kBAAkB;IAM3B,QAAQ,CAAC,KAAK,EAAE,cAAc;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE;IANtC,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAG,IAAI,CAAU;IAEtC,gBAAgB;gBAEL,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,YAAA;IAGtC;;;OAGG;IACH,MAAM,IAAI,MAAM;IAiBhB,QAAQ,IAAI,MAAM;CAGnB;AAID;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU;IACrB;;;;;;;OAOG;iCACc,MAAM,KAAO,kBAAkB;IAOhD;;;;;;OAMG;iCACc,MAAM,KAAO,kBAAkB;IAOhD;;;;;;OAMG;oCACgB,kBAAkB;IAIrC;;;;;;OAMG;gCACY,kBAAkB;IAIjC;;;;;;OAMG;oCACkB,OAAO,EAAE,KAAG,kBAAkB;IAOnD;;;;;;OAMG;qCACmB,OAAO,EAAE,KAAG,kBAAkB;IAOpD;;;;;OAKG;iCACe,OAAO,KAAG,KAAK,IAAI,kBAAkB;CAG/C,CAAC"}