@zuzjs/flare-admin 0.1.1

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,267 @@
1
+ # @zuzjs/flare-admin
2
+
3
+ > Server-side admin SDK for [FlareServer](https://www.zedgon.io) — the self-hosted Firebase alternative.
4
+ > Works like `firebase-admin`: runs **only on your backend**, never in a browser.
5
+
6
+ ---
7
+
8
+ ## How it works
9
+
10
+ ```
11
+ Your Express app HTTP REST FlareServer
12
+ ────────────────── ──────────► ─────────────────────
13
+ connectApp({ POST /admin/token Validates adminKey
14
+ serverUrl, { uid, role, claims } Signs JWT w/ jwtSecret
15
+ appId, ◄──────────────── Returns { token }
16
+ adminKey,
17
+ })
18
+
19
+ admin.auth()
20
+ .createCustomToken(uid)
21
+ → Promise<string> ──────────────────────► client: flare.auth(token)
22
+ socket elevated ✓
23
+ ```
24
+
25
+ **No MongoDB URI is ever shared.** The SDK talks to FlareServer's `/admin/token` REST endpoint using only the `adminKey`. This works identically whether you self-host Flare or use it as SaaS at `https://www.zedgon.io`.
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @zuzjs/flare-admin
33
+ # or
34
+ pnpm add @zuzjs/flare-admin
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Quick start
40
+
41
+ ### 1. Get your keys
42
+
43
+ ```bash
44
+ flare app create my-app
45
+ ```
46
+
47
+ This prints two configs:
48
+
49
+ | Config | Safe for... |
50
+ |---|---|
51
+ | `apiKey` | Browser / client-side |
52
+ | `adminKey` | Server-side only — never expose to browser |
53
+
54
+ ### 2. Set environment variables
55
+
56
+ ```bash
57
+ # .env (server-side only)
58
+ FLARE_URL=http://localhost:5050 # your FlareServer URL
59
+ FLARE_APP_ID=my-app
60
+ FLARE_ADMIN_KEY=FA_ADMIN_xxxxxxxxxxxx
61
+ ```
62
+
63
+ ### 3. Initialize once at boot
64
+
65
+ ```typescript
66
+ import { connectApp } from "@zuzjs/flare-admin";
67
+
68
+ const admin = connectApp({
69
+ serverUrl: process.env.FLARE_URL!,
70
+ appId: process.env.FLARE_APP_ID!,
71
+ adminKey: process.env.FLARE_ADMIN_KEY!,
72
+ });
73
+ ```
74
+
75
+ ### 4. Mint a token in your login route
76
+
77
+ ```typescript
78
+ import { getApp } from "@zuzjs/flare-admin";
79
+
80
+ app.post("/login", async (req, res) => {
81
+ // --- your existing auth logic ---
82
+ const user = await myAuthLogic(req.body);
83
+ if (!user) return res.status(401).json({ error: "invalid credentials" });
84
+
85
+ // Set your own session / cookie as normal
86
+ req.session.userId = user.id;
87
+
88
+ // --- the bridge ---
89
+ const flareToken = await getApp().auth().createCustomToken(user.id, {
90
+ role: user.isAdmin ? "admin" : "user",
91
+ claims: { email: user.email, plan: user.plan },
92
+ });
93
+
94
+ res.json({ user, flareToken });
95
+ });
96
+ ```
97
+
98
+ ### 5. Authenticate the Flare client
99
+
100
+ ```typescript
101
+ // Browser / React Native
102
+ import FlareClient from "@zuzjs/flare";
103
+
104
+ const flare = new FlareClient({
105
+ endpoint: "http://localhost:5050",
106
+ appId: "my-app",
107
+ apiKey: "FA_xxxxxxxx", // browser-safe key
108
+ });
109
+
110
+ flare.connect();
111
+
112
+ // After login:
113
+ const { flareToken } = await fetch("/login", { method: "POST", body: ... }).then(r => r.json());
114
+ await flare.auth(flareToken);
115
+ // ✅ Socket is now elevated — auth.uid and auth.role are set
116
+ ```
117
+
118
+ ---
119
+
120
+ ## API
121
+
122
+ ### `connectApp(config, name?)`
123
+
124
+ Initialize a FlareAdmin app. Idempotent — safe to call at module scope.
125
+
126
+ ```typescript
127
+ const admin = connectApp({
128
+ serverUrl: string; // FlareServer base URL
129
+ appId: string; // App ID from `flare app create`
130
+ adminKey: string; // Admin key — server-side only
131
+ defaultTtl?: string; // Default token TTL, e.g. "24h" (default)
132
+ });
133
+ ```
134
+
135
+ ### `getApp(name?)`
136
+
137
+ Retrieve an already-initialized app instance.
138
+
139
+ ### `auth(name?)`
140
+
141
+ Shorthand for `getApp(name).auth()`.
142
+
143
+ ### `admin.auth().createCustomToken(uid, opts?)`
144
+
145
+ Mint a custom auth token.
146
+
147
+ ```typescript
148
+ const token = await admin.auth().createCustomToken(uid, {
149
+ role?: "user" | "admin" | "anon", // default: "user"
150
+ claims?: Record<string, unknown>, // extra JWT payload fields
151
+ ttl?: string, // e.g. "1h", "7d"
152
+ });
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Security rules on the server
158
+
159
+ Once a client calls `flare.auth(token)`, the FlareServer socket has:
160
+
161
+ ```
162
+ auth.uid = the uid you passed to createCustomToken()
163
+ auth.role = "user" | "admin" | "anon"
164
+ ```
165
+
166
+ Use these in your security rules:
167
+
168
+ ```json
169
+ {
170
+ "users": { ".read": "auth != null", ".write": "auth.uid == $docId" },
171
+ "posts": { ".read": "true", ".write": "auth != null" },
172
+ "settings": { ".read": "auth != null", ".write": "auth.role == 'admin'" },
173
+ "*": { ".read": "false", ".write": "false" }
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Multi-tenant / multiple apps
180
+
181
+ ```typescript
182
+ const adminA = connectApp({ serverUrl, appId: "app-a", adminKey: "..." }, "a");
183
+ const adminB = connectApp({ serverUrl, appId: "app-b", adminKey: "..." }, "b");
184
+
185
+ const tokenA = await getApp("a").auth().createCustomToken(userId);
186
+ const tokenB = await getApp("b").auth().createCustomToken(userId);
187
+ ```
188
+
189
+ ## Admin-Only Auth Join Field Control
190
+
191
+ Auth-user joins in admin SDK default to full fields.
192
+
193
+ Use `allowSensitiveAuthUserFields(false)` per query when you want public-profile-only output:
194
+
195
+ ```typescript
196
+ const safeBoards = await admin.db()
197
+ .collection("boards")
198
+ .join("users", { source: "team.uid", target: "id", as: "team" })
199
+ .allowSensitiveAuthUserFields(false)
200
+ .get();
201
+ ```
202
+
203
+ Important:
204
+ - This option is admin-only.
205
+ - Normal client/system query paths cannot enable sensitive auth-user fields.
206
+
207
+ ---
208
+
209
+ ## Query Builder Parity (Admin)
210
+
211
+ `admin.db().collection(...)` and `admin.connection().collection(...)` are aligned with the client-style query builder API.
212
+
213
+ ### Supported filter helpers
214
+
215
+ `where`, `and`, `or`, `in`, `andIn`, `orIn`, `notIn`, `andNotIn`, `orNotIn`, `arrayContains`, `andArrayContains`, `orArrayContains`, `arrayContainsAny`, `andArrayContainsAny`, `orArrayContainsAny`, `some`, `andSome`, `orSome`, `like`, `andLike`, `orLike`, `notLike`, `andNotLike`, `orNotLike`, `exists`, `andExists`, `orExists`, `notExists`, `andNotExists`, `orNotExists`
216
+
217
+ ### Supported sort / cursor / aggregate helpers
218
+
219
+ `latest`, `newest`, `oldest`, `orderBy`, `limit`, `offset`, `startAt`, `startAfter`, `endAt`, `endBefore`, `count`, `sum`, `avg`, `min`, `max`, `distinct`, `groupBy`, `having`, `select`, `distinctField`, `vectorSearch`
220
+
221
+ ### Supported join helpers
222
+
223
+ `join`, `Join`, `joinNested`, `JoinNested`, `withRelation`
224
+
225
+ Example:
226
+
227
+ ```typescript
228
+ const rows = await admin.db()
229
+ .collection("boards")
230
+ .where({ uid: userId })
231
+ .orSome("team", { uid: userId })
232
+ .join("lists", { source: "id", target: "boardId", as: "lists" })
233
+ .join("users", { source: "team.uid", target: "id", as: "teamMembers" })
234
+ .joinNested("lists", "cards", { source: "id", target: "listId", as: "cards" })
235
+ .withRelation("team.uid->users.id as collaborators")
236
+ .orderBy("updatedAt", "desc")
237
+ .limit(20)
238
+ .get();
239
+ ```
240
+
241
+ ### Realtime parity
242
+
243
+ The same query builder surface is available on socket subscriptions:
244
+
245
+ ```typescript
246
+ const stop = admin.connection()
247
+ .collection("boards")
248
+ .where({ uid: userId })
249
+ .join("lists", { source: "id", target: "boardId", as: "lists" })
250
+ .onSnapshot((event) => {
251
+ console.log(event.type, event.data);
252
+ });
253
+ ```
254
+
255
+ ### Debugging structured query output
256
+
257
+ Both DB and realtime collection references provide `getRawQuery()`:
258
+
259
+ ```typescript
260
+ const raw = admin.db()
261
+ .collection("boards")
262
+ .where({ uid: userId })
263
+ .withRelation("team.uid->users.id as collaborators")
264
+ .getRawQuery();
265
+
266
+ console.log(raw.collection, raw.query);
267
+ ```
@@ -0,0 +1,92 @@
1
+ import { FlareAdminConfig, WhereCondition, HavingClause, JoinClause, AggregateSpec, VectorSearchClause, StructuredQuery } from "../types";
2
+ import { AdminDocumentReference } from "./Document";
3
+ export declare class AdminCollectionReference<T = Record<string, unknown>> {
4
+ private readonly cfg;
5
+ readonly name: string;
6
+ private sq;
7
+ private opts;
8
+ constructor(cfg: Required<FlareAdminConfig>, name: string);
9
+ private get baseUrl();
10
+ private get headers();
11
+ private clone;
12
+ allowSensitiveAuthUserFields(enabled?: boolean): AdminCollectionReference<T>;
13
+ private normalizeFilterValue;
14
+ private toQueryFilters;
15
+ private appendAndFilters;
16
+ private appendOrFilters;
17
+ private appendFilters;
18
+ private appendOperatorFilter;
19
+ where(condition: WhereCondition): AdminCollectionReference<T>;
20
+ and(condition: WhereCondition): AdminCollectionReference<T>;
21
+ or(condition: WhereCondition): AdminCollectionReference<T>;
22
+ in(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
23
+ andIn(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
24
+ orIn(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
25
+ notIn(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
26
+ andNotIn(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
27
+ orNotIn(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
28
+ arrayContains(field: string, value: unknown): AdminCollectionReference<T>;
29
+ andArrayContains(field: string, value: unknown): AdminCollectionReference<T>;
30
+ orArrayContains(field: string, value: unknown): AdminCollectionReference<T>;
31
+ arrayContainsAny(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
32
+ andArrayContainsAny(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
33
+ orArrayContainsAny(field: string, values: unknown[] | unknown): AdminCollectionReference<T>;
34
+ some(field: string, condition: Record<string, unknown>): AdminCollectionReference<T>;
35
+ andSome(field: string, condition: Record<string, unknown>): AdminCollectionReference<T>;
36
+ orSome(field: string, condition: Record<string, unknown>): AdminCollectionReference<T>;
37
+ like(field: string, value: string): AdminCollectionReference<T>;
38
+ andLike(field: string, value: string): AdminCollectionReference<T>;
39
+ orLike(field: string, value: string): AdminCollectionReference<T>;
40
+ notLike(field: string, value: string): AdminCollectionReference<T>;
41
+ andNotLike(field: string, value: string): AdminCollectionReference<T>;
42
+ orNotLike(field: string, value: string): AdminCollectionReference<T>;
43
+ exists(field: string): AdminCollectionReference<T>;
44
+ andExists(field: string): AdminCollectionReference<T>;
45
+ orExists(field: string): AdminCollectionReference<T>;
46
+ notExists(field: string): AdminCollectionReference<T>;
47
+ andNotExists(field: string): AdminCollectionReference<T>;
48
+ orNotExists(field: string): AdminCollectionReference<T>;
49
+ latest(): AdminCollectionReference<T>;
50
+ newest(): AdminCollectionReference<T>;
51
+ oldest(): AdminCollectionReference<T>;
52
+ orderBy(field: string, dir?: "asc" | "desc"): AdminCollectionReference<T>;
53
+ limit(n: number): AdminCollectionReference<T>;
54
+ offset(n: number): AdminCollectionReference<T>;
55
+ startAt(...values: unknown[]): AdminCollectionReference<T>;
56
+ startAfter(...values: unknown[]): AdminCollectionReference<T>;
57
+ endAt(...values: unknown[]): AdminCollectionReference<T>;
58
+ endBefore(...values: unknown[]): AdminCollectionReference<T>;
59
+ aggregate(...specs: AggregateSpec[]): AdminCollectionReference<T>;
60
+ count(alias?: string): AdminCollectionReference<T>;
61
+ sum(field: string, alias?: string): AdminCollectionReference<T>;
62
+ avg(field: string, alias?: string): AdminCollectionReference<T>;
63
+ min(field: string, alias?: string): AdminCollectionReference<T>;
64
+ max(field: string, alias?: string): AdminCollectionReference<T>;
65
+ distinct(field: string, alias?: string): AdminCollectionReference<T>;
66
+ groupBy(...fields: string[]): AdminCollectionReference<T>;
67
+ having(field: string, op: HavingClause["op"], value: number): AdminCollectionReference<T>;
68
+ private buildStructuredJoin;
69
+ private cloneStructuredJoin;
70
+ private appendNestedJoinByAlias;
71
+ private parseRelationRef;
72
+ join(collectionName: string, j: JoinClause): AdminCollectionReference<T>;
73
+ joinNested(parentAlias: string, collectionName: string, j: JoinClause): AdminCollectionReference<T>;
74
+ Join(collectionName: string, j: JoinClause): AdminCollectionReference<T>;
75
+ JoinNested(parentAlias: string, collectionName: string, j: JoinClause): AdminCollectionReference<T>;
76
+ withRelation(relation: string, options?: (Omit<JoinClause, "source" | "target" | "as"> & {
77
+ as?: string;
78
+ })): AdminCollectionReference<T>;
79
+ select(...fields: string[]): AdminCollectionReference<T>;
80
+ distinctField(field: string): AdminCollectionReference<T>;
81
+ vectorSearch(opts: VectorSearchClause): AdminCollectionReference<T>;
82
+ getRawQuery(): {
83
+ collection: string;
84
+ query: StructuredQuery;
85
+ };
86
+ get(): Promise<T[]>;
87
+ first(): Promise<T | null>;
88
+ last(): Promise<T | null>;
89
+ add(data: Partial<T>): Promise<AdminDocumentReference<T>>;
90
+ deleteMany(): Promise<number>;
91
+ doc(id: string): AdminDocumentReference<T>;
92
+ }
@@ -0,0 +1,27 @@
1
+ import { FlareAdminConfig } from "../types";
2
+ import { AdminCollectionReference } from "./Collection";
3
+ export declare class AdminDocumentReference<T = Record<string, unknown>> {
4
+ private readonly cfg;
5
+ readonly collection: string;
6
+ readonly id: string;
7
+ constructor(cfg: Required<FlareAdminConfig>, collection: string, id: string);
8
+ private get baseUrl();
9
+ private get headers();
10
+ private request;
11
+ /** Fetch this document. Returns `null` if it does not exist. */
12
+ get(): Promise<T | null>;
13
+ /**
14
+ * Replace (or create) this document entirely.
15
+ * All fields not in `data` are removed.
16
+ */
17
+ set(data: Partial<T>): Promise<void>;
18
+ /**
19
+ * Merge `data` into the existing document (upsert).
20
+ * Only the provided fields are changed.
21
+ */
22
+ update(data: Partial<T>): Promise<void>;
23
+ /** Delete this document. */
24
+ delete(): Promise<void>;
25
+ /** Return the parent collection reference. */
26
+ parent(): AdminCollectionReference<T>;
27
+ }
@@ -0,0 +1,22 @@
1
+ import { FlareAdminConfig, FlareAdminDb } from "../types";
2
+ import { AdminCollectionReference } from "./Collection";
3
+ export declare class FlareAdminDbService implements FlareAdminDb {
4
+ private readonly cfg;
5
+ constructor(cfg: Required<FlareAdminConfig>);
6
+ /**
7
+ * Reference a collection for one-shot queries and mutations.
8
+ *
9
+ * Supports the full StructuredQuery builder API:
10
+ * `where`, `and`, `or`, `orderBy`, `limit`, `offset`,
11
+ * `startAt/After`, `endAt/Before`, `count/sum/avg/min/max/distinct`,
12
+ * `groupBy`, `having`, `Join`, `select`, `distinctField`, `vectorSearch`.
13
+ *
14
+ * @example
15
+ * const users = await admin.db().collection<User>("users").get();
16
+ * const admins = await admin.db().collection("users")
17
+ * .where({ role: "admin" }).orderBy("name").get();
18
+ * const ref = await admin.db().collection("users").add({ name: "Alice" });
19
+ * await admin.db().collection("users").doc("alice").update({ plan: "pro" });
20
+ */
21
+ collection<T = Record<string, unknown>>(name: string): AdminCollectionReference<T>;
22
+ }
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var F=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var F__default=/*#__PURE__*/_interopDefault(F);/* @zuzjs/flare-admin */
2
+ function v(o){let e=[];for(let[n,r]of Object.entries(o))if(typeof r=="string"){let t=r.match(/^(>=|<=|!=|>|<|==)\s*(.+)$/);if(t){let[,i,s]=t;e.push({field:n,op:i,value:q(s.trim())});}else e.push({field:n,op:"==",value:r});}else Array.isArray(r)?e.push({field:n,op:"in",value:r}):e.push({field:n,op:"==",value:r});return e}function q(o){return isNaN(Number(o))?o==="true"?true:o==="false"?false:o==="null"?null:o:Number(o)}function k(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}var m=class{constructor(e,n,r){this.cfg=e;this.collection=n;this.id=r;}get baseUrl(){return `${this.cfg.serverUrl}/admin/db/${this.cfg.appId}/${this.collection}/${this.id}`}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}async request(e,n){let r;try{r=await fetch(this.baseUrl,{method:e,headers:this.headers,...n!==void 0?{body:JSON.stringify(n)}:{}});}catch(i){let s=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (${e} ${this.baseUrl}): ${s}`)}let t=await r.json().catch(()=>({}));if(!r.ok)throw new Error(`[flare-admin] ${e} ${this.baseUrl} failed (HTTP ${r.status}): `+(t.error??"Unknown error"));return t}async get(){let e;try{e=await fetch(this.baseUrl,{headers:this.headers});}catch(r){let t=r instanceof Error?r.message:String(r);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${t}`)}if(e.status===404)return null;let n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(`[flare-admin] GET ${this.baseUrl} failed (HTTP ${e.status}): `+(n.error??"Unknown error"));return n.data??null}async set(e){await this.request("PUT",e);}async update(e){await this.request("PATCH",e);}async delete(){await this.request("DELETE");}parent(){return new p(this.cfg,this.collection)}};var p=class o{constructor(e,n){this.cfg=e;this.name=n;this.sq={};this.opts={allowSensitiveAuthUserFields:true};}get baseUrl(){return `${this.cfg.serverUrl}/admin/db/${this.cfg.appId}/${this.name}`}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}clone(e){let n=new o(this.cfg,this.name);return n.sq={...this.sq,...e},n.opts={...this.opts},n}allowSensitiveAuthUserFields(e=true){let n=this.clone({});return n.opts.allowSensitiveAuthUserFields=!!e,n}normalizeFilterValue(e,n){return e==="in"||e==="not-in"||e==="array-contains-any"?Array.isArray(n)?n:[n]:n}toQueryFilters(e){return v(e).map(r=>typeof r=="object"&&r!=null&&"field"in r&&"op"in r?{...r,value:this.normalizeFilterValue(r.op,r.value)}:r)}appendAndFilters(e){return this.clone({where:[...this.sq.where??[],...e]})}appendOrFilters(e){let n=[...this.sq.where??[]];if(n.length===0)return this.clone({where:[{or:e}]});let r=n[0];if(n.length===1&&typeof r=="object"&&r!=null&&"or"in r)return this.clone({where:[{or:[...r.or,...e]}]});let i=n.length===1?n[0]:{and:n};return this.clone({where:[{or:[i,...e]}]})}appendFilters(e,n){return n==="or"?this.appendOrFilters(e):this.appendAndFilters(e)}appendOperatorFilter(e,n,r,t){return this.appendFilters([{field:e,op:n,value:this.normalizeFilterValue(n,r)}],t)}where(e){return this.appendFilters(this.toQueryFilters(e),"and")}and(e){return this.appendFilters(this.toQueryFilters(e),"and")}or(e){return this.appendFilters(this.toQueryFilters(e),"or")}in(e,n){return this.appendOperatorFilter(e,"in",n,"and")}andIn(e,n){return this.appendOperatorFilter(e,"in",n,"and")}orIn(e,n){return this.appendOperatorFilter(e,"in",n,"or")}notIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"and")}andNotIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"and")}orNotIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"or")}arrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"and")}andArrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"and")}orArrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"or")}arrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"and")}andArrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"and")}orArrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"or")}some(e,n){return this.appendOperatorFilter(e,"elem-match",n,"and")}andSome(e,n){return this.appendOperatorFilter(e,"elem-match",n,"and")}orSome(e,n){return this.appendOperatorFilter(e,"elem-match",n,"or")}like(e,n){return this.appendOperatorFilter(e,"like",n,"and")}andLike(e,n){return this.appendOperatorFilter(e,"like",n,"and")}orLike(e,n){return this.appendOperatorFilter(e,"like",n,"or")}notLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"and")}andNotLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"and")}orNotLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"or")}exists(e){return this.appendOperatorFilter(e,"exists",true,"and")}andExists(e){return this.appendOperatorFilter(e,"exists",true,"and")}orExists(e){return this.appendOperatorFilter(e,"exists",true,"or")}notExists(e){return this.appendOperatorFilter(e,"not-exists",true,"and")}andNotExists(e){return this.appendOperatorFilter(e,"not-exists",true,"and")}orNotExists(e){return this.appendOperatorFilter(e,"not-exists",true,"or")}latest(){return this.clone({orderBy:[...this.sq.orderBy??[],{field:"_seq",dir:"desc"}]})}newest(){return this.latest()}oldest(){return this.clone({orderBy:[...this.sq.orderBy??[],{field:"_seq",dir:"asc"}]})}orderBy(e,n="asc"){return this.clone({orderBy:[...this.sq.orderBy??[],{field:e,dir:n}]})}limit(e){return this.clone({limit:e})}offset(e){return this.clone({offset:e})}startAt(...e){return this.clone({startAt:{values:e}})}startAfter(...e){return this.clone({startAfter:{values:e}})}endAt(...e){return this.clone({endAt:{values:e}})}endBefore(...e){return this.clone({endBefore:{values:e}})}aggregate(...e){return this.clone({aggregate:[...this.sq.aggregate??[],...e]})}count(e="count"){return this.aggregate({fn:"count",alias:e})}sum(e,n){return this.aggregate({fn:"sum",field:e,alias:n??`sum_${e}`})}avg(e,n){return this.aggregate({fn:"avg",field:e,alias:n??`avg_${e}`})}min(e,n){return this.aggregate({fn:"min",field:e,alias:n??`min_${e}`})}max(e,n){return this.aggregate({fn:"max",field:e,alias:n??`max_${e}`})}distinct(e,n){return this.aggregate({fn:"distinct",field:e,alias:n??`distinct_${e}`})}groupBy(...e){return this.clone({groupBy:{fields:e}})}having(e,n,r){return this.clone({having:[...this.sq.having??[],{field:e,op:n,value:r}]})}buildStructuredJoin(e,n){let r={from:String(e??""),localField:String(n?.source??""),foreignField:String(n?.target??""),as:String(n?.as??""),single:n?.single};return Array.isArray(n?.where)&&(r.where=n.where),Array.isArray(n?.orderBy)&&(r.orderBy=n.orderBy),typeof n?.limit=="number"&&(r.limit=n.limit),typeof n?.offset=="number"&&(r.offset=n.offset),Array.isArray(n?.select)&&(r.select=n.select),Array.isArray(n?.joins)&&(r.joins=n.joins.map(t=>this.buildStructuredJoin(String(t?.collection??""),t))),r}cloneStructuredJoin(e){let n={...e};return Array.isArray(e.where)&&(n.where=e.where.map(r=>({...r}))),Array.isArray(e.orderBy)&&(n.orderBy=e.orderBy.map(r=>({...r}))),Array.isArray(e.select)&&(n.select=[...e.select]),Array.isArray(e.joins)&&(n.joins=e.joins.map(r=>this.cloneStructuredJoin(r))),n}appendNestedJoinByAlias(e,n,r){for(let t of e){if(t.as===n)return t.joins=[...t.joins??[],r],true;if(Array.isArray(t.joins)&&this.appendNestedJoinByAlias(t.joins,n,r))return true}return false}parseRelationRef(e){let r=String(e??"").trim().match(/^([A-Za-z0-9_.]+)\s*->\s*([A-Za-z0-9_]+)\.([A-Za-z0-9_.]+)(?:\s+as\s+([A-Za-z0-9_]+))?$/i);if(!r)throw new Error(`Invalid relation format: "${e}". Expected "source.path->collection.target"`);return {source:r[1],collection:r[2],target:r[3],alias:r[4]}}join(e,n){let r=this.buildStructuredJoin(e,n);return this.clone({joins:[...this.sq.joins??[],r]})}joinNested(e,n,r){let t=String(e??"").trim();if(!t)throw new Error("joinNested requires parentAlias");let i=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(i.length===0)throw new Error(`joinNested parent alias "${t}" not found`);let s=this.buildStructuredJoin(n,r);if(!this.appendNestedJoinByAlias(i,t,s))throw new Error(`joinNested parent alias "${t}" not found`);return this.clone({joins:i})}Join(e,n){return this.join(e,n)}JoinNested(e,n,r){return this.joinNested(e,n,r)}withRelation(e,n={}){let r=this.parseRelationRef(e);return this.join(r.collection,{...n,source:r.source,target:r.target,as:n.as??r.alias??r.collection})}select(...e){return this.clone({select:e})}distinctField(e){return this.clone({distinctField:e})}vectorSearch(e){return this.clone({vectorSearch:e})}getRawQuery(){let e={...this.sq};return Array.isArray(this.sq.where)&&(e.where=this.sq.where.map(n=>({...n}))),Array.isArray(this.sq.orderBy)&&(e.orderBy=this.sq.orderBy.map(n=>({...n}))),Array.isArray(this.sq.aggregate)&&(e.aggregate=this.sq.aggregate.map(n=>({...n}))),Array.isArray(this.sq.having)&&(e.having=this.sq.having.map(n=>({...n}))),Array.isArray(this.sq.select)&&(e.select=[...this.sq.select]),Array.isArray(this.sq.joins)&&(e.joins=this.sq.joins.map(n=>this.cloneStructuredJoin(n))),this.sq.groupBy?.fields&&(e.groupBy={fields:[...this.sq.groupBy.fields]}),this.sq.startAt?.values&&(e.startAt={values:[...this.sq.startAt.values]}),this.sq.startAfter?.values&&(e.startAfter={values:[...this.sq.startAfter.values]}),this.sq.endAt?.values&&(e.endAt={values:[...this.sq.endAt.values]}),this.sq.endBefore?.values&&(e.endBefore={values:[...this.sq.endBefore.values]}),{collection:this.name,query:e}}async get(){let e=new URL(this.baseUrl);e.searchParams.set("query",JSON.stringify(this.sq)),e.searchParams.set("allowSensitiveAuthUserFields",this.opts.allowSensitiveAuthUserFields?"1":"0");let n;try{n=await fetch(e.toString(),{headers:this.headers});}catch(t){let i=t instanceof Error?t.message:String(t);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${i}`)}let r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] GET ${this.baseUrl} failed (HTTP ${n.status}): ${r.error??"Unknown error"}`);return r.data??[]}async first(){let e=await this.get();return e.length>0?e[0]:null}async last(){let e=await this.get();return e.length>0?e[e.length-1]:null}async add(e){let n;try{n=await fetch(this.baseUrl,{method:"POST",headers:this.headers,body:JSON.stringify(e)});}catch(t){let i=t instanceof Error?t.message:String(t);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}): ${i}`)}let r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] POST ${this.baseUrl} failed (HTTP ${n.status}): ${r.error??"Unknown error"}`);return new m(this.cfg,this.name,r.id)}async deleteMany(){let e;try{e=await fetch(this.baseUrl,{method:"DELETE",headers:this.headers,body:JSON.stringify({where:this.sq.where??[]})});}catch(r){let t=r instanceof Error?r.message:String(r);throw new Error(`[flare-admin] Network error (DELETE ${this.baseUrl}): ${t}`)}let n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(`[flare-admin] DELETE ${this.baseUrl} failed (HTTP ${e.status}): ${n.error??"Unknown error"}`);return n.deleted??0}doc(e){return new m(this.cfg,this.name,e)}};var f=class{constructor(e){this.cfg=e;}collection(e){return new p(this.cfg,e)}};var g=class{constructor(e){this.cfg=e;}async createCustomToken(e,n={}){let r=`${this.cfg.serverUrl.replace(/\/$/,"")}/admin/token`,t=JSON.stringify({appId:this.cfg.appId,uid:String(e),role:n.role??"user",claims:n.claims??{},ttl:n.ttl??this.cfg.defaultTtl}),i;try{i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:t});}catch(a){let h=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Could not reach FlareServer at "${r}": ${h}
3
+ Make sure FLARE_URL is set correctly and the server is running.`)}let s;try{s=await i.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${i.status})`)}if(!i.ok)throw new Error(`[flare-admin] createCustomToken failed (HTTP ${i.status}): `+(s.error??"Unknown error"));if(typeof s.token!="string")throw new Error('[flare-admin] Server response missing "token" field');return s.token}};var A=class{constructor(e){this.cfg=e;}get baseUrl(){return `${this.cfg.serverUrl.replace(/\/$/,"")}/admin/notify/${this.cfg.appId}`}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}async send(e){let n;try{n=await fetch(`${this.baseUrl}/send`,{method:"POST",headers:this.headers,body:JSON.stringify(e??{})});}catch(t){let i=t instanceof Error?t.message:String(t);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}/send): ${i}`)}let r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] Notification send failed (HTTP ${n.status}): `+(r.error??"Unknown error"));return {sent:!!r.sent,appId:String(r.appId??this.cfg.appId),targetCount:Number(r.targetCount??0),successCount:Number(r.successCount??0),failureCount:Number(r.failureCount??0),invalidatedTokenCount:Number(r.invalidatedTokenCount??0),dryRun:!!r.dryRun}}async tokens(){let e;try{e=await fetch(`${this.baseUrl}/tokens`,{method:"GET",headers:this.headers});}catch(r){let t=r instanceof Error?r.message:String(r);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}/tokens): ${t}`)}let n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(`[flare-admin] Tokens fetch failed (HTTP ${e.status}): `+(n.error??"Unknown error"));return {appId:String(n.appId??this.cfg.appId),hasPushGateway:!!n.hasPushGateway,total:Number(n.total??0),tokens:Array.isArray(n.tokens)?n.tokens:[]}}};var y=class{constructor(e){this.cfg=e;this.ws=null;this.pendingAcks=new Map;this.subscriptions=new Map;this.activeSubscriptions=new Map;this.subscriptionErrorHandlers=new Map;this.subscriptionPermissionHandlers=new Map;this.subscriptionLastErrors=new Map;this.connected=false;this.shouldReconnect=true;this.reconnectDelay=2e3;let n=e.serverUrl.replace(/^http/,"ws");this.wsUrl=`${n}/?appId=${encodeURIComponent(e.appId)}&adminKey=${encodeURIComponent(e.adminKey)}`,this._readyPromise=new Promise(r=>{this._readyResolve=r;}),this._connect();}ready(){return this._readyPromise}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false;}send(e,n){return new Promise((r,t)=>{let i=k(),s={id:i,type:e,ts:Date.now(),...n},a=setTimeout(()=>{this.pendingAcks.delete(i),t(new Error(`[flare-admin] WS request timeout (${e})`));},1e4);this.pendingAcks.set(i,c=>{clearTimeout(a),c.type==="error"?t(new Error(`[flare-admin] Server error: ${c.message}`)):r(c);});let h=()=>this.ws?.send(JSON.stringify(s));this.connected&&this.ws?.readyState===F__default.default.OPEN?h():this.ready().then(h).catch(t);})}subscribe(e,n,r,t,i={}){let s=k(),a={baseId:s,liveId:s,collection:e,docId:n,structuredQuery:r,callback:t,options:i};this.activeSubscriptions.set(s,a),this.subscriptionErrorHandlers.set(s,new Set),this.subscriptionPermissionHandlers.set(s,new Set),this.activateSubscription(a);let h=()=>{let u=this.activeSubscriptions.get(s)?.liveId??s;this.activeSubscriptions.delete(s),this.subscriptions.delete(s),this.subscriptions.delete(u),this.subscriptionErrorHandlers.delete(s),this.subscriptionPermissionHandlers.delete(s),this.subscriptionLastErrors.delete(s),this.connected&&this.send("unsubscribe",{subscriptionId:u}).catch(()=>{});},c=h;return c.unsubscribe=h,c.onError=d=>{this.subscriptionErrorHandlers.get(s)?.add(d);let u=this.subscriptionLastErrors.get(s);if(u)try{d(u);}catch{}return c},c.onPermissionDenied=d=>{this.subscriptionPermissionHandlers.get(s)?.add(d);let u=this.subscriptionLastErrors.get(s);if(u?.permissionDenied)try{d(u);}catch{}return c},c.catch=d=>c.onError(d),c}activateSubscription(e){let n=()=>{this.subscriptions.set(e.liveId,e.callback);let r={collection:e.collection};e.docId&&(r.docId=e.docId),e.structuredQuery&&(r.query=e.structuredQuery),e.options.skipSnapshot&&(r.skipSnapshot=true),this.send("subscribe",r).then(t=>{let i=t.subscriptionId;if(i&&i!==e.liveId){let s=this.subscriptions.get(e.liveId);s&&(this.subscriptions.delete(e.liveId),this.subscriptions.set(i,s),e.liveId=i);}}).catch(()=>{this.subscriptions.delete(e.liveId),this.emitSubscriptionError(e.baseId,this.toSubscriptionError(new Error("Subscribe failed")));});};this.connected?n():this.ready().then(n).catch(r=>{this.emitSubscriptionError(e.baseId,this.toSubscriptionError(r));});}async replayActiveSubscriptions(){if(!this.connected)return;let e=Array.from(this.activeSubscriptions.values());for(let n of e){if(!this.activeSubscriptions.has(n.baseId))continue;let r=n.liveId;this.subscriptions.delete(r),n.liveId=n.baseId,r&&r!==n.baseId&&await this.send("unsubscribe",{subscriptionId:r}).catch(()=>{}),this.activateSubscription(n);}}toSubscriptionError(e){let n=e instanceof Error?e.message:String(e??"Unknown subscription error"),r=n.match(/^\[([^\]]+)\]\s*(.*)$/),t=r?.[1],i=(r?.[2]??n).trim()||n,s=t==="PERMISSION_DENIED"||n.includes("PERMISSION_DENIED");return {code:t,message:i,permissionDenied:s,raw:e}}emitSubscriptionError(e,n){this.subscriptionLastErrors.set(e,n);let r=this.subscriptionErrorHandlers.get(e);if(r)for(let t of r)try{t(n);}catch{}if(n.permissionDenied){let t=this.subscriptionPermissionHandlers.get(e);if(t)for(let i of t)try{i(n);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new F__default.default(this.wsUrl),this.ws.on("message",e=>{let n;try{n=JSON.parse(e.toString());}catch{return}this._handle(n);}),this.ws.on("close",e=>{this.connected=false,this.shouldReconnect&&e!==1e3&&setTimeout(()=>{this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this._connect();},this.reconnectDelay);}),this.ws.on("error",()=>{});}_handle(e){let n=e.type;if(n==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._readyResolve(),this.replayActiveSubscriptions().catch(()=>{}));return}if(n==="ack"||n==="pong"||n==="call_response"){let r=e.correlationId??e.id,t=this.pendingAcks.get(r);t&&(t(e),this.pendingAcks.delete(r));return}if(n==="error"){let r=e.correlationId;if(r){let t=this.pendingAcks.get(r);t&&(t(e),this.pendingAcks.delete(r));let i=Array.from(this.activeSubscriptions.values()).find(s=>s.liveId===r||s.baseId===r);if(i){let s=this.toSubscriptionError(new Error(`[${String(e.code??"ERROR")}] ${String(e.message??"Unknown error")}`));this.emitSubscriptionError(i.baseId,s);}}return}if(n==="snapshot"||n==="change"){let r=e.subscriptionId,t=this.subscriptions.get(r);t&&t({subscriptionId:r,collection:e.collection,docId:e.docId,data:e.data,type:n==="snapshot"?"snapshot":"change",operation:e.operation});}}};var w=class{constructor(e,n,r){this.conn=e;this.collection=n;this.id=r;}onSnapshot(e){let n=()=>{};return n=this.conn.subscribe(this.collection,this.id,void 0,r=>{r.type==="snapshot"&&(e(r),n());}),n}};var C=class o{constructor(e,n){this.conn=e;this.name=n;this.sq={};}clone(e){let n=new o(this.conn,this.name);return n.sq={...this.sq,...e},n}normalizeFilterValue(e,n){return e==="in"||e==="not-in"||e==="array-contains-any"?Array.isArray(n)?n:[n]:n}toQueryFilters(e){return v(e).map(r=>typeof r=="object"&&r!=null&&"field"in r&&"op"in r?{...r,value:this.normalizeFilterValue(r.op,r.value)}:r)}appendAndFilters(e){return this.clone({where:[...this.sq.where??[],...e]})}appendOrFilters(e){let n=[...this.sq.where??[]];if(n.length===0)return this.clone({where:[{or:e}]});let r=n[0];if(n.length===1&&typeof r=="object"&&r!=null&&"or"in r)return this.clone({where:[{or:[...r.or,...e]}]});let i=n.length===1?n[0]:{and:n};return this.clone({where:[{or:[i,...e]}]})}appendFilters(e,n){return n==="or"?this.appendOrFilters(e):this.appendAndFilters(e)}appendOperatorFilter(e,n,r,t){return this.appendFilters([{field:e,op:n,value:this.normalizeFilterValue(n,r)}],t)}where(e){return this.appendFilters(this.toQueryFilters(e),"and")}and(e){return this.appendFilters(this.toQueryFilters(e),"and")}or(e){return this.appendFilters(this.toQueryFilters(e),"or")}in(e,n){return this.appendOperatorFilter(e,"in",n,"and")}andIn(e,n){return this.appendOperatorFilter(e,"in",n,"and")}orIn(e,n){return this.appendOperatorFilter(e,"in",n,"or")}notIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"and")}andNotIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"and")}orNotIn(e,n){return this.appendOperatorFilter(e,"not-in",n,"or")}arrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"and")}andArrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"and")}orArrayContains(e,n){return this.appendOperatorFilter(e,"array-contains",n,"or")}arrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"and")}andArrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"and")}orArrayContainsAny(e,n){return this.appendOperatorFilter(e,"array-contains-any",n,"or")}some(e,n){return this.appendOperatorFilter(e,"elem-match",n,"and")}andSome(e,n){return this.appendOperatorFilter(e,"elem-match",n,"and")}orSome(e,n){return this.appendOperatorFilter(e,"elem-match",n,"or")}like(e,n){return this.appendOperatorFilter(e,"like",n,"and")}andLike(e,n){return this.appendOperatorFilter(e,"like",n,"and")}orLike(e,n){return this.appendOperatorFilter(e,"like",n,"or")}notLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"and")}andNotLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"and")}orNotLike(e,n){return this.appendOperatorFilter(e,"not-like",n,"or")}exists(e){return this.appendOperatorFilter(e,"exists",true,"and")}andExists(e){return this.appendOperatorFilter(e,"exists",true,"and")}orExists(e){return this.appendOperatorFilter(e,"exists",true,"or")}notExists(e){return this.appendOperatorFilter(e,"not-exists",true,"and")}andNotExists(e){return this.appendOperatorFilter(e,"not-exists",true,"and")}orNotExists(e){return this.appendOperatorFilter(e,"not-exists",true,"or")}latest(){return this.clone({orderBy:[...this.sq.orderBy??[],{field:"_seq",dir:"desc"}]})}newest(){return this.latest()}oldest(){return this.clone({orderBy:[...this.sq.orderBy??[],{field:"_seq",dir:"asc"}]})}orderBy(e,n="asc"){return this.clone({orderBy:[...this.sq.orderBy??[],{field:e,dir:n}]})}limit(e){return this.clone({limit:e})}offset(e){return this.clone({offset:e})}startAt(...e){return this.clone({startAt:{values:e}})}startAfter(...e){return this.clone({startAfter:{values:e}})}endAt(...e){return this.clone({endAt:{values:e}})}endBefore(...e){return this.clone({endBefore:{values:e}})}aggregate(...e){return this.clone({aggregate:[...this.sq.aggregate??[],...e]})}count(e="count"){return this.aggregate({fn:"count",alias:e})}sum(e,n){return this.aggregate({fn:"sum",field:e,alias:n??`sum_${e}`})}avg(e,n){return this.aggregate({fn:"avg",field:e,alias:n??`avg_${e}`})}min(e,n){return this.aggregate({fn:"min",field:e,alias:n??`min_${e}`})}max(e,n){return this.aggregate({fn:"max",field:e,alias:n??`max_${e}`})}distinct(e,n){return this.aggregate({fn:"distinct",field:e,alias:n??`distinct_${e}`})}groupBy(...e){return this.clone({groupBy:{fields:e}})}having(e,n,r){return this.clone({having:[...this.sq.having??[],{field:e,op:n,value:r}]})}buildStructuredJoin(e,n){let r={from:String(e??""),localField:String(n?.source??""),foreignField:String(n?.target??""),as:String(n?.as??""),single:n?.single};return Array.isArray(n?.where)&&(r.where=n.where),Array.isArray(n?.orderBy)&&(r.orderBy=n.orderBy),typeof n?.limit=="number"&&(r.limit=n.limit),typeof n?.offset=="number"&&(r.offset=n.offset),Array.isArray(n?.select)&&(r.select=n.select),Array.isArray(n?.joins)&&(r.joins=n.joins.map(t=>this.buildStructuredJoin(String(t?.collection??""),t))),r}cloneStructuredJoin(e){let n={...e};return Array.isArray(e.where)&&(n.where=e.where.map(r=>({...r}))),Array.isArray(e.orderBy)&&(n.orderBy=e.orderBy.map(r=>({...r}))),Array.isArray(e.select)&&(n.select=[...e.select]),Array.isArray(e.joins)&&(n.joins=e.joins.map(r=>this.cloneStructuredJoin(r))),n}appendNestedJoinByAlias(e,n,r){for(let t of e){if(t.as===n)return t.joins=[...t.joins??[],r],true;if(Array.isArray(t.joins)&&this.appendNestedJoinByAlias(t.joins,n,r))return true}return false}parseRelationRef(e){let r=String(e??"").trim().match(/^([A-Za-z0-9_.]+)\s*->\s*([A-Za-z0-9_]+)\.([A-Za-z0-9_.]+)(?:\s+as\s+([A-Za-z0-9_]+))?$/i);if(!r)throw new Error(`Invalid relation format: "${e}". Expected "source.path->collection.target"`);return {source:r[1],collection:r[2],target:r[3],alias:r[4]}}join(e,n){let r=this.buildStructuredJoin(e,n);return this.clone({joins:[...this.sq.joins??[],r]})}joinNested(e,n,r){let t=String(e??"").trim();if(!t)throw new Error("joinNested requires parentAlias");let i=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(i.length===0)throw new Error(`joinNested parent alias "${t}" not found`);let s=this.buildStructuredJoin(n,r);if(!this.appendNestedJoinByAlias(i,t,s))throw new Error(`joinNested parent alias "${t}" not found`);return this.clone({joins:i})}Join(e,n){return this.join(e,n)}JoinNested(e,n,r){return this.joinNested(e,n,r)}withRelation(e,n={}){let r=this.parseRelationRef(e);return this.join(r.collection,{...n,source:r.source,target:r.target,as:n.as??r.alias??r.collection})}select(...e){return this.clone({select:e})}distinctField(e){return this.clone({distinctField:e})}vectorSearch(e){return this.clone({vectorSearch:e})}doc(e){return new w(this.conn,this.name,e)}getRawQuery(){let e={...this.sq};return Array.isArray(this.sq.where)&&(e.where=this.sq.where.map(n=>({...n}))),Array.isArray(this.sq.orderBy)&&(e.orderBy=this.sq.orderBy.map(n=>({...n}))),Array.isArray(this.sq.aggregate)&&(e.aggregate=this.sq.aggregate.map(n=>({...n}))),Array.isArray(this.sq.having)&&(e.having=this.sq.having.map(n=>({...n}))),Array.isArray(this.sq.select)&&(e.select=[...this.sq.select]),Array.isArray(this.sq.joins)&&(e.joins=this.sq.joins.map(n=>this.cloneStructuredJoin(n))),this.sq.groupBy?.fields&&(e.groupBy={fields:[...this.sq.groupBy.fields]}),this.sq.startAt?.values&&(e.startAt={values:[...this.sq.startAt.values]}),this.sq.startAfter?.values&&(e.startAfter={values:[...this.sq.startAfter.values]}),this.sq.endAt?.values&&(e.endAt={values:[...this.sq.endAt.values]}),this.sq.endBefore?.values&&(e.endBefore={values:[...this.sq.endBefore.values]}),{collection:this.name,query:e}}onSnapshot(e){let n=this._buildSq(),r=()=>{};return r=this.conn.subscribe(this.name,void 0,n,t=>{t.type==="snapshot"&&(e(t),r());}),r}onDocAdded(e){let n=this._buildSq();return this.conn.subscribe(this.name,void 0,n,r=>{r.type==="change"&&r.operation==="insert"&&r.data!=null&&e(r.data,r.docId);},{skipSnapshot:true})}onDocUpdated(e){let n=this._buildSq();return this.conn.subscribe(this.name,void 0,n,r=>{r.type==="change"&&(r.operation==="update"||r.operation==="replace")&&r.data!=null&&e(r.data,r.docId);},{skipSnapshot:true})}onDocDeleted(e){let n=this._buildSq();return this.conn.subscribe(this.name,void 0,n,r=>{r.type==="change"&&r.operation==="delete"&&e(r.docId);},{skipSnapshot:true})}onDocChanged(e){let n=this._buildSq();return this.conn.subscribe(this.name,void 0,n,r=>{r.type==="change"&&e(r.data??null,r.docId,r.operation);},{skipSnapshot:true})}_buildSq(){let e={};return this.sq.where&&this.sq.where.length>0&&(e.where=this.sq.where),this.sq.orderBy&&this.sq.orderBy.length>0&&(e.orderBy=this.sq.orderBy),this.sq.limit!==void 0&&(e.limit=this.sq.limit),this.sq.offset!==void 0&&(e.offset=this.sq.offset),this.sq.startAt&&(e.startAt=this.sq.startAt),this.sq.startAfter&&(e.startAfter=this.sq.startAfter),this.sq.endAt&&(e.endAt=this.sq.endAt),this.sq.endBefore&&(e.endBefore=this.sq.endBefore),this.sq.aggregate&&this.sq.aggregate.length>0&&(e.aggregate=this.sq.aggregate),this.sq.groupBy&&(e.groupBy=this.sq.groupBy),this.sq.having&&this.sq.having.length>0&&(e.having=this.sq.having),this.sq.joins&&this.sq.joins.length>0&&(e.joins=this.sq.joins),this.sq.vectorSearch&&(e.vectorSearch=this.sq.vectorSearch),this.sq.select&&this.sq.select.length>0&&(e.select=this.sq.select),this.sq.distinctField&&(e.distinctField=this.sq.distinctField),e}};var b=class{constructor(e){this._ws=new y(e);}collection(e){return new C(this._ws,e)}ready(){return this._ws.ready()}disconnect(){this._ws.disconnect();}};var T=class{constructor(e){this.cfg={defaultTtl:"24h",...e,serverUrl:e.serverUrl.replace(/\/$/,"")};}auth(){return this._auth??(this._auth=new g(this.cfg))}db(){return this._db??(this._db=new f(this.cfg))}connection(){return this._conn??(this._conn=new b(this.cfg))}notifications(){return this._notifications??(this._notifications=new A(this.cfg))}},S=new Map;function le(o,e="[DEFAULT]"){if(S.has(e))return S.get(e);let n=new T(o);return S.set(e,n),n}function R(o="[DEFAULT]"){let e=S.get(o);if(!e)throw new Error(`[flare-admin] No app named "${o}" found. Call connectApp() before getApp().`);return e}function de(o="[DEFAULT]"){return R(o).auth()}function ue(o="[DEFAULT]"){return R(o).db()}function he(o="[DEFAULT]"){return R(o).connection()}function pe(o="[DEFAULT]"){return R(o).notifications()}exports.AdminCollectionReference=p;exports.AdminDocumentReference=m;exports.AdminLiveCollectionReference=C;exports.AdminLiveDocumentReference=w;exports.FlareAdminApp=T;exports.FlareAdminAuthService=g;exports.FlareAdminConnection=b;exports.FlareAdminDbService=f;exports.FlareAdminNotificationsService=A;exports.FlareAdminWsConnection=y;exports.auth=de;exports.connectApp=le;exports.connection=he;exports.db=ue;exports.getApp=R;exports.notifications=pe;