@zuzjs/flare-admin 0.1.4 → 0.1.5

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 CHANGED
@@ -366,3 +366,213 @@ const raw = admin.db()
366
366
 
367
367
  console.log(raw.collection, raw.query);
368
368
  ```
369
+
370
+ ## Storage API (S3-like)
371
+
372
+ ```typescript
373
+ import { connectApp, AdminStorageSignedAction } from "@zuzjs/flare-admin";
374
+
375
+ const admin = connectApp({
376
+ serverUrl: process.env.FLARE_URL!,
377
+ appId: process.env.FLARE_APP_ID!,
378
+ adminKey: process.env.FLARE_ADMIN_KEY!,
379
+ });
380
+
381
+ const storage = admin.storage();
382
+
383
+ await storage.createBucket("reports");
384
+
385
+ await storage.putObject({
386
+ bucket: "reports",
387
+ key: "weekly/summary.json",
388
+ body: Buffer.from(JSON.stringify({ ok: true })),
389
+ contentType: "application/json",
390
+ encrypt: true,
391
+ });
392
+
393
+ const meta = await storage.headObject({
394
+ bucket: "reports",
395
+ key: "weekly/summary.json",
396
+ });
397
+
398
+ const downloaded = await storage.getObject({
399
+ bucket: "reports",
400
+ key: "weekly/summary.json",
401
+ decrypt: true,
402
+ });
403
+
404
+ const signedDownload = await admin.createSignedUrl({
405
+ bucket: "reports",
406
+ key: "weekly/summary.json",
407
+ action: AdminStorageSignedAction.Download,
408
+ expiresInSeconds: 180,
409
+ forceDownload: true,
410
+ allowedOrigins: ["https://app.example.com"],
411
+ embedOnly: false,
412
+ });
413
+
414
+ await storage.deleteObjects({
415
+ bucket: "reports",
416
+ keys: ["weekly/summary.json"],
417
+ });
418
+
419
+ console.log(meta.size, downloaded.contentBase64, signedDownload.url);
420
+ ```
421
+
422
+ Direct signed-download helpers:
423
+
424
+ ```typescript
425
+ const directUrl = await admin.getObjectUrl({
426
+ bucket: "reports",
427
+ key: "weekly/summary.json",
428
+ expiresInSeconds: 120,
429
+ allowedOrigins: ["*"],
430
+ });
431
+
432
+ const triggered = await admin.downloadObject({
433
+ bucket: "reports",
434
+ key: "weekly/summary.json",
435
+ filename: "summary.json",
436
+ forceDownload: true,
437
+ allowedOrigins: ["https://app.example.com"],
438
+ });
439
+
440
+ console.log(directUrl, triggered.triggered);
441
+ ```
442
+
443
+ ## App-Level Storage Rules (Samples)
444
+
445
+ Use `service zuz.storage` rules to enforce per-app policy on top of platform limits.
446
+
447
+ Example 1: Authenticated read, quota-aware write
448
+
449
+ ```txt
450
+ service zuz.storage {
451
+ match /storage/{bucket}/objects {
452
+ match /{document=**} {
453
+ allow read: if auth != null;
454
+
455
+ allow write: if auth != null
456
+ && requestData.storage.usage.storageBytes + requestData.size
457
+ <= requestData.storage.plan.storageBytes
458
+ && requestData.storage.usage.bandwidthBytes + requestData.size
459
+ <= requestData.storage.plan.bandwidthBytes;
460
+
461
+ allow delete: if auth != null;
462
+ }
463
+ }
464
+ }
465
+ ```
466
+
467
+ Example 2: Pro-plan write + admin override
468
+
469
+ ```txt
470
+ service zuz.storage {
471
+ match /storage/{bucket}/objects {
472
+ match /{document=**} {
473
+ allow read: if auth != null;
474
+
475
+ allow write: if auth != null
476
+ && (
477
+ auth.role == 'admin'
478
+ || auth.claims.plan == 'pro'
479
+ )
480
+ && requestData.storage.usage.storageBytes + requestData.size
481
+ <= requestData.storage.plan.storageBytes
482
+ && requestData.storage.usage.bandwidthBytes + requestData.size
483
+ <= requestData.storage.plan.bandwidthBytes;
484
+
485
+ allow delete: if auth != null
486
+ && (auth.role == 'admin' || auth.claims.plan == 'pro');
487
+ }
488
+ }
489
+ }
490
+ ```
491
+
492
+ Apply rules with admin API:
493
+
494
+ ```http
495
+ POST /v1/apps/{appId}/admin/storage/rules
496
+ Authorization: Bearer FA_ADMIN_xxxxxxxxxxxx
497
+ Content-Type: application/json
498
+
499
+ {
500
+ "rulesDsl": "service zuz.storage { match /storage/{bucket}/objects { match /{document=**} { allow read: if auth != null; } } }"
501
+ }
502
+ ```
503
+
504
+ Tip: map users to app-level plans through app settings (`storagePlans`, `storageUserPlans`, `storageDefaultPlanId`) so `requestData.storage.plan.*` resolves correctly at runtime.
505
+
506
+ ## Storage Signed URLs
507
+
508
+ Create signed URLs for first-party upload/download/delete/edit without exposing admin key to file-transfer clients.
509
+
510
+ ```typescript
511
+ const signedUpload = await admin.createSignedUrl({
512
+ bucket: "reports",
513
+ key: "uploads/big-video.mp4",
514
+ action: AdminStorageSignedAction.Upload,
515
+ expiresInSeconds: 300,
516
+ contentType: "video/mp4",
517
+ encrypt: true,
518
+ });
519
+
520
+ await fetch(signedUpload.url, {
521
+ method: signedUpload.method,
522
+ headers: { "Content-Type": "video/mp4" },
523
+ body: videoBuffer,
524
+ });
525
+
526
+ const signedDownload = await admin.createSignedUrl({
527
+ bucket: "reports",
528
+ key: "uploads/big-video.mp4",
529
+ action: AdminStorageSignedAction.Download,
530
+ expiresInSeconds: 300,
531
+ decrypt: true,
532
+ forceDownload: false,
533
+ allowedOrigins: ["https://app.example.com"],
534
+ embedOnly: true,
535
+ });
536
+
537
+ const bytes = await fetch(signedDownload.url, { method: signedDownload.method }).then((r) => r.arrayBuffer());
538
+
539
+ console.log("expiresAt", signedDownload.expiresAt, "ttl", signedDownload.expiresInSeconds);
540
+ ```
541
+
542
+ Notes:
543
+ - `token` (for example `st_...`) is a signed ticket identifier; expiry is returned as `expiresAt`/`expiresInSeconds`.
544
+ - `forceDownload` and `embedOnly` are mutually exclusive.
545
+ - `allowedOrigins` defaults to `['*']` if omitted.
546
+ - `downloadObject(...)` triggers a browser click only when `document` is available. In server runtimes, it returns `{ ok, url, filename, triggered: false }` so you can redirect, proxy, or return the signed URL.
547
+
548
+ ## External AWS SDK Init From Flare `/aws` Config
549
+
550
+ ```typescript
551
+ import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
552
+ import { connectApp } from "@zuzjs/flare-admin";
553
+
554
+ const admin = connectApp({
555
+ serverUrl: process.env.FLARE_URL!,
556
+ appId: process.env.FLARE_APP_ID!,
557
+ adminKey: process.env.FLARE_ADMIN_KEY!,
558
+ });
559
+
560
+ const aws = await admin.storage().awsConfig("storage-server-id");
561
+
562
+ const s3 = new S3Client({
563
+ endpoint: aws.endpoint,
564
+ region: aws.region,
565
+ forcePathStyle: Boolean(aws.forcePathStyle),
566
+ credentials: {
567
+ accessKeyId: aws.accessKeyId,
568
+ secretAccessKey: aws.secretAccessKey,
569
+ },
570
+ });
571
+
572
+ await s3.send(new PutObjectCommand({
573
+ Bucket: aws.bucket,
574
+ Key: `${aws.prefix ?? ""}manual/admin-test.txt`,
575
+ Body: "hello from admin external sdk",
576
+ ContentType: "text/plain",
577
+ }));
578
+ ```
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var O=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var O__default=/*#__PURE__*/_interopDefault(O);/* @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:L(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 L(o){return isNaN(Number(o))?o==="true"?true:o==="false"?false:o==="null"?null:o:Number(o)}function T(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}function I(o,e){let n=o.dataMapper;if(!n||typeof n!="object")return null;let r=n[e];return typeof r=="function"?r:null}function F(o,e,n){let r=I(o,e);if(!r||n==null||typeof n!="object")return n;try{return r(n)}catch{return n}}function q(o,e,n){if(!e||typeof e!="object"||!Array.isArray(n)||n.length===0)return e;let r=e;for(let t of n){let i=String(t?.as??"").trim();if(!i)continue;let s=Array.isArray(t?.joins)?t.joins:[],a=r[i],c=a;Array.isArray(a)?c=a.map(l=>q(o,l,s)):a&&typeof a=="object"&&(c=q(o,a,s)),c=Array.isArray(c)?c.map(l=>F(o,i,l)):F(o,i,c),c!==a&&(r===e&&(r={...r}),r[i]=c);}return r}function m(o,e,n,r){let t=Array.isArray(r?.joins)?r.joins:[],i=s=>{let a=q(o,s,t);return F(o,e,a)};return Array.isArray(n)?n.map(s=>i(s)):i(n)}var f=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(t){let i=t instanceof Error?t.message:String(t);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${i}`)}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 m(this.cfg,this.collection,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(i){let s=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${s}`)}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 m(this.cfg,this.name,r.data,this.sq)??[]}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 f(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 f(this.cfg,this.name,e)}};var g=class{constructor(e){this.cfg=e;}collection(e){return new p(this.cfg,e)}};var A=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 c=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Could not reach FlareServer at "${r}": ${c}
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}async getTicket(e,n={}){let r=`${this.cfg.serverUrl.replace(/\/$/,"")}/admin/ticket`,t=JSON.stringify({appId:this.cfg.appId,uid:String(e),role:n.role??"user",email:n.email,sid:n.sid,tag:n.tag,ttlSeconds:n.ttlSeconds,ip:n.ip}),i;try{i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:t});}catch(c){let l=c instanceof Error?c.message:String(c);throw new Error(`[flare-admin] Could not reach FlareServer at "${r}": ${l}
4
- 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] getTicket failed (HTTP ${i.status}): `+(s.error??"Unknown error"));let a=s.ticket;if(!a||typeof a.ticket!="string")throw new Error('[flare-admin] Server response missing "ticket" object');return {ticket:String(a.ticket),tag:String(a.tag??""),uuid:String(a.uuid??""),expires_at:String(a.expires_at??""),one_time:!!(a.one_time??true),uid:String(a.uid??String(e)),role:String(a.role??n.role??"user"),ip:String(a.ip??"unknown")}}};var y=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 w=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=T(),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,l=>{clearTimeout(a),l.type==="error"?t(new Error(`[flare-admin] Server error: ${l.message}`)):r(l);});let c=()=>this.ws?.send(JSON.stringify(s));this.connected&&this.ws?.readyState===O__default.default.OPEN?c():this.ready().then(c).catch(t);})}subscribe(e,n,r,t,i={}){let s=T(),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 c=()=>{let h=this.activeSubscriptions.get(s)?.liveId??s;this.activeSubscriptions.delete(s),this.subscriptions.delete(s),this.subscriptions.delete(h),this.subscriptionErrorHandlers.delete(s),this.subscriptionPermissionHandlers.delete(s),this.subscriptionLastErrors.delete(s),this.connected&&this.send("unsubscribe",{subscriptionId:h}).catch(()=>{});},l=c;return l.unsubscribe=c,l.onError=u=>{this.subscriptionErrorHandlers.get(s)?.add(u);let h=this.subscriptionLastErrors.get(s);if(h)try{u(h);}catch{}return l},l.onPermissionDenied=u=>{this.subscriptionPermissionHandlers.get(s)?.add(u);let h=this.subscriptionLastErrors.get(s);if(h?.permissionDenied)try{u(h);}catch{}return l},l.catch=u=>l.onError(u),l}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 O__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);if(t){let i=Array.from(this.activeSubscriptions.values()).find(c=>c.liveId===r),s=String(e.collection??i?.collection??""),a=n==="change"&&e.operation==="delete"?null:m(this.cfg,s,e.data,i?.structuredQuery);t({subscriptionId:r,collection:s,docId:e.docId,data:a,type:n==="snapshot"?"snapshot":"change",operation:e.operation});}}}};var C=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 b=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 C(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 S=class{constructor(e){this._ws=new w(e);}collection(e){return new b(this._ws,e)}ready(){return this._ws.ready()}disconnect(){this._ws.disconnect();}};var E=class{constructor(e){this.cfg={defaultTtl:"24h",...e,serverUrl:e.serverUrl.replace(/\/$/,""),dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new A(this.cfg))}db(){return this._db??(this._db=new g(this.cfg))}connection(){return this._conn??(this._conn=new S(this.cfg))}notifications(){return this._notifications??(this._notifications=new y(this.cfg))}},k=new Map;function ye(o,e="[DEFAULT]"){if(k.has(e))return k.get(e);let n=new E(o);return k.set(e,n),n}function R(o="[DEFAULT]"){let e=k.get(o);if(!e)throw new Error(`[flare-admin] No app named "${o}" found. Call connectApp() before getApp().`);return e}function we(o="[DEFAULT]"){return R(o).auth()}function Ce(o="[DEFAULT]"){return R(o).db()}function be(o="[DEFAULT]"){return R(o).connection()}function Se(o="[DEFAULT]"){return R(o).notifications()}exports.AdminCollectionReference=p;exports.AdminDocumentReference=f;exports.AdminLiveCollectionReference=b;exports.AdminLiveDocumentReference=C;exports.FlareAdminApp=E;exports.FlareAdminAuthService=A;exports.FlareAdminConnection=S;exports.FlareAdminDbService=g;exports.FlareAdminNotificationsService=y;exports.FlareAdminWsConnection=w;exports.auth=we;exports.connectApp=ye;exports.connection=be;exports.db=Ce;exports.getApp=R;exports.notifications=Se;
1
+ 'use strict';var re=require('fs'),k=require('path'),url=require('url'),Y=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var re__default=/*#__PURE__*/_interopDefault(re);var k__default=/*#__PURE__*/_interopDefault(k);var Y__default=/*#__PURE__*/_interopDefault(Y);/* @zuzjs/flare-admin */
2
+ var ee=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,l=ee();var D=(i=>(i.Upload="upload",i.Download="download",i.Delete="delete",i.Edit="edit",i))(D||{});function B(r){let e=[];for(let[t,n]of Object.entries(r))if(typeof n=="string"){let i=n.match(/^(>=|<=|!=|>|<|==)\s*(.+)$/);if(i){let[,s,o]=i;e.push({field:t,op:s,value:te(o.trim())});}else e.push({field:t,op:"==",value:n});}else Array.isArray(n)?e.push({field:t,op:"in",value:n}):e.push({field:t,op:"==",value:n});return e}function te(r){return isNaN(Number(r))?r==="true"?true:r==="false"?false:r==="null"?null:r:Number(r)}function U(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}function ne(r,e){let t=r.dataMapper;if(!t||typeof t!="object")return null;let n=t[e];return typeof n=="function"?n:null}function L(r,e,t){let n=ne(r,e);if(!n||t==null||typeof t!="object")return t;try{return n(t)}catch{return t}}function $(r,e,t){if(!e||typeof e!="object"||!Array.isArray(t)||t.length===0)return e;let n=e;for(let i of t){let s=String(i?.as??"").trim();if(!s)continue;let o=Array.isArray(i?.joins)?i.joins:[],a=n[s],d=a;Array.isArray(a)?d=a.map(c=>$(r,c,o)):a&&typeof a=="object"&&(d=$(r,a,o)),d=Array.isArray(d)?d.map(c=>L(r,s,c)):L(r,s,d),d!==a&&(n===e&&(n={...n}),n[s]=d);}return n}function A(r,e,t,n){let i=Array.isArray(n?.joins)?n.joins:[],s=o=>{let a=$(r,o,i);return L(r,e,a)};return Array.isArray(t)?t.map(o=>s(o)):s(t)}var se=()=>typeof process<"u"&&!!process.versions?.node,g=r=>{if(r.transport==="http")return false;let e=!!(r.grpcUrl&&r.grpcUrl.trim().length>0),t=se();if(r.transport==="grpc"){if(!e)throw new Error("[flare-admin][grpc] transport=grpc requires grpcUrl");if(!t)throw new Error("[flare-admin][grpc] transport=grpc requires Node.js runtime");return true}return e&&t},S=r=>{try{return JSON.stringify(r??{})}catch{return "{}"}},w=r=>r?.field&&r?.op?{queryFilter:{field:String(r.field),op:String(r.op),valueJson:S(r.value)}}:Array.isArray(r?.or)?{orFilter:{or:r.or.map(e=>w(e))}}:Array.isArray(r?.and)?{andFilter:{and:r.and.map(e=>w(e))}}:{queryFilter:{field:"",op:"==",valueJson:"null"}},x=r=>{if(!(!r||!Array.isArray(r.values)))return {valuesJson:r.values.map(e=>S(e))}},H=r=>({from:r.from,localField:r.localField,foreignField:r.foreignField,as:r.as,single:!!r.single,where:Array.isArray(r.where)?r.where.map(w):[],orderBy:Array.isArray(r.orderBy)?r.orderBy.map(e=>({field:e.field,dir:e.dir??"asc"})):[],limit:r.limit??0,offset:r.offset??0,select:Array.isArray(r.select)?r.select:[],joins:Array.isArray(r.joins)?r.joins.map(H):[]}),oe=r=>({where:Array.isArray(r.where)?r.where.map(w):[],orderBy:Array.isArray(r.orderBy)?r.orderBy.map(e=>({field:e.field,dir:e.dir??"asc"})):[],limit:r.limit??0,offset:r.offset??0,startAt:x(r.startAt),startAfter:x(r.startAfter),endAt:x(r.endAt),endBefore:x(r.endBefore),aggregate:Array.isArray(r.aggregate)?r.aggregate.map(e=>({fn:e.fn,field:e.field??"",alias:e.alias??""})):[],groupBy:r.groupBy?{fields:r.groupBy.fields??[]}:void 0,having:Array.isArray(r.having)?r.having.map(e=>({field:e.field,op:e.op,value:e.value})):[],joins:Array.isArray(r.joins)?r.joins.map(H):[],select:Array.isArray(r.select)?r.select:[],distinctField:r.distinctField??""});async function m(r){let e=await import('@grpc/grpc-js'),t=await import('@grpc/proto-loader'),n=k__default.default.dirname(url.fileURLToPath(l)),i=[k__default.default.resolve(n,"../../proto"),k__default.default.resolve(n,"../proto"),k__default.default.resolve(process.cwd(),"proto")],s=i.find(u=>re__default.default.existsSync(k__default.default.join(u,"flare.proto")))??i[0],o=k__default.default.join(s,"flare.proto"),a=await t.load(o,{keepCase:false,longs:String,enums:String,defaults:true,oneofs:true,includeDirs:[s]}),c=e.loadPackageDefinition(a).flare;return new c.AdminService(r,e.credentials.createInsecure())}function h(r,e,t){return new Promise((n,i)=>{r[e](t,(s,o)=>{if(s)return i(s);n(o??{});});})}function f(r,e){if(r.error)throw new Error(`[flare-admin][grpc] ${e} failed: ${r.errorDescription||r.error}`)}async function G(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"AdminQuery",{app_id:r.appId,admin_key:r.adminKey,collection:e,query:oe(t)});f(i,"admin_query");try{let s=JSON.parse(i.dataJson||"[]");return Array.isArray(s)?s:[]}catch{return []}}async function M(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"CreateCustomToken",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",claims_json:S(t.claims??{}),ttl:t.ttl??r.defaultTtl});if(f(i,"create_custom_token"),!i.token)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return String(i.token)}async function Q(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"CreateAuthTicket",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",email:t.email??"",sid:t.sid??"",tag:t.tag??"",ttl_seconds:t.ttlSeconds??0,ip:t.ip??""});return f(i,"create_auth_ticket"),{ticket:String(i.ticket??""),tag:String(i.tag??""),uuid:String(i.uuid??""),expires_at:String(i.expiresAt??""),one_time:!!(i.oneTime??true),uid:String(i.uid??e),role:String(i.role??t.role??"user"),ip:String(i.ip??"unknown")}}async function z(r,e,t){if(!g(r))return;let n=await m(r.grpcUrl),i=await h(n,"GetDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});if(f(i,"get_document"),!i.found)return null;try{return JSON.parse(i.dataJson||"{}")}catch{return {}}}async function K(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"CreateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,data_json:S(t)});return f(i,"create_document"),String(i.id??"")}async function W(r,e,t,n){if(!g(r))return null;let i=await m(r.grpcUrl),s=await h(i,"ReplaceDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:S(n)});return f(s,"replace_document"),true}async function V(r,e,t,n){if(!g(r))return null;let i=await m(r.grpcUrl),s=await h(i,"UpdateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:S(n)});return f(s,"update_document"),true}async function Z(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"DeleteDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});return f(i,"delete_document"),!!i.deleted}async function X(r,e,t){if(!g(r))return null;let n=await m(r.grpcUrl),i=await h(n,"DeleteMany",{app_id:r.appId,admin_key:r.adminKey,collection:e,where:(t??[]).map(w)});return f(i,"delete_many"),Number(i.deleted??0)}var y=class{constructor(e,t,n){this.cfg=e;this.collection=t;this.id=n;}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,t){let n;try{n=await fetch(this.baseUrl,{method:e,headers:this.headers,...t!==void 0?{body:JSON.stringify(t)}:{}});}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[flare-admin] Network error (${e} ${this.baseUrl}): ${o}`)}let i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] ${e} ${this.baseUrl} failed (HTTP ${n.status}): `+(i.error??"Unknown error"));return i}async get(){let e=await z(this.cfg,this.collection,this.id);if(e!==void 0)return e===null?null:A(this.cfg,this.collection,e)??null;let t;try{t=await fetch(this.baseUrl,{headers:this.headers});}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${o}`)}if(t.status===404)return null;let n=await t.json().catch(()=>({}));if(!t.ok)throw new Error(`[flare-admin] GET ${this.baseUrl} failed (HTTP ${t.status}): `+(n.error??"Unknown error"));return A(this.cfg,this.collection,n.data)??null}async set(e){await W(this.cfg,this.collection,this.id,e)===null&&await this.request("PUT",e);}async update(e){await V(this.cfg,this.collection,this.id,e)===null&&await this.request("PATCH",e);}async delete(){await Z(this.cfg,this.collection,this.id)===null&&await this.request("DELETE");}parent(){return new b(this.cfg,this.collection)}};var b=class r{constructor(e,t){this.cfg=e;this.name=t;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 t=new r(this.cfg,this.name);return t.sq={...this.sq,...e},t.opts={...this.opts},t}allowSensitiveAuthUserFields(e=true){let t=this.clone({});return t.opts.allowSensitiveAuthUserFields=!!e,t}normalizeFilterValue(e,t){return e==="in"||e==="not-in"||e==="array-contains-any"?Array.isArray(t)?t:[t]:t}toQueryFilters(e){return B(e).map(n=>typeof n=="object"&&n!=null&&"field"in n&&"op"in n?{...n,value:this.normalizeFilterValue(n.op,n.value)}:n)}appendAndFilters(e){return this.clone({where:[...this.sq.where??[],...e]})}appendOrFilters(e){let t=[...this.sq.where??[]];if(t.length===0)return this.clone({where:[{or:e}]});let n=t[0];if(t.length===1&&typeof n=="object"&&n!=null&&"or"in n)return this.clone({where:[{or:[...n.or,...e]}]});let s=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[s,...e]}]})}appendFilters(e,t){return t==="or"?this.appendOrFilters(e):this.appendAndFilters(e)}appendOperatorFilter(e,t,n,i){return this.appendFilters([{field:e,op:t,value:this.normalizeFilterValue(t,n)}],i)}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,t){return this.appendOperatorFilter(e,"in",t,"and")}andIn(e,t){return this.appendOperatorFilter(e,"in",t,"and")}orIn(e,t){return this.appendOperatorFilter(e,"in",t,"or")}notIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"and")}andNotIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"and")}orNotIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"or")}arrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"and")}andArrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"and")}orArrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"or")}arrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"and")}andArrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"and")}orArrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"or")}some(e,t){return this.appendOperatorFilter(e,"elem-match",t,"and")}andSome(e,t){return this.appendOperatorFilter(e,"elem-match",t,"and")}orSome(e,t){return this.appendOperatorFilter(e,"elem-match",t,"or")}like(e,t){return this.appendOperatorFilter(e,"like",t,"and")}andLike(e,t){return this.appendOperatorFilter(e,"like",t,"and")}orLike(e,t){return this.appendOperatorFilter(e,"like",t,"or")}notLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"and")}andNotLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"and")}orNotLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"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,t="asc"){return this.clone({orderBy:[...this.sq.orderBy??[],{field:e,dir:t}]})}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,t){return this.aggregate({fn:"sum",field:e,alias:t??`sum_${e}`})}avg(e,t){return this.aggregate({fn:"avg",field:e,alias:t??`avg_${e}`})}min(e,t){return this.aggregate({fn:"min",field:e,alias:t??`min_${e}`})}max(e,t){return this.aggregate({fn:"max",field:e,alias:t??`max_${e}`})}distinct(e,t){return this.aggregate({fn:"distinct",field:e,alias:t??`distinct_${e}`})}groupBy(...e){return this.clone({groupBy:{fields:e}})}having(e,t,n){return this.clone({having:[...this.sq.having??[],{field:e,op:t,value:n}]})}buildStructuredJoin(e,t){let n={from:String(e??""),localField:String(t?.source??""),foreignField:String(t?.target??""),as:String(t?.as??""),single:t?.single};return Array.isArray(t?.where)&&(n.where=t.where),Array.isArray(t?.orderBy)&&(n.orderBy=t.orderBy),typeof t?.limit=="number"&&(n.limit=t.limit),typeof t?.offset=="number"&&(n.offset=t.offset),Array.isArray(t?.select)&&(n.select=t.select),Array.isArray(t?.joins)&&(n.joins=t.joins.map(i=>this.buildStructuredJoin(String(i?.collection??""),i))),n}cloneStructuredJoin(e){let t={...e};return Array.isArray(e.where)&&(t.where=e.where.map(n=>({...n}))),Array.isArray(e.orderBy)&&(t.orderBy=e.orderBy.map(n=>({...n}))),Array.isArray(e.select)&&(t.select=[...e.select]),Array.isArray(e.joins)&&(t.joins=e.joins.map(n=>this.cloneStructuredJoin(n))),t}appendNestedJoinByAlias(e,t,n){for(let i of e){if(i.as===t)return i.joins=[...i.joins??[],n],true;if(Array.isArray(i.joins)&&this.appendNestedJoinByAlias(i.joins,t,n))return true}return false}parseRelationRef(e){let n=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(!n)throw new Error(`Invalid relation format: "${e}". Expected "source.path->collection.target"`);return {source:n[1],collection:n[2],target:n[3],alias:n[4]}}join(e,t){let n=this.buildStructuredJoin(e,t);return this.clone({joins:[...this.sq.joins??[],n]})}joinNested(e,t,n){let i=String(e??"").trim();if(!i)throw new Error("joinNested requires parentAlias");let s=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(s.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let o=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(s,i,o))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:s})}Join(e,t){return this.join(e,t)}JoinNested(e,t,n){return this.joinNested(e,t,n)}withRelation(e,t={}){let n=this.parseRelationRef(e);return this.join(n.collection,{...t,source:n.source,target:n.target,as:t.as??n.alias??n.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(t=>({...t}))),Array.isArray(this.sq.orderBy)&&(e.orderBy=this.sq.orderBy.map(t=>({...t}))),Array.isArray(this.sq.aggregate)&&(e.aggregate=this.sq.aggregate.map(t=>({...t}))),Array.isArray(this.sq.having)&&(e.having=this.sq.having.map(t=>({...t}))),Array.isArray(this.sq.select)&&(e.select=[...this.sq.select]),Array.isArray(this.sq.joins)&&(e.joins=this.sq.joins.map(t=>this.cloneStructuredJoin(t))),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=await G(this.cfg,this.name,this.sq);if(e)return A(this.cfg,this.name,e,this.sq)??[];let t=new URL(this.baseUrl);t.searchParams.set("query",JSON.stringify(this.sq)),t.searchParams.set("allowSensitiveAuthUserFields",this.opts.allowSensitiveAuthUserFields?"1":"0");let n;try{n=await fetch(t.toString(),{headers:this.headers});}catch(o){let a=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${a}`)}let i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] GET ${this.baseUrl} failed (HTTP ${n.status}): ${i.error??"Unknown error"}`);return A(this.cfg,this.name,i.data,this.sq)??[]}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 t=await K(this.cfg,this.name,e);if(t!==null)return new y(this.cfg,this.name,t);let n;try{n=await fetch(this.baseUrl,{method:"POST",headers:this.headers,body:JSON.stringify(e)});}catch(s){let o=s instanceof Error?s.message:String(s);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}): ${o}`)}let i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`[flare-admin] POST ${this.baseUrl} failed (HTTP ${n.status}): ${i.error??"Unknown error"}`);return new y(this.cfg,this.name,i.id)}async deleteMany(){let e=await X(this.cfg,this.name,this.sq.where??[]);if(e!==null)return e;let t;try{t=await fetch(this.baseUrl,{method:"DELETE",headers:this.headers,body:JSON.stringify({where:this.sq.where??[]})});}catch(i){let s=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (DELETE ${this.baseUrl}): ${s}`)}let n=await t.json().catch(()=>({}));if(!t.ok)throw new Error(`[flare-admin] DELETE ${this.baseUrl} failed (HTTP ${t.status}): ${n.error??"Unknown error"}`);return n.deleted??0}doc(e){return new y(this.cfg,this.name,e)}};var C=class{constructor(e){this.cfg=e;}collection(e){return new b(this.cfg,e)}};var v=class{constructor(e){this.cfg=e;}async createCustomToken(e,t={}){if(g(this.cfg)){let a=await M(this.cfg,String(e),t);if(!a)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return a}let n=`${this.cfg.serverUrl.replace(/\/$/,"")}/admin/token`,i=JSON.stringify({appId:this.cfg.appId,uid:String(e),role:t.role??"user",claims:t.claims??{},ttl:t.ttl??this.cfg.defaultTtl}),s;try{s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(a){let d=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Could not reach FlareServer at "${n}": ${d}
3
+ Make sure FLARE_URL is set correctly and the server is running.`)}let o;try{o=await s.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${s.status})`)}if(!s.ok)throw new Error(`[flare-admin] createCustomToken failed (HTTP ${s.status}): `+(o.error??"Unknown error"));if(typeof o.token!="string")throw new Error('[flare-admin] Server response missing "token" field');return o.token}async getTicket(e,t={}){if(g(this.cfg)){let d=await Q(this.cfg,String(e),t);if(!d)throw new Error("[flare-admin][grpc] create_auth_ticket returned empty payload");return d}let n=`${this.cfg.serverUrl.replace(/\/$/,"")}/admin/ticket`,i=JSON.stringify({appId:this.cfg.appId,uid:String(e),role:t.role??"user",email:t.email,sid:t.sid,tag:t.tag,ttlSeconds:t.ttlSeconds,ip:t.ip}),s;try{s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(d){let c=d instanceof Error?d.message:String(d);throw new Error(`[flare-admin] Could not reach FlareServer at "${n}": ${c}
4
+ Make sure FLARE_URL is set correctly and the server is running.`)}let o;try{o=await s.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${s.status})`)}if(!s.ok)throw new Error(`[flare-admin] getTicket failed (HTTP ${s.status}): `+(o.error??"Unknown error"));let a=o.ticket;if(!a||typeof a.ticket!="string")throw new Error('[flare-admin] Server response missing "ticket" object');return {ticket:String(a.ticket),tag:String(a.tag??""),uuid:String(a.uuid??""),expires_at:String(a.expires_at??""),one_time:!!(a.one_time??true),uid:String(a.uid??String(e)),role:String(a.role??t.role??"user"),ip:String(a.ip??"unknown")}}};var T=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 t;try{t=await fetch(`${this.baseUrl}/send`,{method:"POST",headers:this.headers,body:JSON.stringify(e??{})});}catch(i){let s=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}/send): ${s}`)}let n=await t.json().catch(()=>({}));if(!t.ok)throw new Error(`[flare-admin] Notification send failed (HTTP ${t.status}): `+(n.error??"Unknown error"));return {sent:!!n.sent,appId:String(n.appId??this.cfg.appId),targetCount:Number(n.targetCount??0),successCount:Number(n.successCount??0),failureCount:Number(n.failureCount??0),invalidatedTokenCount:Number(n.invalidatedTokenCount??0),dryRun:!!n.dryRun}}async tokens(){let e;try{e=await fetch(`${this.baseUrl}/tokens`,{method:"GET",headers:this.headers});}catch(n){let i=n instanceof Error?n.message:String(n);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}/tokens): ${i}`)}let t=await e.json().catch(()=>({}));if(!e.ok)throw new Error(`[flare-admin] Tokens fetch failed (HTTP ${e.status}): `+(t.error??"Unknown error"));return {appId:String(t.appId??this.cfg.appId),hasPushGateway:!!t.hasPushGateway,total:Number(t.total??0),tokens:Array.isArray(t.tokens)?t.tokens:[]}}};var E=class{constructor(e){this.cfg=e;}base(e){return `${this.cfg.serverUrl.replace(/\/$/,"")}/admin/storage/${encodeURIComponent(this.cfg.appId)}${e}`}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}async jsonRequest(e,t,n){let i,s=this.base(t);try{i=await fetch(s,{method:e,headers:this.headers,...n!==void 0?{body:JSON.stringify(n)}:{}});}catch(a){let d=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Network error (${e} ${s}): ${d}`)}let o=await i.json().catch(()=>({}));if(!i.ok)throw new Error(`[flare-admin] ${e} ${s} failed (HTTP ${i.status}): `+(o.error??"Unknown error"));return o}async request(e,t,n){return this.jsonRequest(e,t,n)}async servers(){let e=await this.jsonRequest("GET","/servers");return Array.isArray(e.servers)?e.servers:[]}async createServer(e){let t=await this.jsonRequest("POST","/servers",e??{});return {ok:!!(t.ok??true),serverId:String(t.serverId??"")}}async patchServer(e,t){let n=String(e??"").trim();if(!n)throw new Error("storage server id is required");let i=await this.jsonRequest("POST",`/servers/${encodeURIComponent(n)}`,t??{});return {ok:!!(i.ok??true),serverId:String(i.serverId??n)}}async deleteServer(e){let t=String(e??"").trim();if(!t)throw new Error("storage server id is required");let n=await this.jsonRequest("DELETE",`/servers/${encodeURIComponent(t)}`);return {ok:!!(n.ok??true),serverId:String(n.serverId??t),removedObjects:Number(n.removedObjects??0)}}async awsConfig(e){let t=String(e??"").trim();if(!t)throw new Error("storage server id is required");return (await this.jsonRequest("GET",`/servers/${encodeURIComponent(t)}/aws`)).aws??{}}async uploadObject(e){return await this.jsonRequest("POST","/object/upload",e??{})}async downloadObject(e){return await this.jsonRequest("POST","/object/download",e??{})}async deleteObject(e){return await this.jsonRequest("POST","/object/delete",e??{})}async createSignedUrl(e){return await this.jsonRequest("POST","/signed-url",e??{})}async setRules(e){let t=await this.jsonRequest("POST","/rules",{...e?.rules?{rules:e.rules}:{},...typeof e?.rulesDsl=="string"?{rulesDsl:e.rulesDsl}:{},...e?.rulesHistoryPolicy?{rulesHistoryPolicy:e.rulesHistoryPolicy}:{}});return {id:String(t.id??this.cfg.appId)}}async validateRules(e){let t=await this.jsonRequest("POST","/rules/validate",{rulesDsl:e});return {valid:!!t.valid,diagnostics:Array.isArray(t.diagnostics)?t.diagnostics:[],rulesCount:Number(t.rulesCount??0)}}async rulesHistory(){let e=await this.jsonRequest("GET","/rules/history");return {history:Array.isArray(e.history)?e.history:[],policy:e.policy??{maxEntries:30,maxAgeDays:365},restoreEvents:Array.isArray(e.restoreEvents)?e.restoreEvents:[]}}async restoreRules(e){let t=String(e??"").trim();if(!t)throw new Error("historyId is required");let n=await this.jsonRequest("POST","/rules/restore",{historyId:t});return {id:String(n.id??this.cfg.appId),rulesText:String(n.rulesText??"")}}};function J(r){if(typeof Buffer<"u")return Buffer.from(r).toString("base64");let e="";for(let t=0;t<r.length;t++)e+=String.fromCharCode(r[t]);return btoa(e)}async function ae(r){return r===void 0?"":typeof r=="string"?J(new TextEncoder().encode(r)):Buffer&&Buffer.isBuffer(r)?r.toString("base64"):r instanceof Uint8Array?J(r):r instanceof ArrayBuffer?J(new Uint8Array(r)):""}function ce(r){return Buffer?Buffer.from(String(r)).toString("base64"):btoa(String(r))}function de(r){try{let e=Buffer?Buffer.from(r,"base64").toString():atob(r),t=parseInt(e,10);return isNaN(t)?0:t}catch{return 0}}function le(r){return (String(r??"").split("/").pop()??"download").replace(/["\\\r\n]/g,"")||"download"}var R=class{constructor(e){this._bucketCache=new Map;this._bucketListLoaded=false;this._bucketListPromise=null;this._svc=e;}async _ensureBuckets(){if(!this._bucketListLoaded)return this._bucketListPromise||(this._bucketListPromise=this._loadBuckets().then(()=>{this._bucketListLoaded=true;}).catch(e=>{throw this._bucketListPromise=null,e}).finally(()=>{this._bucketListPromise=null;})),this._bucketListPromise}async _loadBuckets(){let e=await this.listBuckets();for(let t of e)this._bucketCache.set(t.bucket,t.id);}_invalidateCache(){this._bucketCache.clear(),this._bucketListLoaded=false,this._bucketListPromise=null;}async _resolveBucketId(e,t){let n=this._bucketCache.get(e);if(n)return n;await this._ensureBuckets();let i=this._bucketCache.get(e);if(i)return i;if(t)return (await this.createBucket(e)).id;throw new Error(`Bucket "${e}" not found. Create it first with createBucket("${e}").`)}async createBucket(e,t={}){let n=e.trim();if(!n)throw new Error("bucket name is required");await this._ensureBuckets();let i=this._bucketCache.get(n);if(i){let d=(await this.listBuckets()).find(c=>c.id===i);if(d)return d}let s;try{s=await this._svc.createServer({name:n,kind:t.kind??"managed",bucket:n,prefix:t.prefix,region:t.region,endpoint:t.endpoint,accessKey:t.accessKey,secretKey:t.secretKey,dataDir:t.dataDir,forcePathStyle:t.forcePathStyle});}catch(a){if((a instanceof Error?a.message:String(a)).includes("bucket_conflict")){this._invalidateCache(),await this._ensureBuckets();let c=this._bucketCache.get(n);if(c){let p=(await this.listBuckets()).find(q=>q.id===c);if(p)return p}}throw a}let o={id:s.serverId,name:n,bucket:n,kind:t.kind??"managed",prefix:t.prefix};return this._bucketCache.set(n,o.id),o}async listBuckets(){let t=(await this._svc.servers()).map(n=>({id:n.id,name:n.name,bucket:n.bucket,kind:n.kind,region:n.region,endpoint:n.endpoint,prefix:n.prefix,frozen:n.frozen,readOnly:n.readOnly,createdAt:n.createdAt,updatedAt:n.updatedAt}));this._bucketCache.clear();for(let n of t)this._bucketCache.set(n.bucket,n.id);return this._bucketListLoaded=true,t}async deleteBucket(e){let t=await this._resolveBucketId(e,false),n=await this._svc.deleteServer(t);return this._bucketCache.delete(e),{ok:n.ok,removedObjects:n.removedObjects}}async deleteBuckets(e){let t=[],n={};return await Promise.all(e.map(async i=>{try{await this.deleteBucket(i),t.push(i);}catch(s){n[i]=s instanceof Error?s.message:String(s);}})),{ok:Object.keys(n).length===0,deleted:t,errors:n}}async getBucketLocation(e){let n=(await this.listBuckets()).find(i=>i.bucket===e||i.name===e);if(!n)throw new Error(`Bucket "${e}" not found`);return {bucket:n.bucket,kind:n.kind,region:n.region,endpoint:n.endpoint}}async putObject(e){let t=await this._resolveBucketId(e.bucket,true);if(e.contentBase64!==void 0){let c=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:e.contentBase64,contentType:e.contentType,encrypt:e.encrypt});return {ok:c.ok,bucket:e.bucket,key:String(c.path??e.key),size:Number(c.size??0),encrypted:!!c.encrypted}}let n=4*1024*1024,i=e.base64MaxBytes??n,s;if(typeof e.body=="string"?s=new TextEncoder().encode(e.body).length:(e.body instanceof Uint8Array||e.body instanceof ArrayBuffer||Buffer&&Buffer.isBuffer(e.body))&&(s=e.body.byteLength),s!==void 0&&s>i){let c=await this.createSignedUrl({bucket:e.bucket,key:e.key,action:"upload",expiresInSeconds:300,sizeBytes:s,contentType:e.contentType,encrypt:e.encrypt}),u;typeof e.body=="string"?u=new TextEncoder().encode(e.body):u=e.body;let p=await fetch(c.url,{method:c.method??"PUT",headers:{...e.contentType?{"Content-Type":e.contentType}:{}},body:u});if(!p.ok){let q=await p.text().catch(()=>"");throw new Error(`[flare-admin] Signed-URL upload failed (HTTP ${p.status}): ${q}`)}return {ok:true,bucket:e.bucket,key:e.key,size:s??0,encrypted:!!(e.encrypt??true)}}let a=await ae(e.body),d=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:a,contentType:e.contentType,encrypt:e.encrypt});return {ok:d.ok,bucket:e.bucket,key:String(d.path??e.key),size:Number(d.size??0),encrypted:!!d.encrypted}}async getObject(e){let t=await this._resolveBucketId(e.bucket,false),n=await this._svc.downloadObject({serverId:t,path:e.key,decrypt:e.decrypt});return {ok:n.ok,bucket:e.bucket,key:String(n.path??e.key),contentBase64:String(n.contentBase64??""),contentType:String(n.contentType??"application/octet-stream"),size:Number(n.size??0),encrypted:!!n.encrypted}}async getObjectUrl(e){return (await this.createSignedUrl({bucket:e.bucket,key:e.key,action:"download",decrypt:e.decrypt,expiresInSeconds:e.expiresInSeconds,forceDownload:e.forceDownload,allowedOrigins:e.allowedOrigins,embedOnly:e.embedOnly})).url}async downloadObject(e){let t=e.forceDownload??true,n=await this.getObjectUrl({...e,forceDownload:t}),i=e.filename??le(e.key),s=globalThis.document;if(!s)return {ok:true,url:n,filename:i,triggered:false};let o=s.createElement("a");return o.href=n,e.openInNewTab?o.target="_blank":o.download=i,o.rel="noopener noreferrer",s.body?.appendChild(o),o.click(),o.remove(),{ok:true,url:n,filename:i,triggered:true}}async headObject(e){let t=await this._resolveBucketId(e.bucket,false),n=await this._svc.request("POST","/object/head",{serverId:t,path:e.key});return {bucket:e.bucket,key:String(n.path??e.key),size:Number(n.size??0),contentType:String(n.contentType??"application/octet-stream"),encrypted:!!n.encrypted,createdAt:n.createdAt,updatedAt:n.updatedAt}}async headObjects(e){return Promise.all(e.keys.map(t=>this.headObject({bucket:e.bucket,key:t})))}async listObjects(e){let t=await this._resolveBucketId(e.bucket,false),n=e.cursor?de(e.cursor):0,i=Math.max(1,Math.min(e.limit??100,1e3)),s=await this._svc.request("POST","/object/list",{serverId:t,prefix:e.prefix,limit:i,skip:n}),o=Array.isArray(s.objects)?s.objects:[],a=!!s.hasMore,d=Number(s.count??o.length);return {bucket:e.bucket,objects:o.map(c=>({bucket:e.bucket,key:String(c.path??c.key??""),size:Number(c.size??0),contentType:String(c.contentType??"application/octet-stream"),encrypted:!!c.encrypted,createdAt:c.createdAt,updatedAt:c.updatedAt})),count:d,hasMore:a,cursor:a?ce(n+o.length):void 0}}async copyObject(e){let[t,n]=await Promise.all([this._resolveBucketId(e.sourceBucket,false),this._resolveBucketId(e.destBucket,true)]);return {ok:!!((await this._svc.request("POST","/object/copy",{serverId:t,path:e.sourceKey,destServerId:n,destPath:e.destKey})).ok??true)}}async copyObjects(e){let t={};return await Promise.all(e.map(async n=>{try{await this.copyObject(n);}catch(i){t[`${n.sourceBucket}/${n.sourceKey}`]=i instanceof Error?i.message:String(i);}})),{ok:Object.keys(t).length===0,errors:t}}async deleteObject(e){return this._svc.deleteObject(e)}async deleteObjects(e){let t=await this._resolveBucketId(e.bucket,false),n=await this._svc.request("POST","/object/delete-many",{serverId:t,paths:e.keys});return {ok:!!(n.ok??true),deleted:Array.isArray(n.deleted)?n.deleted:e.keys,errors:n.errors??{}}}async createSignedUrl(e){let t=await this._resolveBucketId(e.bucket,false);return await this._svc.request("POST","/signed-url",{serverId:t,path:e.key,action:e.action,expiresInSeconds:e.expiresInSeconds,sizeBytes:e.sizeBytes,contentType:e.contentType,encrypt:e.encrypt,decrypt:e.decrypt,forceDownload:e.forceDownload,allowedOrigins:e.allowedOrigins,embedOnly:e.embedOnly})}};var O=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 t=e.serverUrl.replace(/^http/,"ws");this.wsUrl=`${t}/?appId=${encodeURIComponent(e.appId)}&adminKey=${encodeURIComponent(e.adminKey)}`,this._readyPromise=new Promise(n=>{this._readyResolve=n;}),this._connect();}ready(){return this._readyPromise}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false;}send(e,t){return new Promise((n,i)=>{let s=U(),o={id:s,type:e,ts:Date.now(),...t},a=setTimeout(()=>{this.pendingAcks.delete(s),i(new Error(`[flare-admin] WS request timeout (${e})`));},1e4);this.pendingAcks.set(s,c=>{clearTimeout(a),c.type==="error"?i(new Error(`[flare-admin] Server error: ${c.message}`)):n(c);});let d=()=>this.ws?.send(JSON.stringify(o));this.connected&&this.ws?.readyState===Y__default.default.OPEN?d():this.ready().then(d).catch(i);})}subscribe(e,t,n,i,s={}){let o=U(),a={baseId:o,liveId:o,collection:e,docId:t,structuredQuery:n,callback:i,options:s};this.activeSubscriptions.set(o,a),this.subscriptionErrorHandlers.set(o,new Set),this.subscriptionPermissionHandlers.set(o,new Set),this.activateSubscription(a);let d=()=>{let p=this.activeSubscriptions.get(o)?.liveId??o;this.activeSubscriptions.delete(o),this.subscriptions.delete(o),this.subscriptions.delete(p),this.subscriptionErrorHandlers.delete(o),this.subscriptionPermissionHandlers.delete(o),this.subscriptionLastErrors.delete(o),this.connected&&this.send("unsubscribe",{subscriptionId:p}).catch(()=>{});},c=d;return c.unsubscribe=d,c.onError=u=>{this.subscriptionErrorHandlers.get(o)?.add(u);let p=this.subscriptionLastErrors.get(o);if(p)try{u(p);}catch{}return c},c.onPermissionDenied=u=>{this.subscriptionPermissionHandlers.get(o)?.add(u);let p=this.subscriptionLastErrors.get(o);if(p?.permissionDenied)try{u(p);}catch{}return c},c.catch=u=>c.onError(u),c}activateSubscription(e){let t=()=>{this.subscriptions.set(e.liveId,e.callback);let n={collection:e.collection};e.docId&&(n.docId=e.docId),e.structuredQuery&&(n.query=e.structuredQuery),e.options.skipSnapshot&&(n.skipSnapshot=true),this.send("subscribe",n).then(i=>{let s=i.subscriptionId;if(s&&s!==e.liveId){let o=this.subscriptions.get(e.liveId);o&&(this.subscriptions.delete(e.liveId),this.subscriptions.set(s,o),e.liveId=s);}}).catch(()=>{this.subscriptions.delete(e.liveId),this.emitSubscriptionError(e.baseId,this.toSubscriptionError(new Error("Subscribe failed")));});};this.connected?t():this.ready().then(t).catch(n=>{this.emitSubscriptionError(e.baseId,this.toSubscriptionError(n));});}async replayActiveSubscriptions(){if(!this.connected)return;let e=Array.from(this.activeSubscriptions.values());for(let t of e){if(!this.activeSubscriptions.has(t.baseId))continue;let n=t.liveId;this.subscriptions.delete(n),t.liveId=t.baseId,n&&n!==t.baseId&&await this.send("unsubscribe",{subscriptionId:n}).catch(()=>{}),this.activateSubscription(t);}}toSubscriptionError(e){let t=e instanceof Error?e.message:String(e??"Unknown subscription error"),n=t.match(/^\[([^\]]+)\]\s*(.*)$/),i=n?.[1],s=(n?.[2]??t).trim()||t,o=i==="PERMISSION_DENIED"||t.includes("PERMISSION_DENIED");return {code:i,message:s,permissionDenied:o,raw:e}}emitSubscriptionError(e,t){this.subscriptionLastErrors.set(e,t);let n=this.subscriptionErrorHandlers.get(e);if(n)for(let i of n)try{i(t);}catch{}if(t.permissionDenied){let i=this.subscriptionPermissionHandlers.get(e);if(i)for(let s of i)try{s(t);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new Y__default.default(this.wsUrl),this.ws.on("message",e=>{let t;try{t=JSON.parse(e.toString());}catch{return}this._handle(t);}),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 t=e.type;if(t==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._readyResolve(),this.replayActiveSubscriptions().catch(()=>{}));return}if(t==="ack"||t==="pong"||t==="call_response"){let n=e.correlationId??e.id,i=this.pendingAcks.get(n);i&&(i(e),this.pendingAcks.delete(n));return}if(t==="error"){let n=e.correlationId;if(n){let i=this.pendingAcks.get(n);i&&(i(e),this.pendingAcks.delete(n));let s=Array.from(this.activeSubscriptions.values()).find(o=>o.liveId===n||o.baseId===n);if(s){let o=this.toSubscriptionError(new Error(`[${String(e.code??"ERROR")}] ${String(e.message??"Unknown error")}`));this.emitSubscriptionError(s.baseId,o);}}return}if(t==="snapshot"||t==="change"){let n=e.subscriptionId,i=this.subscriptions.get(n);if(i){let s=Array.from(this.activeSubscriptions.values()).find(d=>d.liveId===n),o=String(e.collection??s?.collection??""),a=t==="change"&&e.operation==="delete"?null:A(this.cfg,o,e.data,s?.structuredQuery);i({subscriptionId:n,collection:o,docId:e.docId,data:a,type:t==="snapshot"?"snapshot":"change",operation:e.operation});}}}};var j=class{constructor(e,t,n){this.conn=e;this.collection=t;this.id=n;}onSnapshot(e){let t=()=>{};return t=this.conn.subscribe(this.collection,this.id,void 0,n=>{n.type==="snapshot"&&(e(n),t());}),t}};var I=class r{constructor(e,t){this.conn=e;this.name=t;this.sq={};}clone(e){let t=new r(this.conn,this.name);return t.sq={...this.sq,...e},t}normalizeFilterValue(e,t){return e==="in"||e==="not-in"||e==="array-contains-any"?Array.isArray(t)?t:[t]:t}toQueryFilters(e){return B(e).map(n=>typeof n=="object"&&n!=null&&"field"in n&&"op"in n?{...n,value:this.normalizeFilterValue(n.op,n.value)}:n)}appendAndFilters(e){return this.clone({where:[...this.sq.where??[],...e]})}appendOrFilters(e){let t=[...this.sq.where??[]];if(t.length===0)return this.clone({where:[{or:e}]});let n=t[0];if(t.length===1&&typeof n=="object"&&n!=null&&"or"in n)return this.clone({where:[{or:[...n.or,...e]}]});let s=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[s,...e]}]})}appendFilters(e,t){return t==="or"?this.appendOrFilters(e):this.appendAndFilters(e)}appendOperatorFilter(e,t,n,i){return this.appendFilters([{field:e,op:t,value:this.normalizeFilterValue(t,n)}],i)}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,t){return this.appendOperatorFilter(e,"in",t,"and")}andIn(e,t){return this.appendOperatorFilter(e,"in",t,"and")}orIn(e,t){return this.appendOperatorFilter(e,"in",t,"or")}notIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"and")}andNotIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"and")}orNotIn(e,t){return this.appendOperatorFilter(e,"not-in",t,"or")}arrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"and")}andArrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"and")}orArrayContains(e,t){return this.appendOperatorFilter(e,"array-contains",t,"or")}arrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"and")}andArrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"and")}orArrayContainsAny(e,t){return this.appendOperatorFilter(e,"array-contains-any",t,"or")}some(e,t){return this.appendOperatorFilter(e,"elem-match",t,"and")}andSome(e,t){return this.appendOperatorFilter(e,"elem-match",t,"and")}orSome(e,t){return this.appendOperatorFilter(e,"elem-match",t,"or")}like(e,t){return this.appendOperatorFilter(e,"like",t,"and")}andLike(e,t){return this.appendOperatorFilter(e,"like",t,"and")}orLike(e,t){return this.appendOperatorFilter(e,"like",t,"or")}notLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"and")}andNotLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"and")}orNotLike(e,t){return this.appendOperatorFilter(e,"not-like",t,"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,t="asc"){return this.clone({orderBy:[...this.sq.orderBy??[],{field:e,dir:t}]})}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,t){return this.aggregate({fn:"sum",field:e,alias:t??`sum_${e}`})}avg(e,t){return this.aggregate({fn:"avg",field:e,alias:t??`avg_${e}`})}min(e,t){return this.aggregate({fn:"min",field:e,alias:t??`min_${e}`})}max(e,t){return this.aggregate({fn:"max",field:e,alias:t??`max_${e}`})}distinct(e,t){return this.aggregate({fn:"distinct",field:e,alias:t??`distinct_${e}`})}groupBy(...e){return this.clone({groupBy:{fields:e}})}having(e,t,n){return this.clone({having:[...this.sq.having??[],{field:e,op:t,value:n}]})}buildStructuredJoin(e,t){let n={from:String(e??""),localField:String(t?.source??""),foreignField:String(t?.target??""),as:String(t?.as??""),single:t?.single};return Array.isArray(t?.where)&&(n.where=t.where),Array.isArray(t?.orderBy)&&(n.orderBy=t.orderBy),typeof t?.limit=="number"&&(n.limit=t.limit),typeof t?.offset=="number"&&(n.offset=t.offset),Array.isArray(t?.select)&&(n.select=t.select),Array.isArray(t?.joins)&&(n.joins=t.joins.map(i=>this.buildStructuredJoin(String(i?.collection??""),i))),n}cloneStructuredJoin(e){let t={...e};return Array.isArray(e.where)&&(t.where=e.where.map(n=>({...n}))),Array.isArray(e.orderBy)&&(t.orderBy=e.orderBy.map(n=>({...n}))),Array.isArray(e.select)&&(t.select=[...e.select]),Array.isArray(e.joins)&&(t.joins=e.joins.map(n=>this.cloneStructuredJoin(n))),t}appendNestedJoinByAlias(e,t,n){for(let i of e){if(i.as===t)return i.joins=[...i.joins??[],n],true;if(Array.isArray(i.joins)&&this.appendNestedJoinByAlias(i.joins,t,n))return true}return false}parseRelationRef(e){let n=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(!n)throw new Error(`Invalid relation format: "${e}". Expected "source.path->collection.target"`);return {source:n[1],collection:n[2],target:n[3],alias:n[4]}}join(e,t){let n=this.buildStructuredJoin(e,t);return this.clone({joins:[...this.sq.joins??[],n]})}joinNested(e,t,n){let i=String(e??"").trim();if(!i)throw new Error("joinNested requires parentAlias");let s=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(s.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let o=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(s,i,o))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:s})}Join(e,t){return this.join(e,t)}JoinNested(e,t,n){return this.joinNested(e,t,n)}withRelation(e,t={}){let n=this.parseRelationRef(e);return this.join(n.collection,{...t,source:n.source,target:n.target,as:t.as??n.alias??n.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 j(this.conn,this.name,e)}getRawQuery(){let e={...this.sq};return Array.isArray(this.sq.where)&&(e.where=this.sq.where.map(t=>({...t}))),Array.isArray(this.sq.orderBy)&&(e.orderBy=this.sq.orderBy.map(t=>({...t}))),Array.isArray(this.sq.aggregate)&&(e.aggregate=this.sq.aggregate.map(t=>({...t}))),Array.isArray(this.sq.having)&&(e.having=this.sq.having.map(t=>({...t}))),Array.isArray(this.sq.select)&&(e.select=[...this.sq.select]),Array.isArray(this.sq.joins)&&(e.joins=this.sq.joins.map(t=>this.cloneStructuredJoin(t))),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 t=this._buildSq(),n=()=>{};return n=this.conn.subscribe(this.name,void 0,t,i=>{i.type==="snapshot"&&(e(i),n());}),n}onDocAdded(e){let t=this._buildSq();return this.conn.subscribe(this.name,void 0,t,n=>{n.type==="change"&&n.operation==="insert"&&n.data!=null&&e(n.data,n.docId);},{skipSnapshot:true})}onDocUpdated(e){let t=this._buildSq();return this.conn.subscribe(this.name,void 0,t,n=>{n.type==="change"&&(n.operation==="update"||n.operation==="replace")&&n.data!=null&&e(n.data,n.docId);},{skipSnapshot:true})}onDocDeleted(e){let t=this._buildSq();return this.conn.subscribe(this.name,void 0,t,n=>{n.type==="change"&&n.operation==="delete"&&e(n.docId);},{skipSnapshot:true})}onDocChanged(e){let t=this._buildSq();return this.conn.subscribe(this.name,void 0,t,n=>{n.type==="change"&&e(n.data??null,n.docId,n.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 F=class{constructor(e){this._ws=new O(e);}collection(e){return new I(this._ws,e)}ready(){return this._ws.ready()}disconnect(){this._ws.disconnect();}};var _t="ServerTimeStamp",qt={$serverTimestamp:true};var N=class{constructor(e){this.cfg={defaultTtl:"24h",transport:"auto",...e,serverUrl:e.serverUrl.replace(/\/$/,""),grpcUrl:e.grpcUrl??"",dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new v(this.cfg))}db(){return this._db??(this._db=new C(this.cfg))}connection(){return this._conn??(this._conn=new F(this.cfg))}notifications(){return this._notifications??(this._notifications=new T(this.cfg))}storageService(){return this._storage??(this._storage=new E(this.cfg))}storage(){return this._storageS3||(this._storageS3=new R(this.storageService())),this._storageS3}s3(){return this.storage()}async createSignedUrl(e){return await this.s3().createSignedUrl(e)}createBucket(e,t){return this.s3().createBucket(e,t)}listBuckets(){return this.s3().listBuckets()}deleteBucket(e){return this.s3().deleteBucket(e)}deleteBuckets(e){return this.s3().deleteBuckets(e)}getBucketLocation(e){return this.s3().getBucketLocation(e)}putObject(e){return this.s3().putObject(e)}getObject(e){return this.s3().getObject(e)}getObjectUrl(e){return this.s3().getObjectUrl(e)}downloadObject(e){return this.s3().downloadObject(e)}headObject(e){return this.s3().headObject(e)}headObjects(e){return this.s3().headObjects(e)}listObjects(e){return this.s3().listObjects(e)}copyObject(e){return this.s3().copyObject(e)}copyObjects(e){return this.s3().copyObjects(e)}deleteObjects(e){return this.s3().deleteObjects(e)}},_=new Map;function Gt(r,e="[DEFAULT]"){if(_.has(e))return _.get(e);let t=new N(r);return _.set(e,t),t}function P(r="[DEFAULT]"){let e=_.get(r);if(!e)throw new Error(`[flare-admin] No app named "${r}" found. Call connectApp() before getApp().`);return e}function Mt(r="[DEFAULT]"){return P(r).auth()}function Qt(r="[DEFAULT]"){return P(r).db()}function zt(r="[DEFAULT]"){return P(r).connection()}function Kt(r="[DEFAULT]"){return P(r).notifications()}function Wt(r="[DEFAULT]"){return P(r).storage()}exports.AdminCollectionReference=b;exports.AdminDocumentReference=y;exports.AdminLiveCollectionReference=I;exports.AdminLiveDocumentReference=j;exports.AdminStorageSignedAction=D;exports.FlareAdminApp=N;exports.FlareAdminAuthService=v;exports.FlareAdminConnection=F;exports.FlareAdminDbService=C;exports.FlareAdminNotificationsService=T;exports.FlareAdminStorageS3=R;exports.FlareAdminWsConnection=O;exports.ServerTimeStamp=_t;exports.ServerTimeStampField=qt;exports.auth=Mt;exports.connectApp=Gt;exports.connection=zt;exports.db=Qt;exports.getApp=P;exports.notifications=Kt;exports.storage=Wt;