@zuzjs/flare-admin 0.1.9 → 0.1.11
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 +22 -0
- package/dist/db/Collection.d.ts +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +163 -2
- package/dist/index.d.ts +23 -1
- package/dist/index.js +3 -3
- package/dist/lib/functions.d.ts +32 -0
- package/dist/lib/normalization.d.ts +7 -0
- package/dist/types/index.d.ts +110 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -477,12 +477,31 @@ await storage.putObject({
|
|
|
477
477
|
key: "weekly/summary.json",
|
|
478
478
|
body: Buffer.from(JSON.stringify({ ok: true })),
|
|
479
479
|
contentType: "application/json",
|
|
480
|
+
access: "public",
|
|
481
|
+
// encrypt defaults to false when omitted
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
const uploaded = await storage.putObject({
|
|
485
|
+
bucket: "reports",
|
|
486
|
+
key: "weekly/private-summary.json",
|
|
487
|
+
body: Buffer.from(JSON.stringify({ ok: true, scope: "internal" })),
|
|
488
|
+
contentType: "application/json",
|
|
489
|
+
access: "private",
|
|
480
490
|
encrypt: true,
|
|
481
491
|
});
|
|
482
492
|
|
|
493
|
+
console.log(uploaded.key);
|
|
494
|
+
console.log(uploaded.access);
|
|
495
|
+
console.log(uploaded.url);
|
|
496
|
+
|
|
483
497
|
const meta = await storage.headObject({ bucket: "reports", key: "weekly/summary.json" });
|
|
498
|
+
console.log(meta.access, meta.url);
|
|
499
|
+
|
|
484
500
|
const downloaded = await storage.getObject({ bucket: "reports", key: "weekly/summary.json", decrypt: true });
|
|
485
501
|
|
|
502
|
+
const listed = await storage.listObjects({ bucket: "reports", prefix: "weekly/" });
|
|
503
|
+
console.log(listed.objects[0]?.access, listed.objects[0]?.url);
|
|
504
|
+
|
|
486
505
|
await storage.deleteObjects({ bucket: "reports", keys: ["weekly/summary.json"] });
|
|
487
506
|
```
|
|
488
507
|
|
|
@@ -495,6 +514,7 @@ const signedUpload = await admin.createSignedUrl({
|
|
|
495
514
|
action: AdminStorageSignedAction.Upload,
|
|
496
515
|
expiresInSeconds: 300,
|
|
497
516
|
contentType: "video/mp4",
|
|
517
|
+
access: "private",
|
|
498
518
|
encrypt: true,
|
|
499
519
|
});
|
|
500
520
|
|
|
@@ -515,6 +535,8 @@ const signedDownload = await admin.createSignedUrl({
|
|
|
515
535
|
```
|
|
516
536
|
|
|
517
537
|
Notes:
|
|
538
|
+
- `putObject()` defaults to `encrypt: false` and `access: "public"`.
|
|
539
|
+
- Upload, head, and list responses all surface `access` and `url` so you can carry public/private intent alongside the object key.
|
|
518
540
|
- `forceDownload` and `embedOnly` are mutually exclusive.
|
|
519
541
|
- `allowedOrigins` defaults to `['*']` if omitted.
|
|
520
542
|
|
package/dist/db/Collection.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdminBulkWriteOptions, AdminBulkWriteResult, AdminUpdateManyItem,
|
|
1
|
+
import { AdminBulkWriteOptions, AdminBulkWriteResult, AdminUpdateManyItem, AggregateSpec, FlareAdminConfig, HavingClause, JoinClause, StructuredQuery, VectorSearchClause, WhereCondition } from "../types";
|
|
2
2
|
import { AdminDocumentReference } from "./Document";
|
|
3
3
|
export declare class AdminCollectionReference<T = Record<string, unknown>> {
|
|
4
4
|
private readonly cfg;
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var
|
|
2
|
-
var Se=()=>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,p=Se();var V=(i=>(i.Upload="upload",i.Download="download",i.Delete="delete",i.Edit="edit",i))(V||{});function W(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:we(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 we(r){return isNaN(Number(r))?r==="true"?true:r==="false"?false:r==="null"?null:r:Number(r)}function Z(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}function Ce(r,e){let t=r.dataMapper;if(!t||typeof t!="object")return null;let n=t[e];return typeof n=="function"?n:null}function X(r,e,t){let n=Ce(r,e);if(!n||t==null||typeof t!="object")return t;try{return n(t)}catch{return t}}function Y(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=>Y(r,c,o)):a&&typeof a=="object"&&(d=Y(r,a,o)),d=Array.isArray(d)?d.map(c=>X(r,s,c)):X(r,s,d),d!==a&&(n===e&&(n={...n}),n[s]=d);}return n}function v(r,e,t,n){let i=Array.isArray(n?.joins)?n.joins:[],s=o=>{let a=Y(r,o,i);return X(r,e,a)};return Array.isArray(t)?t.map(o=>s(o)):s(t)}var Re=()=>typeof process<"u"&&!!process.versions?.node,h=r=>{if(r.transport==="http")return false;let e=!!(r.grpcUrl&&r.grpcUrl.trim().length>0),t=Re();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},B=r=>{try{return JSON.stringify(r??{})}catch{return "{}"}},F=r=>r?.field&&r?.op?{queryFilter:{field:String(r.field),op:String(r.op),valueJson:B(r.value)}}:Array.isArray(r?.or)?{orFilter:{or:r.or.map(e=>F(e))}}:Array.isArray(r?.and)?{andFilter:{and:r.and.map(e=>F(e))}}:{queryFilter:{field:"",op:"==",valueJson:"null"}},H=r=>{if(!(!r||!Array.isArray(r.values)))return {valuesJson:r.values.map(e=>B(e))}},ae=r=>({from:r.from,localField:r.localField,foreignField:r.foreignField,as:r.as,single:!!r.single,where:Array.isArray(r.where)?r.where.map(F):[],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(ae):[]}),Oe=r=>({where:Array.isArray(r.where)?r.where.map(F):[],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:H(r.startAt),startAfter:H(r.startAfter),endAt:H(r.endAt),endBefore:H(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(ae):[],select:Array.isArray(r.select)?r.select:[],distinctField:r.distinctField??""});async function k(r){let e=await import('@grpc/grpc-js'),t=await import('@grpc/proto-loader'),n=P__default.default.dirname(url.fileURLToPath(p)),i=[P__default.default.resolve(n,"../../proto"),P__default.default.resolve(n,"../proto"),P__default.default.resolve(process.cwd(),"proto")],s=i.find(m=>ve__default.default.existsSync(P__default.default.join(m,"flare.proto")))??i[0],o=P__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 S(r,e,t){return new Promise((n,i)=>{r[e](t,(s,o)=>{if(s)return i(s);n(o??{});});})}function w(r,e){if(r.error)throw new Error(`[flare-admin][grpc] ${e} failed: ${r.errorDescription||r.error}`)}async function ce(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(n,"AdminQuery",{app_id:r.appId,admin_key:r.adminKey,collection:e,query:Oe(t)});w(i,"admin_query");try{let s=JSON.parse(i.dataJson||"[]");return Array.isArray(s)?s:[]}catch{return []}}async function de(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(n,"CreateCustomToken",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",claims_json:B(t.claims??{}),ttl:t.ttl??r.defaultTtl});if(w(i,"create_custom_token"),!i.token)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return String(i.token)}async function le(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(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 w(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 ue(r,e,t){if(!h(r))return;let n=await k(r.grpcUrl),i=await S(n,"GetDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});if(w(i,"get_document"),!i.found)return null;try{return JSON.parse(i.dataJson||"{}")}catch{return {}}}async function me(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(n,"CreateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,data_json:B(t)});return w(i,"create_document"),String(i.id??"")}async function pe(r,e,t,n){if(!h(r))return null;let i=await k(r.grpcUrl),s=await S(i,"ReplaceDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:B(n)});return w(s,"replace_document"),true}async function ge(r,e,t,n){if(!h(r))return null;let i=await k(r.grpcUrl),s=await S(i,"UpdateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:B(n)});return w(s,"update_document"),true}async function he(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(n,"DeleteDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});return w(i,"delete_document"),!!i.deleted}async function fe(r,e,t){if(!h(r))return null;let n=await k(r.grpcUrl),i=await S(n,"DeleteMany",{app_id:r.appId,admin_key:r.adminKey,collection:e,where:(t??[]).map(F)});return w(i,"delete_many"),Number(i.deleted??0)}var Ae=r=>r.replace(/\/$/,""),Ie=r=>{let e=String(r.httpBase??"").trim();return Ae(e||r.serverUrl)},A=(r,e)=>{let t=Ie(r),n=e.startsWith("/")?e:`/${e}`;return `${t}${n}`};var O=class{constructor(e,t,n){this.cfg=e;this.collection=t;this.id=n;}get baseUrl(){return A(this.cfg,`/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 ue(this.cfg,this.collection,this.id);if(e!==void 0)return e===null?null:v(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 v(this.cfg,this.collection,n.data)??null}async set(e){await pe(this.cfg,this.collection,this.id,e)===null&&await this.request("PUT",e);}async update(e){await ge(this.cfg,this.collection,this.id,e)===null&&await this.request("PATCH",e);}async delete(){await he(this.cfg,this.collection,this.id)===null&&await this.request("DELETE");}parent(){return new I(this.cfg,this.collection)}};var I=class r{constructor(e,t){this.cfg=e;this.name=t;this.sq={};this.opts={allowSensitiveAuthUserFields:true};}get baseUrl(){return A(this.cfg,`/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 W(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 ce(this.cfg,this.name,this.sq);if(e)return v(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 v(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 me(this.cfg,this.name,e);if(t!==null)return new O(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 O(this.cfg,this.name,i.id)}async update(e,t){let n=this.doc(e);return await n.update(t),n}ensureBulkOptions(e){let t=Number(e?.batchSize??250),n=Number(e?.concurrency??1);return {...e,batchSize:Number.isFinite(t)&&t>0?Math.floor(t):250,concurrency:Number.isFinite(n)&&n>0?Math.floor(n):1,continueOnError:e?.continueOnError===true}}toPercent(e,t){if(!(typeof t!="number"||t<=0))return Math.round(e/t*100)}emitBulkProgress(e,t,n){n&&n({operation:e,...t,percent:this.toPercent(t.processed,t.total)});}async*chunkIterable(e,t){let n=[];for await(let i of e)n.push(i),n.length>=t&&(yield n,n=[]);n.length>0&&(yield n);}assertBulkSignal(e){if(e?.aborted)throw new Error("Bulk write aborted")}async runChunkWorkers(e,t,n,i,s,o,a=false,d){let c=0,m=async()=>{for(;c<t.length;){this.assertBulkSignal(d);let f=c;c+=1;let R=t[f];try{let b=await i(R);s.succeeded+=1,s.processed+=1,this.emitBulkProgress(e,{processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total,lastDocId:b.docId},o);}catch(b){if(s.failed+=1,s.processed+=1,this.emitBulkProgress(e,{processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total,lastError:b},o),!a)throw b}}},u=Math.max(1,Math.min(n,t.length));await Promise.all(Array.from({length:u},()=>m()));}async runBulkWrite(e,t,n,i){let s=this.ensureBulkOptions(i);this.assertBulkSignal(s.signal);let o={processed:0,succeeded:0,failed:0,total:Array.isArray(t)?t.length:void 0};this.emitBulkProgress(e,{processed:0,succeeded:0,failed:0,total:o.total},s.onProgress);for await(let a of this.chunkIterable(t,s.batchSize))this.assertBulkSignal(s.signal),await this.runChunkWorkers(e,a,s.concurrency,n,o,s.onProgress,s.continueOnError,s.signal);return {operation:e,processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total}}async addMany(e,t){return this.runBulkWrite("addMany",e,async n=>({docId:(await this.add(n)).id}),t)}async updateMany(e,t){return this.runBulkWrite("updateMany",e,async n=>(await this.doc(n.id).update(n.data),{docId:n.id}),t)}async deleteMany(e,t){return e==null?this.deleteManyByQuery():this.runBulkWrite("deleteMany",e,async n=>(await this.doc(n).delete(),{docId:n}),t)}async deleteManyByQuery(){let e=await fe(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 O(this.cfg,this.name,e)}};var x=class{constructor(e){this.cfg=e;}collection(e){return new I(this.cfg,e)}};var _=class{constructor(e){this.cfg=e;}async createCustomToken(e,t={}){if(h(this.cfg)){let a=await de(this.cfg,String(e),t);if(!a)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return a}let n=A(this.cfg,"/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
|
|
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 E=class{constructor(e){this.cfg=e;}get baseUrl(){return A(this.cfg,`/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 G=class{constructor(e){this.cfg=e;}base(e){return A(this.cfg,`/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 ee(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 Pe(r){return r===void 0?"":typeof r=="string"?ee(new TextEncoder().encode(r)):Buffer&&Buffer.isBuffer(r)?r.toString("base64"):r instanceof Uint8Array?ee(r):r instanceof ArrayBuffer?ee(new Uint8Array(r)):""}function Be(r){return Buffer?Buffer.from(String(r)).toString("base64"):btoa(String(r))}function je(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 Fe(r){return (String(r??"").split("/").pop()??"download").replace(/["\\\r\n]/g,"")||"download"}var D=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 u=(await this.listBuckets()).find(f=>f.id===c);if(u)return u}}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}),m;typeof e.body=="string"?m=new TextEncoder().encode(e.body):m=e.body;let u=await fetch(c.url,{method:c.method??"PUT",headers:{...e.contentType?{"Content-Type":e.contentType}:{}},body:m});if(!u.ok){let f=await u.text().catch(()=>"");throw new Error(`[flare-admin] Signed-URL upload failed (HTTP ${u.status}): ${f}`)}return {ok:true,bucket:e.bucket,key:e.key,size:s??0,encrypted:!!(e.encrypt??true)}}let a=await Pe(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??Fe(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?je(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?Be(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 q=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 U=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 W(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 q(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}stream(e={}){let t=this._buildSq(),n=new Set,i=[],s=new Map,o=Math.max(0,Number(e.flushMs??24)),a=Math.max(1,Number(e.maxBatchSize??200)),d=e.insertAt??"end",c=typeof e.maxDocs=="number"&&e.maxDocs>0?Math.floor(e.maxDocs):void 0,m=String(e.idField??"id"),u=[],f=false,R=false,b=0,j,$=()=>{s.clear();for(let l=0;l<u.length;l+=1){let g=ne(u[l]);g&&s.set(g,l);}},ne=(l,g)=>{if(g)return g;if(l==null)return;if(typeof e.getId=="function"){let C=e.getId(l);if(typeof C=="string"&&C.length>0)return C}let y=l?.[m]??l?._id??l?.docId;if(typeof y=="string"&&y.length>0)return y},re=()=>{c==null||u.length<=c||(u=u.slice(0,c));},ie=()=>{typeof e.sort=="function"&&(u=u.slice().sort(e.sort));},se=(l,g)=>{b+=1;let y=u.slice(),C={reason:l,batchSize:g,version:b,ready:R};for(let M of Array.from(n))try{M(y,C);}catch{}},z=()=>{j!=null&&(clearTimeout(j),j=void 0);},be=l=>{if(l.operation==="delete"){let M=s.get(l.docId??"");if(M==null)return;u.splice(M,1),$();return}let g=l.data;if(g==null)return;let y=ne(g,l.docId);if(!y)return;let C=s.get(y);if(typeof C=="number"){u[C]=g;return}d==="start"?u.unshift(g):u.push(g),re(),$();},oe=()=>{if(f||i.length===0)return;z();let l=i.splice(0,i.length);for(let g of l)be(g);ie(),$(),se("change-batch",l.length);},ke=()=>{f||j!=null||(j=setTimeout(oe,o));},Q=this.conn.subscribe(this.name,void 0,t,l=>{if(!f){if(l.type==="snapshot"){u=Array.isArray(l.data)?[...l.data]:[],R=true,z(),i.length=0,ie(),re(),$(),se("snapshot",0);return}if(i.push({docId:l.docId,operation:l.operation,data:l.data??null}),i.length>=a){oe();return}ke();}}),K={subscribe(l,g=true){if(n.add(l),g){let y={reason:R?"change-batch":"snapshot",batchSize:0,version:b,ready:R};try{l(u.slice(),y);}catch{}}return ()=>{n.delete(l);}},getSnapshot(){return u.slice()},isReady(){return R},getVersion(){return b},close:()=>{f||(f=true,z(),i.length=0,n.clear(),Q());},onError(l){return Q.onError(l),K},onPermissionDenied(l){return Q.onPermissionDenied(l),K}};return K}asStore(e={}){let t=this.stream(e);return {subscribe:n=>t.subscribe(()=>{n();},false),getSnapshot:()=>t.getSnapshot(),getServerSnapshot:()=>[],stream:t,destroy:()=>{t.close();}}}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 L=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;this._state="disconnected";this._stateListeners=[];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._setState("connecting"),this._connect();}ready(){return this._readyPromise}get connectionState(){return this._state}onConnectionStateChange(e){return this._stateListeners.push(e),()=>{this._stateListeners=this._stateListeners.filter(t=>t!==e);}}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false,this._setState("disconnected");}send(e,t){return new Promise((n,i)=>{let s=Z(),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===ye__default.default.OPEN?d():this.ready().then(d).catch(i);})}subscribe(e,t,n,i,s={}){let o=Z(),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 u=this.activeSubscriptions.get(o)?.liveId??o;this.activeSubscriptions.delete(o),this.subscriptions.delete(o),this.subscriptions.delete(u),this.subscriptionErrorHandlers.delete(o),this.subscriptionPermissionHandlers.delete(o),this.subscriptionLastErrors.delete(o),this.connected&&this.send("unsubscribe",{subscriptionId:u}).catch(()=>{});},c=d;return c.unsubscribe=d,c.onError=m=>{this.subscriptionErrorHandlers.get(o)?.add(m);let u=this.subscriptionLastErrors.get(o);if(u)try{m(u);}catch{}return c},c.onPermissionDenied=m=>{this.subscriptionPermissionHandlers.get(o)?.add(m);let u=this.subscriptionLastErrors.get(o);if(u?.permissionDenied)try{m(u);}catch{}return c},c.catch=m=>c.onError(m),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{}}}_setState(e){if(this._state!==e){this._state=e;for(let t of this._stateListeners.slice())try{t(e);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new ye__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?(this._setState("reconnecting"),setTimeout(()=>{this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this._connect();},this.reconnectDelay)):this._setState("disconnected");}),this.ws.on("error",()=>{this._setState("error");});}_handle(e){let t=e.type;if(t==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._setState("connected"),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:v(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 N=class{constructor(e){this._ws=new L(e);}collection(e){return new U(this._ws,e)}ready(){return this._ws.ready()}get connectionState(){return this._ws.connectionState}onConnectionStateChange(e){return this._ws.onConnectionStateChange(e)}disconnect(){this._ws.disconnect();}};var mn="ServerTimeStamp",pn={$serverTimestamp:true};var te=class{constructor(e){this.cfg={defaultTtl:"24h",transport:"auto",...e,serverUrl:e.serverUrl.replace(/\/$/,""),httpBase:e.httpBase?.replace(/\/$/,"")??"",grpcUrl:e.grpcUrl??"",dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new _(this.cfg))}db(){return this._db??(this._db=new x(this.cfg))}generateFlareId(){return crypto.randomUUID().replace(/-/g,"").substring(0,20)}doc(e){let t=this.generateFlareId(),n=this.db().collection(e).doc(t);return n.id=t,n}live(){return this._conn??(this._conn=new N(this.cfg))}notifications(){return this._notifications??(this._notifications=new E(this.cfg))}storageService(){return this._storage??(this._storage=new G(this.cfg))}storage(){return this._storageS3||(this._storageS3=new D(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)}onConnectionStateChange(e){return this.live().onConnectionStateChange(e)}disconnect(){this._conn?.disconnect(),this._conn=void 0;}},T=new Map;function Sn(r,e="[DEFAULT]"){if(T.has(e))return T.get(e);let t=new te(r);return T.set(e,t),t}function J(r="[DEFAULT]"){let e=T.get(r);if(!e)throw new Error(`[flare-admin] No app named "${r}" found. Call connectApp() before getApp().`);return e}function wn(r="[DEFAULT]"){let e=T.get(r);return e?(e.disconnect(),T.delete(r),true):false}function Cn(){for(let r of T.values())r.disconnect();T.clear();}function vn(r="[DEFAULT]"){return J(r).auth()}function Tn(r="[DEFAULT]"){return J(r).db()}function Rn(r="[DEFAULT]"){return J(r).live()}function On(r="[DEFAULT]"){return J(r).notifications()}function In(r="[DEFAULT]"){return J(r).storage()}exports.AdminCollectionReference=I;exports.AdminDocumentReference=O;exports.AdminLiveCollectionReference=U;exports.AdminLiveDocumentReference=q;exports.AdminStorageSignedAction=V;exports.FlareAdminApp=te;exports.FlareAdminAuthService=_;exports.FlareAdminConnection=N;exports.FlareAdminDbService=x;exports.FlareAdminNotificationsService=E;exports.FlareAdminStorageS3=D;exports.FlareAdminWsConnection=L;exports.ServerTimeStamp=mn;exports.ServerTimeStampField=pn;exports.auth=vn;exports.connectApp=Sn;exports.db=Tn;exports.disconnectAllApps=Cn;exports.disconnectApp=wn;exports.getApp=J;exports.live=Rn;exports.notifications=On;exports.storage=In;
|
|
1
|
+
'use strict';var De=require('fs'),D=require('path'),url=require('url'),Ie=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var De__default=/*#__PURE__*/_interopDefault(De);var D__default=/*#__PURE__*/_interopDefault(D);var Ie__default=/*#__PURE__*/_interopDefault(Ie);/* @zuzjs/flare-admin */
|
|
2
|
+
var Be=()=>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,p=Be();var oe=(i=>(i.Upload="upload",i.Download="download",i.Delete="delete",i.Edit="edit",i))(oe||{});var xe={id:"_id",createdAt:"_createdAt",updatedAt:"_updatedAt"},fe={_id:"id",_createdAt:"createdAt",_updatedAt:"updatedAt"},E=r=>!!r&&typeof r=="object"&&!Array.isArray(r),B=(r,e)=>Object.keys(r).length===1&&Object.prototype.hasOwnProperty.call(r,e),V=r=>{if(r instanceof Date)return r.toISOString();if(Array.isArray(r))return r.map(t=>V(t));if(!E(r))return r;if(B(r,"$date"))return {$date:V(r.$date)};let e={};for(let[t,n]of Object.entries(r))e[t]=V(n);return e},h=r=>{let e=String(r??"").trim();return e&&(xe[e]??e)},je=r=>{let e=String(r??"").trim();return e&&(fe[e]?fe[e]:e.startsWith("_")&&!e.startsWith("__")&&e.length>1?e.slice(1):e)},_e=r=>"field"in r&&"op"in r,w=r=>{if(r instanceof Date)return {$date:r.toISOString()};if(Array.isArray(r))return r.map(t=>w(t));if(!E(r))return r;if(B(r,"$oid"))return {$oid:String(r.$oid??"")};if(B(r,"$date"))return {$date:V(r.$date)};let e={};for(let[t,n]of Object.entries(r)){let i=h(t);if(i==="_id"){if(typeof n=="string"){e[i]={$oid:n};continue}if(E(n)&&B(n,"$oid")){e[i]={$oid:String(n.$oid??"")};continue}}e[i]=w(n);}return e},Z=r=>{if(Array.isArray(r))return r.map(t=>Z(t));if(!E(r))return r;if(B(r,"$oid"))return String(r.$oid??"");if(B(r,"$date")){let t=r.$date;if(t instanceof Date)return Number.isNaN(t.getTime())?null:t;if(typeof t=="string"||typeof t=="number"){let n=new Date(t);return Number.isNaN(n.getTime())?null:n}if(E(t)&&typeof t.$numberLong=="string"){let n=Number(t.$numberLong);if(!Number.isFinite(n))return null;let i=new Date(n);return Number.isNaN(i.getTime())?null:i}return null}let e={};for(let[t,n]of Object.entries(r)){let i=je(t);if(t==="_id"){if(typeof n=="string"){e.id=n;continue}if(E(n)&&B(n,"$oid")){e.id=String(n.$oid??"");continue}}e[i]=Z(n);}return e},I=r=>"or"in r&&Array.isArray(r.or)?{...r,or:r.or.map(e=>I(e))}:"and"in r&&Array.isArray(r.and)?{...r,and:r.and.map(e=>I(e))}:_e(r)?{...r,field:h(r.field),value:w(r.value)}:r,X=r=>{if(!r||typeof r!="object")return r;let e=r,t={...e},n=i=>{let o={...i};return o.localField=h(String(i?.localField??"")),o.foreignField=h(String(i?.foreignField??"")),Array.isArray(i.where)&&(o.where=i.where.map(s=>I(s))),Array.isArray(i.orderBy)&&(o.orderBy=i.orderBy.map(s=>({...s,field:h(String(s?.field??""))}))),i.groupBy&&typeof i.groupBy=="object"&&Array.isArray(i.groupBy.fields)&&(o.groupBy={...i.groupBy,fields:i.groupBy.fields.map(s=>h(String(s??"")))}),Array.isArray(i.having)&&(o.having=i.having.map(s=>({...s,field:h(String(s?.field??""))}))),Array.isArray(i.select)&&(o.select=i.select.map(s=>h(String(s??"")))),typeof i.distinctField=="string"&&(o.distinctField=h(i.distinctField)),i.vectorSearch&&typeof i.vectorSearch=="object"&&(o.vectorSearch={...i.vectorSearch,field:h(String(i.vectorSearch.field??""))}),Array.isArray(i.joins)&&(o.joins=i.joins.map(s=>n(s))),o};return Array.isArray(e.where)&&(t.where=e.where.map(i=>I(i))),Array.isArray(e.orderBy)&&(t.orderBy=e.orderBy.map(i=>({...i,field:h(String(i?.field??""))}))),e.groupBy&&typeof e.groupBy=="object"&&Array.isArray(e.groupBy.fields)&&(t.groupBy={...e.groupBy,fields:e.groupBy.fields.map(i=>h(String(i??"")))}),Array.isArray(e.having)&&(t.having=e.having.map(i=>({...i,field:h(String(i?.field??""))}))),Array.isArray(e.select)&&(t.select=e.select.map(i=>h(String(i??"")))),typeof e.distinctField=="string"&&(t.distinctField=h(e.distinctField)),e.vectorSearch&&typeof e.vectorSearch=="object"&&(t.vectorSearch={...e.vectorSearch,field:h(String(e.vectorSearch.field??""))}),Array.isArray(e.joins)&&(t.joins=e.joins.map(i=>n(i))),t};function Ee(r,e){let t=r.dataMapper;if(!t||typeof t!="object")return null;let n=t[e];return typeof n=="function"?n:null}function se(r,e,t){let n=Ee(r,e);if(!n||t==null||typeof t!="object")return t;try{return n(t)}catch{return t}}function ae(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 o=String(i?.as??"").trim();if(!o)continue;let s=Array.isArray(i?.joins)?i.joins:[],a=n[o],l=a;Array.isArray(a)?l=a.map(c=>ae(r,c,s)):a&&typeof a=="object"&&(l=ae(r,a,s)),l=Array.isArray(l)?l.map(c=>se(r,o,c)):se(r,o,l),l!==a&&(n===e&&(n={...n}),n[o]=l);}return n}function F(r,e,t,n){let i=Array.isArray(n?.joins)?n.joins:[],o=s=>{let a=ae(r,Z(s),i);return se(r,e,a)};return Array.isArray(t)?t.map(s=>o(s)):o(t)}var Le=()=>typeof process<"u"&&!!process.versions?.node,S=r=>{if(r.transport==="http")return false;let e=!!(r.grpcUrl&&r.grpcUrl.trim().length>0),t=Le();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},q=r=>{try{return JSON.stringify(r??{})}catch{return "{}"}},U=r=>r?.field&&r?.op?{queryFilter:{field:String(r.field),op:String(r.op),valueJson:q(r.value)}}:Array.isArray(r?.or)?{orFilter:{or:r.or.map(e=>U(e))}}:Array.isArray(r?.and)?{andFilter:{and:r.and.map(e=>U(e))}}:{queryFilter:{field:"",op:"==",valueJson:"null"}},Y=r=>{if(!(!r||!Array.isArray(r.values)))return {valuesJson:r.values.map(e=>q(e))}},Ae=r=>({from:r.from,localField:r.localField,foreignField:r.foreignField,as:r.as,single:!!r.single,where:Array.isArray(r.where)?r.where.map(U):[],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(Ae):[]}),Ue=r=>({where:Array.isArray(r.where)?r.where.map(U):[],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:Y(r.startAt),startAfter:Y(r.startAfter),endAt:Y(r.endAt),endBefore:Y(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(Ae):[],select:Array.isArray(r.select)?r.select:[],distinctField:r.distinctField??""});async function v(r){let e=await import('@grpc/grpc-js'),t=await import('@grpc/proto-loader'),n=D__default.default.dirname(url.fileURLToPath(p)),i=[D__default.default.resolve(n,"../../proto"),D__default.default.resolve(n,"../proto"),D__default.default.resolve(process.cwd(),"proto")],o=i.find(m=>De__default.default.existsSync(D__default.default.join(m,"flare.proto")))??i[0],s=D__default.default.join(o,"flare.proto"),a=await t.load(s,{keepCase:false,longs:String,enums:String,defaults:true,oneofs:true,includeDirs:[o]}),c=e.loadPackageDefinition(a).flare;return new c.AdminService(r,e.credentials.createInsecure())}function T(r,e,t){return new Promise((n,i)=>{r[e](t,(o,s)=>{if(o)return i(o);n(s??{});});})}function R(r,e){if(r.error)throw new Error(`[flare-admin][grpc] ${e} failed: ${r.errorDescription||r.error}`)}async function ye(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(n,"AdminQuery",{app_id:r.appId,admin_key:r.adminKey,collection:e,query:Ue(X(t))});R(i,"admin_query");try{let o=JSON.parse(i.dataJson||"[]");return Array.isArray(o)?o:[]}catch{return []}}async function be(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(n,"CreateCustomToken",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",claims_json:q(t.claims??{}),ttl:t.ttl??r.defaultTtl});if(R(i,"create_custom_token"),!i.token)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return String(i.token)}async function ke(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(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 R(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 Se(r,e,t){if(!S(r))return;let n=await v(r.grpcUrl),i=await T(n,"GetDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});if(R(i,"get_document"),!i.found)return null;try{return JSON.parse(i.dataJson||"{}")}catch{return {}}}async function we(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(n,"CreateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,data_json:q(w(t))});return R(i,"create_document"),String(i.id??"")}async function Ce(r,e,t,n){if(!S(r))return null;let i=await v(r.grpcUrl),o=await T(i,"ReplaceDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:q(w(n))});return R(o,"replace_document"),true}async function ve(r,e,t,n){if(!S(r))return null;let i=await v(r.grpcUrl),o=await T(i,"UpdateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:q(w(n))});return R(o,"update_document"),true}async function Te(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(n,"DeleteDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});return R(i,"delete_document"),!!i.deleted}async function Re(r,e,t){if(!S(r))return null;let n=await v(r.grpcUrl),i=await T(n,"DeleteMany",{app_id:r.appId,admin_key:r.adminKey,collection:e,where:(t??[]).map(o=>U(I(o)))});return R(i,"delete_many"),Number(i.deleted??0)}var Oe=r=>r.replace(/\/$/,""),$e=r=>{let e=String(r.httpBase??"").trim();return Oe(e||r.serverUrl)},y=(r,e)=>{let t=$e(r),n=e.startsWith("/")?e:`/${e}`;return `${t}${n}`};function ee(r){let e=[];for(let[t,n]of Object.entries(r))if(typeof n=="string"){let i=n.match(/^(>=|<=|!=|>|<|==)\s*(.+)$/);if(i){let[,o,s]=i;e.push({field:t,op:o,value:Ne(s.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 Ne(r){return isNaN(Number(r))?r==="true"?true:r==="false"?false:r==="null"?null:r:Number(r)}function ce(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}var x=class{constructor(e,t,n){this.cfg=e;this.collection=t;this.id=n;}get baseUrl(){return y(this.cfg,`/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(w(t))}:{}});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (${e} ${this.baseUrl}): ${s}`)}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 Se(this.cfg,this.collection,this.id);if(e!==void 0)return e===null?null:F(this.cfg,this.collection,e)??null;let t;try{t=await fetch(this.baseUrl,{headers:this.headers});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${s}`)}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 F(this.cfg,this.collection,n.data)??null}async set(e){await Ce(this.cfg,this.collection,this.id,e)===null&&await this.request("PUT",e);}async update(e){await ve(this.cfg,this.collection,this.id,e)===null&&await this.request("PATCH",e);}async delete(){await Te(this.cfg,this.collection,this.id)===null&&await this.request("DELETE");}parent(){return new j(this.cfg,this.collection)}};var j=class r{constructor(e,t){this.cfg=e;this.name=t;this.sq={};this.opts={allowSensitiveAuthUserFields:true};}get baseUrl(){return y(this.cfg,`/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 ee(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 o=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[o,...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 o=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(o.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let s=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(o,i,s))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:o})}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 ye(this.cfg,this.name,this.sq);if(e)return F(this.cfg,this.name,e,this.sq)??[];let t=new URL(this.baseUrl);t.searchParams.set("query",JSON.stringify(X(this.sq))),t.searchParams.set("allowSensitiveAuthUserFields",this.opts.allowSensitiveAuthUserFields?"1":"0");let n;try{n=await fetch(t.toString(),{headers:this.headers});}catch(s){let a=s instanceof Error?s.message:String(s);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 F(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 we(this.cfg,this.name,e);if(t!==null)return new x(this.cfg,this.name,t);let n;try{n=await fetch(this.baseUrl,{method:"POST",headers:this.headers,body:JSON.stringify(w(e))});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}): ${s}`)}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 x(this.cfg,this.name,i.id)}async update(e,t){let n=this.doc(e);return await n.update(t),n}ensureBulkOptions(e){let t=Number(e?.batchSize??250),n=Number(e?.concurrency??1);return {...e,batchSize:Number.isFinite(t)&&t>0?Math.floor(t):250,concurrency:Number.isFinite(n)&&n>0?Math.floor(n):1,continueOnError:e?.continueOnError===true}}toPercent(e,t){if(!(typeof t!="number"||t<=0))return Math.round(e/t*100)}emitBulkProgress(e,t,n){n&&n({operation:e,...t,percent:this.toPercent(t.processed,t.total)});}async*chunkIterable(e,t){let n=[];for await(let i of e)n.push(i),n.length>=t&&(yield n,n=[]);n.length>0&&(yield n);}assertBulkSignal(e){if(e?.aborted)throw new Error("Bulk write aborted")}async runChunkWorkers(e,t,n,i,o,s,a=false,l){let c=0,m=async()=>{for(;c<t.length;){this.assertBulkSignal(l);let A=c;c+=1;let b=t[A];try{let k=await i(b);o.succeeded+=1,o.processed+=1,this.emitBulkProgress(e,{processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total,lastDocId:k.docId},s);}catch(k){if(o.failed+=1,o.processed+=1,this.emitBulkProgress(e,{processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total,lastError:k},s),!a)throw k}}},d=Math.max(1,Math.min(n,t.length));await Promise.all(Array.from({length:d},()=>m()));}async runBulkWrite(e,t,n,i){let o=this.ensureBulkOptions(i);this.assertBulkSignal(o.signal);let s={processed:0,succeeded:0,failed:0,total:Array.isArray(t)?t.length:void 0};this.emitBulkProgress(e,{processed:0,succeeded:0,failed:0,total:s.total},o.onProgress);for await(let a of this.chunkIterable(t,o.batchSize))this.assertBulkSignal(o.signal),await this.runChunkWorkers(e,a,o.concurrency,n,s,o.onProgress,o.continueOnError,o.signal);return {operation:e,processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total}}async addMany(e,t){return this.runBulkWrite("addMany",e,async n=>({docId:(await this.add(n)).id}),t)}async updateMany(e,t){return this.runBulkWrite("updateMany",e,async n=>(await this.doc(n.id).update(n.data),{docId:n.id}),t)}async deleteMany(e,t){return e==null?this.deleteManyByQuery():this.runBulkWrite("deleteMany",e,async n=>(await this.doc(n).delete(),{docId:n}),t)}async deleteManyByQuery(){let e=await Re(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??[]).map(i=>I(i))})});}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (DELETE ${this.baseUrl}): ${o}`)}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 x(this.cfg,this.name,e)}};var $=class{constructor(e){this.cfg=e;}collection(e){return new j(this.cfg,e)}};var N=class{constructor(e){this.cfg=e;}async createCustomToken(e,t={}){if(S(this.cfg)){let a=await be(this.cfg,String(e),t);if(!a)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return a}let n=y(this.cfg,"/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}),o;try{o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(a){let l=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Could not reach FlareServer at "${n}": ${l}
|
|
3
|
+
Make sure FLARE_URL is set correctly and the server is running.`)}let s;try{s=await o.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${o.status})`)}if(!o.ok)throw new Error(`[flare-admin] createCustomToken failed (HTTP ${o.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,t={}){if(S(this.cfg)){let l=await ke(this.cfg,String(e),t);if(!l)throw new Error("[flare-admin][grpc] create_auth_ticket returned empty payload");return l}let n=y(this.cfg,"/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}),o;try{o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(l){let c=l instanceof Error?l.message:String(l);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 s;try{s=await o.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${o.status})`)}if(!o.ok)throw new Error(`[flare-admin] getTicket failed (HTTP ${o.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??t.role??"user"),ip:String(a.ip??"unknown")}}};var J=class{constructor(e){this.cfg=e;}get baseUrl(){return y(this.cfg,`/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 o=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}/send): ${o}`)}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 te=class{constructor(e){this.cfg=e;}base(e){return y(this.cfg,`/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,o=this.base(t);try{i=await fetch(o,{method:e,headers:this.headers,...n!==void 0?{body:JSON.stringify(n)}:{}});}catch(a){let l=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Network error (${e} ${o}): ${l}`)}let s=await i.json().catch(()=>({}));if(!i.ok)throw new Error(`[flare-admin] ${e} ${o} failed (HTTP ${i.status}): `+(s.error??"Unknown error"));return s}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 de(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 Je(r){return r===void 0?"":typeof r=="string"?de(new TextEncoder().encode(r)):Buffer&&Buffer.isBuffer(r)?r.toString("base64"):r instanceof Uint8Array?de(r):r instanceof ArrayBuffer?de(new Uint8Array(r)):""}function Me(r){return Buffer?Buffer.from(String(r)).toString("base64"):btoa(String(r))}function We(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 He(r){return (String(r??"").split("/").pop()??"download").replace(/["\\\r\n]/g,"")||"download"}var M=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 l=(await this.listBuckets()).find(c=>c.id===i);if(l)return l}let o;try{o=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 d=(await this.listBuckets()).find(A=>A.id===c);if(d)return d}}throw a}let s={id:o.serverId,name:n,bucket:n,kind:t.kind??"managed",prefix:t.prefix};return this._bucketCache.set(n,s.id),s}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(o){n[i]=o instanceof Error?o.message:String(o);}})),{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),n=e.encrypt??false,i=e.access??"public";if(e.contentBase64!==void 0){let d=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:e.contentBase64,contentType:e.contentType,access:i,encrypt:n});return {ok:d.ok,bucket:e.bucket,key:String(d.path??e.key),access:String(d.access??i),url:typeof d.url=="string"?d.url:void 0,size:Number(d.size??0),encrypted:!!d.encrypted}}let o=4*1024*1024,s=e.base64MaxBytes??o,a;if(typeof e.body=="string"?a=new TextEncoder().encode(e.body).length:(e.body instanceof Uint8Array||e.body instanceof ArrayBuffer||Buffer&&Buffer.isBuffer(e.body))&&(a=e.body.byteLength),a!==void 0&&a>s){let d=await this.createSignedUrl({bucket:e.bucket,key:e.key,action:"upload",expiresInSeconds:300,sizeBytes:a,contentType:e.contentType,access:i,encrypt:n}),A;typeof e.body=="string"?A=new TextEncoder().encode(e.body):A=e.body;let b=await fetch(d.url,{method:d.method??"PUT",headers:{...e.contentType?{"Content-Type":e.contentType}:{}},body:A});if(!b.ok){let _=await b.text().catch(()=>"");throw new Error(`[flare-admin] Signed-URL upload failed (HTTP ${b.status}): ${_}`)}let k=await b.text().catch(()=>""),f={};if(k)try{f=JSON.parse(k);}catch{throw new Error("[flare-admin] Failed to parse signed upload response")}return {ok:!!(f.ok??true),bucket:e.bucket,key:String(f.path??e.key),access:String(f.access??i),url:typeof f.url=="string"?f.url:void 0,size:Number(f.size??a??0),encrypted:!!(f.encrypted??n)}}let c=await Je(e.body),m=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:c,contentType:e.contentType,access:i,encrypt:n});return {ok:m.ok,bucket:e.bucket,key:String(m.path??e.key),access:String(m.access??i),url:typeof m.url=="string"?m.url:void 0,size:Number(m.size??0),encrypted:!!m.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??He(e.key),o=globalThis.document;if(!o)return {ok:true,url:n,filename:i,triggered:false};let s=o.createElement("a");return s.href=n,e.openInNewTab?s.target="_blank":s.download=i,s.rel="noopener noreferrer",o.body?.appendChild(s),s.click(),s.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"),access:typeof n.access=="string"?n.access:void 0,url:typeof n.url=="string"?n.url:void 0,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?We(e.cursor):0,i=Math.max(1,Math.min(e.limit??100,1e3)),o=await this._svc.request("POST","/object/list",{serverId:t,prefix:e.prefix,limit:i,skip:n}),s=Array.isArray(o.objects)?o.objects:[],a=!!o.hasMore,l=Number(o.count??s.length);return {bucket:e.bucket,objects:s.map(c=>({bucket:e.bucket,key:String(c.path??c.key??""),size:Number(c.size??0),contentType:String(c.contentType??"application/octet-stream"),access:typeof c.access=="string"?c.access:void 0,url:typeof c.url=="string"?c.url:void 0,encrypted:!!c.encrypted,createdAt:c.createdAt,updatedAt:c.updatedAt})),count:l,hasMore:a,cursor:a?Me(n+s.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 W=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 H=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 ee(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 o=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[o,...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 o=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(o.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let s=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(o,i,s))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:o})}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 W(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}stream(e={}){let t=this._buildSq(),n=new Set,i=[],o=new Map,s=Math.max(0,Number(e.flushMs??24)),a=Math.max(1,Number(e.maxBatchSize??200)),l=e.insertAt??"end",c=typeof e.maxDocs=="number"&&e.maxDocs>0?Math.floor(e.maxDocs):void 0,m=String(e.idField??"id"),d=[],A=false,b=false,k=0,f,_=()=>{o.clear();for(let u=0;u<d.length;u+=1){let g=ue(d[u]);g&&o.set(g,u);}},ue=(u,g)=>{if(g)return g;if(u==null)return;if(typeof e.getId=="function"){let O=e.getId(u);if(typeof O=="string"&&O.length>0)return O}let C=u?.[m]??u?._id??u?.docId;if(typeof C=="string"&&C.length>0)return C},me=()=>{c==null||d.length<=c||(d=d.slice(0,c));},pe=()=>{typeof e.sort=="function"&&(d=d.slice().sort(e.sort));},ge=(u,g)=>{k+=1;let C=d.slice(),O={reason:u,batchSize:g,version:k,ready:b};for(let K of Array.from(n))try{K(C,O);}catch{}},ne=()=>{f!=null&&(clearTimeout(f),f=void 0);},Fe=u=>{if(u.operation==="delete"){let K=o.get(u.docId??"");if(K==null)return;d.splice(K,1),_();return}let g=u.data;if(g==null)return;let C=ue(g,u.docId);if(!C)return;let O=o.get(C);if(typeof O=="number"){d[O]=g;return}l==="start"?d.unshift(g):d.push(g),me(),_();},he=()=>{if(A||i.length===0)return;ne();let u=i.splice(0,i.length);for(let g of u)Fe(g);pe(),_(),ge("change-batch",u.length);},Pe=()=>{A||f!=null||(f=setTimeout(he,s));},re=this.conn.subscribe(this.name,void 0,t,u=>{if(!A){if(u.type==="snapshot"){d=Array.isArray(u.data)?[...u.data]:[],b=true,ne(),i.length=0,pe(),me(),_(),ge("snapshot",0);return}if(i.push({docId:u.docId,operation:u.operation,data:u.data??null}),i.length>=a){he();return}Pe();}}),ie={subscribe(u,g=true){if(n.add(u),g){let C={reason:b?"change-batch":"snapshot",batchSize:0,version:k,ready:b};try{u(d.slice(),C);}catch{}}return ()=>{n.delete(u);}},getSnapshot(){return d.slice()},isReady(){return b},getVersion(){return k},close:()=>{A||(A=true,ne(),i.length=0,n.clear(),re());},onError(u){return re.onError(u),ie},onPermissionDenied(u){return re.onPermissionDenied(u),ie}};return ie}asStore(e={}){let t=this.stream(e);return {subscribe:n=>t.subscribe(()=>{n();},false),getSnapshot:()=>t.getSnapshot(),getServerSnapshot:()=>[],stream:t,destroy:()=>{t.close();}}}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 z=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;this._state="disconnected";this._stateListeners=[];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._setState("connecting"),this._connect();}ready(){return this._readyPromise}get connectionState(){return this._state}onConnectionStateChange(e){return this._stateListeners.push(e),()=>{this._stateListeners=this._stateListeners.filter(t=>t!==e);}}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false,this._setState("disconnected");}send(e,t){return new Promise((n,i)=>{let o=ce(),s={id:o,type:e,ts:Date.now(),...t},a=setTimeout(()=>{this.pendingAcks.delete(o),i(new Error(`[flare-admin] WS request timeout (${e})`));},1e4);this.pendingAcks.set(o,c=>{clearTimeout(a),c.type==="error"?i(new Error(`[flare-admin] Server error: ${c.message}`)):n(c);});let l=()=>this.ws?.send(JSON.stringify(s));this.connected&&this.ws?.readyState===Ie__default.default.OPEN?l():this.ready().then(l).catch(i);})}subscribe(e,t,n,i,o={}){let s=ce(),a={baseId:s,liveId:s,collection:e,docId:t,structuredQuery:n,callback:i,options:o};this.activeSubscriptions.set(s,a),this.subscriptionErrorHandlers.set(s,new Set),this.subscriptionPermissionHandlers.set(s,new Set),this.activateSubscription(a);let l=()=>{let d=this.activeSubscriptions.get(s)?.liveId??s;this.activeSubscriptions.delete(s),this.subscriptions.delete(s),this.subscriptions.delete(d),this.subscriptionErrorHandlers.delete(s),this.subscriptionPermissionHandlers.delete(s),this.subscriptionLastErrors.delete(s),this.connected&&this.send("unsubscribe",{subscriptionId:d}).catch(()=>{});},c=l;return c.unsubscribe=l,c.onError=m=>{this.subscriptionErrorHandlers.get(s)?.add(m);let d=this.subscriptionLastErrors.get(s);if(d)try{m(d);}catch{}return c},c.onPermissionDenied=m=>{this.subscriptionPermissionHandlers.get(s)?.add(m);let d=this.subscriptionLastErrors.get(s);if(d?.permissionDenied)try{m(d);}catch{}return c},c.catch=m=>c.onError(m),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 o=i.subscriptionId;if(o&&o!==e.liveId){let s=this.subscriptions.get(e.liveId);s&&(this.subscriptions.delete(e.liveId),this.subscriptions.set(o,s),e.liveId=o);}}).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],o=(n?.[2]??t).trim()||t,s=i==="PERMISSION_DENIED"||t.includes("PERMISSION_DENIED");return {code:i,message:o,permissionDenied:s,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 o of i)try{o(t);}catch{}}}_setState(e){if(this._state!==e){this._state=e;for(let t of this._stateListeners.slice())try{t(e);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new Ie__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?(this._setState("reconnecting"),setTimeout(()=>{this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this._connect();},this.reconnectDelay)):this._setState("disconnected");}),this.ws.on("error",()=>{this._setState("error");});}_handle(e){let t=e.type;if(t==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._setState("connected"),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 o=Array.from(this.activeSubscriptions.values()).find(s=>s.liveId===n||s.baseId===n);if(o){let s=this.toSubscriptionError(new Error(`[${String(e.code??"ERROR")}] ${String(e.message??"Unknown error")}`));this.emitSubscriptionError(o.baseId,s);}}return}if(t==="snapshot"||t==="change"){let n=e.subscriptionId,i=this.subscriptions.get(n);if(i){let o=Array.from(this.activeSubscriptions.values()).find(l=>l.liveId===n),s=String(e.collection??o?.collection??""),a=t==="change"&&e.operation==="delete"?null:F(this.cfg,s,e.data,o?.structuredQuery);i({subscriptionId:n,collection:s,docId:e.docId,data:a,type:t==="snapshot"?"snapshot":"change",operation:e.operation});}}}};var G=class{constructor(e){this._ws=new z(e);}collection(e){return new H(this._ws,e)}ready(){return this._ws.ready()}get connectionState(){return this._ws.connectionState}onConnectionStateChange(e){return this._ws.onConnectionStateChange(e)}disconnect(){this._ws.disconnect();}};var L=class{constructor(e,t=e.appId){this.cfg=e;this.targetAppId=t;}get appId(){return this.targetAppId}get callerAppId(){return this.cfg.appId}baseUrl(e){return y(this.cfg,`/system/apps/${e??this.appId}/functions`)}get authParams(){return new URLSearchParams({appId:this.callerAppId,adminKey:this.cfg.adminKey}).toString()}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}url(e){let t=`${this.baseUrl()}${e}`;return `${t}${t.includes("?")?"&":"?"}${this.authParams}`}async request(e,t){let n=this.url(e),i;try{i=await fetch(n,{...t,headers:{...this.headers,...t?.headers??{}}});}catch(s){let a=s instanceof Error?s.message:String(s);throw new Error(`[flare-admin/functions] Network error (${t?.method??"GET"} ${n}): ${a}`)}let o=await i.json().catch(()=>({}));if(!i.ok||o.ok===false){let s=String(o.error??o.message??"unknown_error");throw new Error(`[flare-admin/functions] Request failed (HTTP ${i.status}): ${s}`)}return o}extractFunction(e){return e.function??e.item??e}async list(){let e=await this.request("");return Array.isArray(e.list)?e.list:[]}async get(e){try{let t=await this.request(`/${e}`);return this.extractFunction(t)}catch(t){let n=t instanceof Error?t.message:String(t);if(n.includes("not_found")||n.includes("HTTP 404"))return null;throw t}}async create(e){let t=await this.request("",{method:"POST",body:JSON.stringify(e)});return this.extractFunction(t)}async patch(e,t){let n=await this.request(`/${e}`,{method:"PATCH",body:JSON.stringify(t)});return this.extractFunction(n)}async upsert(e,t){return await this.get(e)?this.patch(e,{name:t.name,enabled:t.enabled,scope:t.scope,target:t.target,timeoutMs:t.timeoutMs}):this.create({...t,id:e})}async delete(e){let t=await this.request(`/${e}`,{method:"DELETE"});return {ok:!!(t.ok??true),id:String(t.id??e)}}async invoke(e,t){let n=await this.request(`/${e}/invoke`,{method:"POST",body:JSON.stringify(t??{})});return {ok:!!(n.ok??true),functionId:String(n.functionId??e),status:n.status??"success",output:n.output,error:n.error,durationMs:typeof n.durationMs=="number"?n.durationMs:void 0,executionId:n.executionId}}async executions(e){let t=new URLSearchParams;e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.cursor&&t.set("cursor",e.cursor);let n=t.size?`/executions?${t.toString()}`:"/executions",i=await this.request(n);return {list:Array.isArray(i.list)?i.list:[],total:Number(i.total??0)}}async validate(e,t){try{let n=await this.request("/validate",{method:"POST",body:JSON.stringify({source:e,functionId:t})});return {valid:!!(n.valid??!1),diagnostics:Array.isArray(n.diagnostics)?n.diagnostics:[],mode:n.mode??"server"}}catch{return {valid:false,diagnostics:[],mode:"unavailable"}}}};var _n="ServerTimeStamp",En={$serverTimestamp:true};var le=class{constructor(e){this.cfg={defaultTtl:"24h",transport:"auto",...e,serverUrl:e.serverUrl.replace(/\/$/,""),httpBase:e.httpBase?.replace(/\/$/,"")??"",grpcUrl:e.grpcUrl??"",dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new N(this.cfg))}db(){return this._db??(this._db=new $(this.cfg))}generateFlareId(){return crypto.randomUUID().replace(/-/g,"").substring(0,20)}doc(e){let t=this.generateFlareId(),n=this.db().collection(e).doc(t);return n.id=t,n}live(){return this._conn??(this._conn=new G(this.cfg))}functions(){return this._functions??(this._functions=new L(this.cfg))}functionsFor(e){return new L(this.cfg,e)}notifications(){return this._notifications??(this._notifications=new J(this.cfg))}storageService(){return this._storage??(this._storage=new te(this.cfg))}storage(){return this._storageS3||(this._storageS3=new M(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)}onConnectionStateChange(e){return this.live().onConnectionStateChange(e)}disconnect(){this._conn?.disconnect(),this._conn=void 0;}},P=new Map;function Wn(r,e="[DEFAULT]"){if(P.has(e))return P.get(e);let t=new le(r);return P.set(e,t),t}function Q(r="[DEFAULT]"){let e=P.get(r);if(!e)throw new Error(`[flare-admin] No app named "${r}" found. Call connectApp() before getApp().`);return e}function Hn(r="[DEFAULT]"){let e=P.get(r);return e?(e.disconnect(),P.delete(r),true):false}function zn(){for(let r of P.values())r.disconnect();P.clear();}function Gn(r="[DEFAULT]"){return Q(r).auth()}function Qn(r="[DEFAULT]"){return Q(r).db()}function Kn(r="[DEFAULT]"){return Q(r).live()}function Vn(r="[DEFAULT]"){return Q(r).notifications()}function Zn(r="[DEFAULT]"){return Q(r).storage()}exports.AdminCollectionReference=j;exports.AdminDocumentReference=x;exports.AdminLiveCollectionReference=H;exports.AdminLiveDocumentReference=W;exports.AdminStorageSignedAction=oe;exports.FlareAdminApp=le;exports.FlareAdminAuthService=N;exports.FlareAdminConnection=G;exports.FlareAdminDbService=$;exports.FlareAdminFunctionsService=L;exports.FlareAdminNotificationsService=J;exports.FlareAdminStorageS3=M;exports.FlareAdminWsConnection=z;exports.ServerTimeStamp=_n;exports.ServerTimeStampField=En;exports.auth=Gn;exports.connectApp=Wn;exports.db=Qn;exports.disconnectAllApps=zn;exports.disconnectApp=Hn;exports.getApp=Q;exports.live=Kn;exports.notifications=Vn;exports.storage=Zn;
|
package/dist/index.d.cts
CHANGED
|
@@ -144,6 +144,7 @@ interface AdminStorageUploadInput {
|
|
|
144
144
|
path: string;
|
|
145
145
|
contentBase64: string;
|
|
146
146
|
contentType?: string;
|
|
147
|
+
access?: "public" | "private";
|
|
147
148
|
encrypt?: boolean;
|
|
148
149
|
}
|
|
149
150
|
interface AdminStorageDownloadInput {
|
|
@@ -159,6 +160,8 @@ interface AdminStorageObjectResult {
|
|
|
159
160
|
ok: boolean;
|
|
160
161
|
path: string;
|
|
161
162
|
key: string;
|
|
163
|
+
access?: "public" | "private";
|
|
164
|
+
url?: string;
|
|
162
165
|
encrypted?: boolean;
|
|
163
166
|
size?: number;
|
|
164
167
|
contentBase64?: string;
|
|
@@ -177,6 +180,7 @@ interface AdminStorageSignedUrlInput {
|
|
|
177
180
|
expiresInSeconds?: number;
|
|
178
181
|
sizeBytes?: number;
|
|
179
182
|
contentType?: string;
|
|
183
|
+
access?: "public" | "private";
|
|
180
184
|
encrypt?: boolean;
|
|
181
185
|
decrypt?: boolean;
|
|
182
186
|
forceDownload?: boolean;
|
|
@@ -341,6 +345,8 @@ interface AdminStorageObjectMeta {
|
|
|
341
345
|
bucket: string;
|
|
342
346
|
size: number;
|
|
343
347
|
contentType: string;
|
|
348
|
+
access?: "public" | "private";
|
|
349
|
+
url?: string;
|
|
344
350
|
encrypted: boolean;
|
|
345
351
|
createdAt?: unknown;
|
|
346
352
|
updatedAt?: unknown;
|
|
@@ -352,7 +358,9 @@ interface AdminPutObjectInput {
|
|
|
352
358
|
/** Pre-encoded base64 body. Mutually exclusive with `body`. Always uses base64 path. */
|
|
353
359
|
contentBase64?: string;
|
|
354
360
|
contentType?: string;
|
|
355
|
-
/**
|
|
361
|
+
/** Public/private object access. Defaults to public. */
|
|
362
|
+
access?: "public" | "private";
|
|
363
|
+
/** Encrypt at rest with AES-256-GCM. Defaults to false. */
|
|
356
364
|
encrypt?: boolean;
|
|
357
365
|
/**
|
|
358
366
|
* Max payload bytes for the base64-over-JSON upload path.
|
|
@@ -365,6 +373,8 @@ interface AdminPutObjectResult {
|
|
|
365
373
|
ok: boolean;
|
|
366
374
|
bucket: string;
|
|
367
375
|
key: string;
|
|
376
|
+
access: "public" | "private";
|
|
377
|
+
url?: string;
|
|
368
378
|
size: number;
|
|
369
379
|
encrypted: boolean;
|
|
370
380
|
}
|
|
@@ -413,6 +423,105 @@ interface AdminDeleteObjectsInput {
|
|
|
413
423
|
bucket: string;
|
|
414
424
|
keys: string[];
|
|
415
425
|
}
|
|
426
|
+
type AdminFunctionScopeType = "collection" | "document" | "field";
|
|
427
|
+
type AdminFunctionTargetType = "compiled_plan" | "internal" | "webhook" | "isolated_runtime";
|
|
428
|
+
type AdminMutationOperation = "create" | "update" | "delete" | "other";
|
|
429
|
+
type AdminFunctionExecutionStatus = "pending" | "running" | "success" | "failure" | "timeout";
|
|
430
|
+
interface AdminFunctionScope {
|
|
431
|
+
type?: AdminFunctionScopeType;
|
|
432
|
+
collection?: string;
|
|
433
|
+
document_id?: string;
|
|
434
|
+
fields?: string[];
|
|
435
|
+
}
|
|
436
|
+
interface AdminFunctionTarget {
|
|
437
|
+
type?: AdminFunctionTargetType;
|
|
438
|
+
source?: string;
|
|
439
|
+
handler?: string;
|
|
440
|
+
url?: string;
|
|
441
|
+
}
|
|
442
|
+
interface AdminCloudFunction {
|
|
443
|
+
id: string;
|
|
444
|
+
appId: string;
|
|
445
|
+
name: string;
|
|
446
|
+
enabled: boolean;
|
|
447
|
+
scope: AdminFunctionScope;
|
|
448
|
+
target: AdminFunctionTarget;
|
|
449
|
+
timeoutMs?: number;
|
|
450
|
+
createdAt?: string;
|
|
451
|
+
updatedAt?: string;
|
|
452
|
+
}
|
|
453
|
+
interface AdminCreateFunctionInput {
|
|
454
|
+
id?: string;
|
|
455
|
+
name: string;
|
|
456
|
+
enabled?: boolean;
|
|
457
|
+
scope: AdminFunctionScope;
|
|
458
|
+
target: AdminFunctionTarget;
|
|
459
|
+
timeoutMs?: number;
|
|
460
|
+
}
|
|
461
|
+
interface AdminPatchFunctionInput {
|
|
462
|
+
name?: string;
|
|
463
|
+
enabled?: boolean;
|
|
464
|
+
scope?: AdminFunctionScope;
|
|
465
|
+
target?: AdminFunctionTarget;
|
|
466
|
+
timeoutMs?: number;
|
|
467
|
+
}
|
|
468
|
+
interface AdminInvokeFunctionInput {
|
|
469
|
+
documentId?: string;
|
|
470
|
+
operation?: AdminMutationOperation;
|
|
471
|
+
changedFields?: string[];
|
|
472
|
+
updatedFields?: Record<string, unknown>;
|
|
473
|
+
removedFields?: string[];
|
|
474
|
+
fullDocument?: Record<string, unknown>;
|
|
475
|
+
data?: unknown;
|
|
476
|
+
auth?: unknown;
|
|
477
|
+
context?: Record<string, unknown>;
|
|
478
|
+
}
|
|
479
|
+
interface AdminInvokeFunctionResult {
|
|
480
|
+
ok: boolean;
|
|
481
|
+
functionId: string;
|
|
482
|
+
status: AdminFunctionExecutionStatus;
|
|
483
|
+
output?: unknown;
|
|
484
|
+
error?: string;
|
|
485
|
+
durationMs?: number;
|
|
486
|
+
executionId?: string;
|
|
487
|
+
}
|
|
488
|
+
interface AdminFunctionExecution {
|
|
489
|
+
id: string;
|
|
490
|
+
functionId: string;
|
|
491
|
+
appId: string;
|
|
492
|
+
status: AdminFunctionExecutionStatus;
|
|
493
|
+
triggeredBy?: string;
|
|
494
|
+
durationMs?: number;
|
|
495
|
+
output?: unknown;
|
|
496
|
+
error?: string;
|
|
497
|
+
createdAt?: string;
|
|
498
|
+
updatedAt?: string;
|
|
499
|
+
}
|
|
500
|
+
interface AdminFunctionValidationResult {
|
|
501
|
+
valid: boolean;
|
|
502
|
+
diagnostics: unknown[];
|
|
503
|
+
mode?: "server" | "local_fallback" | "unavailable";
|
|
504
|
+
}
|
|
505
|
+
interface FlareAdminFunctions {
|
|
506
|
+
list(): Promise<AdminCloudFunction[]>;
|
|
507
|
+
get(functionId: string): Promise<AdminCloudFunction | null>;
|
|
508
|
+
create(input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
509
|
+
patch(functionId: string, input: AdminPatchFunctionInput): Promise<AdminCloudFunction>;
|
|
510
|
+
upsert(functionId: string, input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
511
|
+
delete(functionId: string): Promise<{
|
|
512
|
+
ok: boolean;
|
|
513
|
+
id: string;
|
|
514
|
+
}>;
|
|
515
|
+
invoke(functionId: string, input?: AdminInvokeFunctionInput): Promise<AdminInvokeFunctionResult>;
|
|
516
|
+
executions(opts?: {
|
|
517
|
+
limit?: number;
|
|
518
|
+
cursor?: string;
|
|
519
|
+
}): Promise<{
|
|
520
|
+
list: AdminFunctionExecution[];
|
|
521
|
+
total: number;
|
|
522
|
+
}>;
|
|
523
|
+
validate(source: string, functionId?: string): Promise<AdminFunctionValidationResult>;
|
|
524
|
+
}
|
|
416
525
|
type QueryOperator = "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "array-contains" | "array-contains-any" | "elem-match" | "like" | "not-like" | "contains" | "exists" | "not-exists";
|
|
417
526
|
interface WhereFilter {
|
|
418
527
|
field: string;
|
|
@@ -1201,6 +1310,38 @@ declare class FlareAdminWsConnection {
|
|
|
1201
1310
|
private _handle;
|
|
1202
1311
|
}
|
|
1203
1312
|
|
|
1313
|
+
declare class FlareAdminFunctionsService implements FlareAdminFunctions {
|
|
1314
|
+
private readonly cfg;
|
|
1315
|
+
private readonly targetAppId;
|
|
1316
|
+
constructor(cfg: Required<FlareAdminConfig>, targetAppId?: string);
|
|
1317
|
+
private get appId();
|
|
1318
|
+
private get callerAppId();
|
|
1319
|
+
private baseUrl;
|
|
1320
|
+
private get authParams();
|
|
1321
|
+
private get headers();
|
|
1322
|
+
private url;
|
|
1323
|
+
private request;
|
|
1324
|
+
private extractFunction;
|
|
1325
|
+
list(): Promise<AdminCloudFunction[]>;
|
|
1326
|
+
get(functionId: string): Promise<AdminCloudFunction | null>;
|
|
1327
|
+
create(input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
1328
|
+
patch(functionId: string, input: AdminPatchFunctionInput): Promise<AdminCloudFunction>;
|
|
1329
|
+
upsert(functionId: string, input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
1330
|
+
delete(functionId: string): Promise<{
|
|
1331
|
+
ok: boolean;
|
|
1332
|
+
id: string;
|
|
1333
|
+
}>;
|
|
1334
|
+
invoke(functionId: string, input?: AdminInvokeFunctionInput): Promise<AdminInvokeFunctionResult>;
|
|
1335
|
+
executions(opts?: {
|
|
1336
|
+
limit?: number;
|
|
1337
|
+
cursor?: string;
|
|
1338
|
+
}): Promise<{
|
|
1339
|
+
list: AdminFunctionExecution[];
|
|
1340
|
+
total: number;
|
|
1341
|
+
}>;
|
|
1342
|
+
validate(source: string, functionId?: string): Promise<AdminFunctionValidationResult>;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1204
1345
|
/**
|
|
1205
1346
|
* Sentinel value that asks flare-node to write the current server timestamp.
|
|
1206
1347
|
*
|
|
@@ -1227,6 +1368,7 @@ declare class FlareAdminApp {
|
|
|
1227
1368
|
private _notifications?;
|
|
1228
1369
|
private _storage?;
|
|
1229
1370
|
private _storageS3?;
|
|
1371
|
+
private _functions?;
|
|
1230
1372
|
/**
|
|
1231
1373
|
* Access the auth service.
|
|
1232
1374
|
*
|
|
@@ -1303,6 +1445,25 @@ declare class FlareAdminApp {
|
|
|
1303
1445
|
* admin.live().disconnect();
|
|
1304
1446
|
*/
|
|
1305
1447
|
live(): FlareAdminConnection;
|
|
1448
|
+
/**
|
|
1449
|
+
* Access cloud functions management APIs.
|
|
1450
|
+
* Requires `adminKey` — operations run as admin, bypassing auth checks.
|
|
1451
|
+
*
|
|
1452
|
+
* @example
|
|
1453
|
+
* const fns = await admin.functions().list();
|
|
1454
|
+
* await admin.functions().invoke('my-fn', { data: { userId: 'abc' } });
|
|
1455
|
+
* await admin.functions().upsert('guard-fn', {
|
|
1456
|
+
* name: 'guard_fn',
|
|
1457
|
+
* scope: { type: 'collection', collection: 'orders' },
|
|
1458
|
+
* target: { type: 'compiled_plan', source: 'if exists(event.invocation.auth.uid) { ... }' },
|
|
1459
|
+
* });
|
|
1460
|
+
*/
|
|
1461
|
+
functions(): FlareAdminFunctions;
|
|
1462
|
+
/**
|
|
1463
|
+
* Access cloud functions for a specific target app.
|
|
1464
|
+
* The caller identity remains this admin app's credentials; only the path target changes.
|
|
1465
|
+
*/
|
|
1466
|
+
functionsFor(appId: string): FlareAdminFunctions;
|
|
1306
1467
|
/**
|
|
1307
1468
|
* Access push notification management APIs.
|
|
1308
1469
|
*/
|
|
@@ -1440,4 +1601,4 @@ declare function live(name?: string): FlareAdminConnection;
|
|
|
1440
1601
|
declare function notifications(name?: string): FlareAdminNotifications;
|
|
1441
1602
|
declare function storage(name?: string): FlareAdminStorageS3;
|
|
1442
1603
|
|
|
1443
|
-
export { type AdminBulkWriteOperation, type AdminBulkWriteOptions, type AdminBulkWriteProgress, type AdminBulkWriteResult, AdminCollectionReference, type AdminConnectionState, type AdminConnectionStateListener, type AdminCopyObjectInput, type AdminDeleteObjectsInput, type AdminDocAddedCallback, type AdminDocChangedCallback, type AdminDocDeletedCallback, type AdminDocUpdatedCallback, AdminDocumentReference, type AdminDownloadObjectInput, type AdminDownloadObjectResult, type AdminGetObjectInput, type AdminGetObjectResult, type AdminGetObjectUrlInput, type AdminHeadObjectInput, type AdminHeadObjectsInput, type AdminListObjectsInput, type AdminListObjectsResult, AdminLiveCollectionReference, AdminLiveDocumentReference, type AdminPushSendInput, type AdminPushSendResult, type AdminPushToken, type AdminPutObjectInput, type AdminPutObjectResult, type AdminSnapshotCallback, type AdminSnapshotData, type AdminStorageAwsConfig, type AdminStorageBucket, type AdminStorageBucketInput, type AdminStorageDeleteInput, type AdminStorageDownloadInput, type AdminStorageObjectMeta, type AdminStorageObjectResult, type AdminStorageRulesHistoryResult, type AdminStorageRulesPolicy, type AdminStorageServer, type AdminStorageServerInput, type AdminStorageServerPatchInput, AdminStorageSignedAction, type AdminStorageSignedUrlInput, type AdminStorageSignedUrlResult, type AdminStorageUploadInput, type AdminSubscriptionError, type AdminSubscriptionErrorCallback, type AdminSubscriptionHandle, type AdminUpdateManyItem, type AggregateFunction, type AggregateSpec, type AnyFilter, type CreateCustomTokenOptions, type CursorValue, FlareAdminApp, type FlareAdminAuth, FlareAdminAuthService, type FlareAdminConfig, FlareAdminConnection, type FlareAdminDb, FlareAdminDbService, type FlareAdminNotifications, FlareAdminNotificationsService, type FlareAdminStorage, FlareAdminStorageS3, FlareAdminWsConnection, type GroupByClause, type HavingClause, type JoinClause, type OrFilter, type OrderByClause, type QueryOperator, ServerTimeStamp, ServerTimeStampField, type StructuredQuery, type VectorSearchClause, type WhereCondition, type WhereFilter, auth, connectApp, db, disconnectAllApps, disconnectApp, getApp, live, notifications, storage };
|
|
1604
|
+
export { type AdminBulkWriteOperation, type AdminBulkWriteOptions, type AdminBulkWriteProgress, type AdminBulkWriteResult, type AdminCloudFunction, AdminCollectionReference, type AdminConnectionState, type AdminConnectionStateListener, type AdminCopyObjectInput, type AdminCreateFunctionInput, type AdminDeleteObjectsInput, type AdminDocAddedCallback, type AdminDocChangedCallback, type AdminDocDeletedCallback, type AdminDocUpdatedCallback, AdminDocumentReference, type AdminDownloadObjectInput, type AdminDownloadObjectResult, type AdminFunctionExecution, type AdminFunctionExecutionStatus, type AdminFunctionScope, type AdminFunctionScopeType, type AdminFunctionTarget, type AdminFunctionTargetType, type AdminGetObjectInput, type AdminGetObjectResult, type AdminGetObjectUrlInput, type AdminHeadObjectInput, type AdminHeadObjectsInput, type AdminInvokeFunctionInput, type AdminInvokeFunctionResult, type AdminListObjectsInput, type AdminListObjectsResult, AdminLiveCollectionReference, AdminLiveDocumentReference, type AdminMutationOperation, type AdminPatchFunctionInput, type AdminPushSendInput, type AdminPushSendResult, type AdminPushToken, type AdminPutObjectInput, type AdminPutObjectResult, type AdminSnapshotCallback, type AdminSnapshotData, type AdminStorageAwsConfig, type AdminStorageBucket, type AdminStorageBucketInput, type AdminStorageDeleteInput, type AdminStorageDownloadInput, type AdminStorageObjectMeta, type AdminStorageObjectResult, type AdminStorageRulesHistoryResult, type AdminStorageRulesPolicy, type AdminStorageServer, type AdminStorageServerInput, type AdminStorageServerPatchInput, AdminStorageSignedAction, type AdminStorageSignedUrlInput, type AdminStorageSignedUrlResult, type AdminStorageUploadInput, type AdminSubscriptionError, type AdminSubscriptionErrorCallback, type AdminSubscriptionHandle, type AdminUpdateManyItem, type AggregateFunction, type AggregateSpec, type AnyFilter, type CreateCustomTokenOptions, type CursorValue, FlareAdminApp, type FlareAdminAuth, FlareAdminAuthService, type FlareAdminConfig, FlareAdminConnection, type FlareAdminDb, FlareAdminDbService, type FlareAdminFunctions, FlareAdminFunctionsService, type FlareAdminNotifications, FlareAdminNotificationsService, type FlareAdminStorage, FlareAdminStorageS3, FlareAdminWsConnection, type GroupByClause, type HavingClause, type JoinClause, type OrFilter, type OrderByClause, type QueryOperator, ServerTimeStamp, ServerTimeStampField, type StructuredQuery, type VectorSearchClause, type WhereCondition, type WhereFilter, auth, connectApp, db, disconnectAllApps, disconnectApp, getApp, live, notifications, storage };
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
* .onSnapshot((snap) => console.log(snap));
|
|
41
41
|
*/
|
|
42
42
|
export { AdminStorageSignedAction } from "./types";
|
|
43
|
+
export type { AdminCloudFunction, AdminCreateFunctionInput, AdminFunctionExecution, AdminFunctionExecutionStatus, AdminFunctionScope, AdminFunctionScopeType, AdminFunctionTarget, AdminFunctionTargetType, AdminInvokeFunctionInput, AdminInvokeFunctionResult, AdminMutationOperation, AdminPatchFunctionInput, FlareAdminFunctions, } from "./types";
|
|
43
44
|
export type { AdminBulkWriteOperation, AdminBulkWriteOptions, AdminBulkWriteProgress, AdminBulkWriteResult, AdminConnectionState, AdminConnectionStateListener, AdminCopyObjectInput, AdminDeleteObjectsInput, AdminDocAddedCallback, AdminDocChangedCallback, AdminDocDeletedCallback, AdminDocUpdatedCallback, AdminDownloadObjectInput, AdminDownloadObjectResult, AdminGetObjectInput, AdminGetObjectResult, AdminGetObjectUrlInput, AdminHeadObjectInput, AdminHeadObjectsInput, AdminListObjectsInput, AdminListObjectsResult, AdminPushSendInput, AdminPushSendResult, AdminPushToken, AdminPutObjectInput, AdminPutObjectResult, AdminSnapshotCallback, AdminSnapshotData, AdminStorageAwsConfig, AdminStorageBucket, AdminStorageBucketInput, AdminStorageDeleteInput, AdminStorageDownloadInput, AdminStorageObjectMeta, AdminStorageObjectResult, AdminStorageRulesHistoryResult, AdminStorageRulesPolicy, AdminStorageServer, AdminStorageServerInput, AdminStorageServerPatchInput, AdminStorageSignedUrlInput, AdminStorageSignedUrlResult, AdminStorageUploadInput, AdminSubscriptionError, AdminSubscriptionErrorCallback, AdminSubscriptionHandle, AdminUpdateManyItem, AggregateFunction, AggregateSpec, AnyFilter, CreateCustomTokenOptions, CursorValue, FlareAdminAuth, FlareAdminConfig, FlareAdminDb, FlareAdminNotifications, FlareAdminStorage, GroupByClause, HavingClause, JoinClause, OrderByClause, OrFilter, QueryOperator, StructuredQuery, VectorSearchClause, WhereCondition, WhereFilter } from "./types";
|
|
44
45
|
export { AdminCollectionReference } from "./db/Collection";
|
|
45
46
|
export { AdminDocumentReference } from "./db/Document";
|
|
@@ -51,9 +52,10 @@ export { FlareAdminConnection } from "./realtime/Connection";
|
|
|
51
52
|
export { AdminLiveCollectionReference } from "./realtime/LiveCollection";
|
|
52
53
|
export { AdminLiveDocumentReference } from "./realtime/LiveDocument";
|
|
53
54
|
export { FlareAdminWsConnection } from "./realtime/WsConnection";
|
|
55
|
+
export { FlareAdminFunctionsService } from "./lib/functions";
|
|
54
56
|
import { FlareAdminStorageS3 } from "./lib/storage";
|
|
55
57
|
import { FlareAdminConnection } from "./realtime/Connection";
|
|
56
|
-
import { AdminCopyObjectInput, AdminDeleteObjectsInput, AdminDownloadObjectInput, AdminDownloadObjectResult, AdminGetObjectInput, AdminGetObjectResult, AdminGetObjectUrlInput, AdminHeadObjectInput, AdminHeadObjectsInput, AdminListObjectsInput, AdminListObjectsResult, AdminPutObjectInput, AdminPutObjectResult, AdminStorageBucket, AdminStorageBucketInput, AdminStorageObjectMeta, AdminStorageSignedUrlInput, AdminStorageSignedUrlResult, FlareAdminAuth, FlareAdminConfig, FlareAdminDb, FlareAdminNotifications } from "./types";
|
|
58
|
+
import { AdminCopyObjectInput, AdminDeleteObjectsInput, AdminDownloadObjectInput, AdminDownloadObjectResult, AdminGetObjectInput, AdminGetObjectResult, AdminGetObjectUrlInput, AdminHeadObjectInput, AdminHeadObjectsInput, AdminListObjectsInput, AdminListObjectsResult, AdminPutObjectInput, AdminPutObjectResult, AdminStorageBucket, AdminStorageBucketInput, AdminStorageObjectMeta, AdminStorageSignedUrlInput, AdminStorageSignedUrlResult, FlareAdminAuth, FlareAdminConfig, FlareAdminDb, FlareAdminFunctions, FlareAdminNotifications } from "./types";
|
|
57
59
|
/**
|
|
58
60
|
* A FlareAdmin application instance.
|
|
59
61
|
* Create one with `connectApp()` and keep it as a module-level singleton.
|
|
@@ -66,6 +68,7 @@ export declare class FlareAdminApp {
|
|
|
66
68
|
private _notifications?;
|
|
67
69
|
private _storage?;
|
|
68
70
|
private _storageS3?;
|
|
71
|
+
private _functions?;
|
|
69
72
|
/**
|
|
70
73
|
* Access the auth service.
|
|
71
74
|
*
|
|
@@ -142,6 +145,25 @@ export declare class FlareAdminApp {
|
|
|
142
145
|
* admin.live().disconnect();
|
|
143
146
|
*/
|
|
144
147
|
live(): FlareAdminConnection;
|
|
148
|
+
/**
|
|
149
|
+
* Access cloud functions management APIs.
|
|
150
|
+
* Requires `adminKey` — operations run as admin, bypassing auth checks.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* const fns = await admin.functions().list();
|
|
154
|
+
* await admin.functions().invoke('my-fn', { data: { userId: 'abc' } });
|
|
155
|
+
* await admin.functions().upsert('guard-fn', {
|
|
156
|
+
* name: 'guard_fn',
|
|
157
|
+
* scope: { type: 'collection', collection: 'orders' },
|
|
158
|
+
* target: { type: 'compiled_plan', source: 'if exists(event.invocation.auth.uid) { ... }' },
|
|
159
|
+
* });
|
|
160
|
+
*/
|
|
161
|
+
functions(): FlareAdminFunctions;
|
|
162
|
+
/**
|
|
163
|
+
* Access cloud functions for a specific target app.
|
|
164
|
+
* The caller identity remains this admin app's credentials; only the path target changes.
|
|
165
|
+
*/
|
|
166
|
+
functionsFor(appId: string): FlareAdminFunctions;
|
|
145
167
|
/**
|
|
146
168
|
* Access push notification management APIs.
|
|
147
169
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import ve from'fs';import B from'path';import {fileURLToPath}from'url';import be from'ws';var Z=(i=>(i.Upload="upload",i.Download="download",i.Delete="delete",i.Edit="edit",i))(Z||{});function H(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:we(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 we(r){return isNaN(Number(r))?r==="true"?true:r==="false"?false:r==="null"?null:r:Number(r)}function X(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}function Ce(r,e){let t=r.dataMapper;if(!t||typeof t!="object")return null;let n=t[e];return typeof n=="function"?n:null}function Y(r,e,t){let n=Ce(r,e);if(!n||t==null||typeof t!="object")return t;try{return n(t)}catch{return t}}function ee(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=>ee(r,c,o)):a&&typeof a=="object"&&(d=ee(r,a,o)),d=Array.isArray(d)?d.map(c=>Y(r,s,c)):Y(r,s,d),d!==a&&(n===e&&(n={...n}),n[s]=d);}return n}function T(r,e,t,n){let i=Array.isArray(n?.joins)?n.joins:[],s=o=>{let a=ee(r,o,i);return Y(r,e,a)};return Array.isArray(t)?t.map(o=>s(o)):s(t)}var Re=()=>typeof process<"u"&&!!process.versions?.node,f=r=>{if(r.transport==="http")return false;let e=!!(r.grpcUrl&&r.grpcUrl.trim().length>0),t=Re();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},j=r=>{try{return JSON.stringify(r??{})}catch{return "{}"}},x=r=>r?.field&&r?.op?{queryFilter:{field:String(r.field),op:String(r.op),valueJson:j(r.value)}}:Array.isArray(r?.or)?{orFilter:{or:r.or.map(e=>x(e))}}:Array.isArray(r?.and)?{andFilter:{and:r.and.map(e=>x(e))}}:{queryFilter:{field:"",op:"==",valueJson:"null"}},G=r=>{if(!(!r||!Array.isArray(r.values)))return {valuesJson:r.values.map(e=>j(e))}},ce=r=>({from:r.from,localField:r.localField,foreignField:r.foreignField,as:r.as,single:!!r.single,where:Array.isArray(r.where)?r.where.map(x):[],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(ce):[]}),Oe=r=>({where:Array.isArray(r.where)?r.where.map(x):[],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:G(r.startAt),startAfter:G(r.startAfter),endAt:G(r.endAt),endBefore:G(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(ce):[],select:Array.isArray(r.select)?r.select:[],distinctField:r.distinctField??""});async function S(r){let e=await import('@grpc/grpc-js'),t=await import('@grpc/proto-loader'),n=B.dirname(fileURLToPath(import.meta.url)),i=[B.resolve(n,"../../proto"),B.resolve(n,"../proto"),B.resolve(process.cwd(),"proto")],s=i.find(m=>ve.existsSync(B.join(m,"flare.proto")))??i[0],o=B.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 w(r,e,t){return new Promise((n,i)=>{r[e](t,(s,o)=>{if(s)return i(s);n(o??{});});})}function C(r,e){if(r.error)throw new Error(`[flare-admin][grpc] ${e} failed: ${r.errorDescription||r.error}`)}async function de(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(n,"AdminQuery",{app_id:r.appId,admin_key:r.adminKey,collection:e,query:Oe(t)});C(i,"admin_query");try{let s=JSON.parse(i.dataJson||"[]");return Array.isArray(s)?s:[]}catch{return []}}async function le(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(n,"CreateCustomToken",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",claims_json:j(t.claims??{}),ttl:t.ttl??r.defaultTtl});if(C(i,"create_custom_token"),!i.token)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return String(i.token)}async function ue(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(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 C(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 me(r,e,t){if(!f(r))return;let n=await S(r.grpcUrl),i=await w(n,"GetDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});if(C(i,"get_document"),!i.found)return null;try{return JSON.parse(i.dataJson||"{}")}catch{return {}}}async function pe(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(n,"CreateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,data_json:j(t)});return C(i,"create_document"),String(i.id??"")}async function ge(r,e,t,n){if(!f(r))return null;let i=await S(r.grpcUrl),s=await w(i,"ReplaceDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:j(n)});return C(s,"replace_document"),true}async function he(r,e,t,n){if(!f(r))return null;let i=await S(r.grpcUrl),s=await w(i,"UpdateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:j(n)});return C(s,"update_document"),true}async function fe(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(n,"DeleteDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});return C(i,"delete_document"),!!i.deleted}async function Ae(r,e,t){if(!f(r))return null;let n=await S(r.grpcUrl),i=await w(n,"DeleteMany",{app_id:r.appId,admin_key:r.adminKey,collection:e,where:(t??[]).map(x)});return C(i,"delete_many"),Number(i.deleted??0)}var ye=r=>r.replace(/\/$/,""),Ie=r=>{let e=String(r.httpBase??"").trim();return ye(e||r.serverUrl)},y=(r,e)=>{let t=Ie(r),n=e.startsWith("/")?e:`/${e}`;return `${t}${n}`};var I=class{constructor(e,t,n){this.cfg=e;this.collection=t;this.id=n;}get baseUrl(){return y(this.cfg,`/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 me(this.cfg,this.collection,this.id);if(e!==void 0)return e===null?null:T(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 T(this.cfg,this.collection,n.data)??null}async set(e){await ge(this.cfg,this.collection,this.id,e)===null&&await this.request("PUT",e);}async update(e){await he(this.cfg,this.collection,this.id,e)===null&&await this.request("PATCH",e);}async delete(){await fe(this.cfg,this.collection,this.id)===null&&await this.request("DELETE");}parent(){return new P(this.cfg,this.collection)}};var P=class r{constructor(e,t){this.cfg=e;this.name=t;this.sq={};this.opts={allowSensitiveAuthUserFields:true};}get baseUrl(){return y(this.cfg,`/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 H(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 de(this.cfg,this.name,this.sq);if(e)return T(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 T(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 pe(this.cfg,this.name,e);if(t!==null)return new I(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 I(this.cfg,this.name,i.id)}async update(e,t){let n=this.doc(e);return await n.update(t),n}ensureBulkOptions(e){let t=Number(e?.batchSize??250),n=Number(e?.concurrency??1);return {...e,batchSize:Number.isFinite(t)&&t>0?Math.floor(t):250,concurrency:Number.isFinite(n)&&n>0?Math.floor(n):1,continueOnError:e?.continueOnError===true}}toPercent(e,t){if(!(typeof t!="number"||t<=0))return Math.round(e/t*100)}emitBulkProgress(e,t,n){n&&n({operation:e,...t,percent:this.toPercent(t.processed,t.total)});}async*chunkIterable(e,t){let n=[];for await(let i of e)n.push(i),n.length>=t&&(yield n,n=[]);n.length>0&&(yield n);}assertBulkSignal(e){if(e?.aborted)throw new Error("Bulk write aborted")}async runChunkWorkers(e,t,n,i,s,o,a=false,d){let c=0,m=async()=>{for(;c<t.length;){this.assertBulkSignal(d);let A=c;c+=1;let O=t[A];try{let k=await i(O);s.succeeded+=1,s.processed+=1,this.emitBulkProgress(e,{processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total,lastDocId:k.docId},o);}catch(k){if(s.failed+=1,s.processed+=1,this.emitBulkProgress(e,{processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total,lastError:k},o),!a)throw k}}},u=Math.max(1,Math.min(n,t.length));await Promise.all(Array.from({length:u},()=>m()));}async runBulkWrite(e,t,n,i){let s=this.ensureBulkOptions(i);this.assertBulkSignal(s.signal);let o={processed:0,succeeded:0,failed:0,total:Array.isArray(t)?t.length:void 0};this.emitBulkProgress(e,{processed:0,succeeded:0,failed:0,total:o.total},s.onProgress);for await(let a of this.chunkIterable(t,s.batchSize))this.assertBulkSignal(s.signal),await this.runChunkWorkers(e,a,s.concurrency,n,o,s.onProgress,s.continueOnError,s.signal);return {operation:e,processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total}}async addMany(e,t){return this.runBulkWrite("addMany",e,async n=>({docId:(await this.add(n)).id}),t)}async updateMany(e,t){return this.runBulkWrite("updateMany",e,async n=>(await this.doc(n.id).update(n.data),{docId:n.id}),t)}async deleteMany(e,t){return e==null?this.deleteManyByQuery():this.runBulkWrite("deleteMany",e,async n=>(await this.doc(n).delete(),{docId:n}),t)}async deleteManyByQuery(){let e=await Ae(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 I(this.cfg,this.name,e)}};var _=class{constructor(e){this.cfg=e;}collection(e){return new P(this.cfg,e)}};var E=class{constructor(e){this.cfg=e;}async createCustomToken(e,t={}){if(f(this.cfg)){let a=await le(this.cfg,String(e),t);if(!a)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return a}let n=y(this.cfg,"/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}
|
|
2
|
-
Make sure FLARE_URL is set correctly and the server is running.`)}let
|
|
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] 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 D=class{constructor(e){this.cfg=e;}get baseUrl(){return y(this.cfg,`/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 z=class{constructor(e){this.cfg=e;}base(e){return y(this.cfg,`/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 te(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 Pe(r){return r===void 0?"":typeof r=="string"?te(new TextEncoder().encode(r)):Buffer&&Buffer.isBuffer(r)?r.toString("base64"):r instanceof Uint8Array?te(r):r instanceof ArrayBuffer?te(new Uint8Array(r)):""}function Be(r){return Buffer?Buffer.from(String(r)).toString("base64"):btoa(String(r))}function je(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 Fe(r){return (String(r??"").split("/").pop()??"download").replace(/["\\\r\n]/g,"")||"download"}var q=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 u=(await this.listBuckets()).find(A=>A.id===c);if(u)return u}}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}),m;typeof e.body=="string"?m=new TextEncoder().encode(e.body):m=e.body;let u=await fetch(c.url,{method:c.method??"PUT",headers:{...e.contentType?{"Content-Type":e.contentType}:{}},body:m});if(!u.ok){let A=await u.text().catch(()=>"");throw new Error(`[flare-admin] Signed-URL upload failed (HTTP ${u.status}): ${A}`)}return {ok:true,bucket:e.bucket,key:e.key,size:s??0,encrypted:!!(e.encrypt??true)}}let a=await Pe(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??Fe(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?je(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?Be(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 L=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 U=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 H(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 L(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}stream(e={}){let t=this._buildSq(),n=new Set,i=[],s=new Map,o=Math.max(0,Number(e.flushMs??24)),a=Math.max(1,Number(e.maxBatchSize??200)),d=e.insertAt??"end",c=typeof e.maxDocs=="number"&&e.maxDocs>0?Math.floor(e.maxDocs):void 0,m=String(e.idField??"id"),u=[],A=false,O=false,k=0,F,M=()=>{s.clear();for(let l=0;l<u.length;l+=1){let p=re(u[l]);p&&s.set(p,l);}},re=(l,p)=>{if(p)return p;if(l==null)return;if(typeof e.getId=="function"){let v=e.getId(l);if(typeof v=="string"&&v.length>0)return v}let b=l?.[m]??l?._id??l?.docId;if(typeof b=="string"&&b.length>0)return b},ie=()=>{c==null||u.length<=c||(u=u.slice(0,c));},se=()=>{typeof e.sort=="function"&&(u=u.slice().sort(e.sort));},oe=(l,p)=>{k+=1;let b=u.slice(),v={reason:l,batchSize:p,version:k,ready:O};for(let W of Array.from(n))try{W(b,v);}catch{}},Q=()=>{F!=null&&(clearTimeout(F),F=void 0);},ke=l=>{if(l.operation==="delete"){let W=s.get(l.docId??"");if(W==null)return;u.splice(W,1),M();return}let p=l.data;if(p==null)return;let b=re(p,l.docId);if(!b)return;let v=s.get(b);if(typeof v=="number"){u[v]=p;return}d==="start"?u.unshift(p):u.push(p),ie(),M();},ae=()=>{if(A||i.length===0)return;Q();let l=i.splice(0,i.length);for(let p of l)ke(p);se(),M(),oe("change-batch",l.length);},Se=()=>{A||F!=null||(F=setTimeout(ae,o));},K=this.conn.subscribe(this.name,void 0,t,l=>{if(!A){if(l.type==="snapshot"){u=Array.isArray(l.data)?[...l.data]:[],O=true,Q(),i.length=0,se(),ie(),M(),oe("snapshot",0);return}if(i.push({docId:l.docId,operation:l.operation,data:l.data??null}),i.length>=a){ae();return}Se();}}),V={subscribe(l,p=true){if(n.add(l),p){let b={reason:O?"change-batch":"snapshot",batchSize:0,version:k,ready:O};try{l(u.slice(),b);}catch{}}return ()=>{n.delete(l);}},getSnapshot(){return u.slice()},isReady(){return O},getVersion(){return k},close:()=>{A||(A=true,Q(),i.length=0,n.clear(),K());},onError(l){return K.onError(l),V},onPermissionDenied(l){return K.onPermissionDenied(l),V}};return V}asStore(e={}){let t=this.stream(e);return {subscribe:n=>t.subscribe(()=>{n();},false),getSnapshot:()=>t.getSnapshot(),getServerSnapshot:()=>[],stream:t,destroy:()=>{t.close();}}}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 N=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;this._state="disconnected";this._stateListeners=[];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._setState("connecting"),this._connect();}ready(){return this._readyPromise}get connectionState(){return this._state}onConnectionStateChange(e){return this._stateListeners.push(e),()=>{this._stateListeners=this._stateListeners.filter(t=>t!==e);}}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false,this._setState("disconnected");}send(e,t){return new Promise((n,i)=>{let s=X(),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===be.OPEN?d():this.ready().then(d).catch(i);})}subscribe(e,t,n,i,s={}){let o=X(),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 u=this.activeSubscriptions.get(o)?.liveId??o;this.activeSubscriptions.delete(o),this.subscriptions.delete(o),this.subscriptions.delete(u),this.subscriptionErrorHandlers.delete(o),this.subscriptionPermissionHandlers.delete(o),this.subscriptionLastErrors.delete(o),this.connected&&this.send("unsubscribe",{subscriptionId:u}).catch(()=>{});},c=d;return c.unsubscribe=d,c.onError=m=>{this.subscriptionErrorHandlers.get(o)?.add(m);let u=this.subscriptionLastErrors.get(o);if(u)try{m(u);}catch{}return c},c.onPermissionDenied=m=>{this.subscriptionPermissionHandlers.get(o)?.add(m);let u=this.subscriptionLastErrors.get(o);if(u?.permissionDenied)try{m(u);}catch{}return c},c.catch=m=>c.onError(m),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{}}}_setState(e){if(this._state!==e){this._state=e;for(let t of this._stateListeners.slice())try{t(e);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new be(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?(this._setState("reconnecting"),setTimeout(()=>{this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this._connect();},this.reconnectDelay)):this._setState("disconnected");}),this.ws.on("error",()=>{this._setState("error");});}_handle(e){let t=e.type;if(t==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._setState("connected"),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:T(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){this._ws=new N(e);}collection(e){return new U(this._ws,e)}ready(){return this._ws.ready()}get connectionState(){return this._ws.connectionState}onConnectionStateChange(e){return this._ws.onConnectionStateChange(e)}disconnect(){this._ws.disconnect();}};var un="ServerTimeStamp",mn={$serverTimestamp:true};var ne=class{constructor(e){this.cfg={defaultTtl:"24h",transport:"auto",...e,serverUrl:e.serverUrl.replace(/\/$/,""),httpBase:e.httpBase?.replace(/\/$/,"")??"",grpcUrl:e.grpcUrl??"",dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new E(this.cfg))}db(){return this._db??(this._db=new _(this.cfg))}generateFlareId(){return crypto.randomUUID().replace(/-/g,"").substring(0,20)}doc(e){let t=this.generateFlareId(),n=this.db().collection(e).doc(t);return n.id=t,n}live(){return this._conn??(this._conn=new J(this.cfg))}notifications(){return this._notifications??(this._notifications=new D(this.cfg))}storageService(){return this._storage??(this._storage=new z(this.cfg))}storage(){return this._storageS3||(this._storageS3=new q(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)}onConnectionStateChange(e){return this.live().onConnectionStateChange(e)}disconnect(){this._conn?.disconnect(),this._conn=void 0;}},R=new Map;function kn(r,e="[DEFAULT]"){if(R.has(e))return R.get(e);let t=new ne(r);return R.set(e,t),t}function $(r="[DEFAULT]"){let e=R.get(r);if(!e)throw new Error(`[flare-admin] No app named "${r}" found. Call connectApp() before getApp().`);return e}function Sn(r="[DEFAULT]"){let e=R.get(r);return e?(e.disconnect(),R.delete(r),true):false}function wn(){for(let r of R.values())r.disconnect();R.clear();}function Cn(r="[DEFAULT]"){return $(r).auth()}function vn(r="[DEFAULT]"){return $(r).db()}function Tn(r="[DEFAULT]"){return $(r).live()}function Rn(r="[DEFAULT]"){return $(r).notifications()}function On(r="[DEFAULT]"){return $(r).storage()}export{P as AdminCollectionReference,I as AdminDocumentReference,U as AdminLiveCollectionReference,L as AdminLiveDocumentReference,Z as AdminStorageSignedAction,ne as FlareAdminApp,E as FlareAdminAuthService,J as FlareAdminConnection,_ as FlareAdminDbService,D as FlareAdminNotificationsService,q as FlareAdminStorageS3,N as FlareAdminWsConnection,un as ServerTimeStamp,mn as ServerTimeStampField,Cn as auth,kn as connectApp,vn as db,wn as disconnectAllApps,Sn as disconnectApp,$ as getApp,Tn as live,Rn as notifications,On as storage};
|
|
1
|
+
import De from'fs';import q from'path';import {fileURLToPath}from'url';import Ie from'ws';var se=(i=>(i.Upload="upload",i.Download="download",i.Delete="delete",i.Edit="edit",i))(se||{});var xe={id:"_id",createdAt:"_createdAt",updatedAt:"_updatedAt"},Ae={_id:"id",_createdAt:"createdAt",_updatedAt:"updatedAt"},D=r=>!!r&&typeof r=="object"&&!Array.isArray(r),x=(r,e)=>Object.keys(r).length===1&&Object.prototype.hasOwnProperty.call(r,e),Z=r=>{if(r instanceof Date)return r.toISOString();if(Array.isArray(r))return r.map(t=>Z(t));if(!D(r))return r;if(x(r,"$date"))return {$date:Z(r.$date)};let e={};for(let[t,n]of Object.entries(r))e[t]=Z(n);return e},f=r=>{let e=String(r??"").trim();return e&&(xe[e]??e)},je=r=>{let e=String(r??"").trim();return e&&(Ae[e]?Ae[e]:e.startsWith("_")&&!e.startsWith("__")&&e.length>1?e.slice(1):e)},_e=r=>"field"in r&&"op"in r,C=r=>{if(r instanceof Date)return {$date:r.toISOString()};if(Array.isArray(r))return r.map(t=>C(t));if(!D(r))return r;if(x(r,"$oid"))return {$oid:String(r.$oid??"")};if(x(r,"$date"))return {$date:Z(r.$date)};let e={};for(let[t,n]of Object.entries(r)){let i=f(t);if(i==="_id"){if(typeof n=="string"){e[i]={$oid:n};continue}if(D(n)&&x(n,"$oid")){e[i]={$oid:String(n.$oid??"")};continue}}e[i]=C(n);}return e},X=r=>{if(Array.isArray(r))return r.map(t=>X(t));if(!D(r))return r;if(x(r,"$oid"))return String(r.$oid??"");if(x(r,"$date")){let t=r.$date;if(t instanceof Date)return Number.isNaN(t.getTime())?null:t;if(typeof t=="string"||typeof t=="number"){let n=new Date(t);return Number.isNaN(n.getTime())?null:n}if(D(t)&&typeof t.$numberLong=="string"){let n=Number(t.$numberLong);if(!Number.isFinite(n))return null;let i=new Date(n);return Number.isNaN(i.getTime())?null:i}return null}let e={};for(let[t,n]of Object.entries(r)){let i=je(t);if(t==="_id"){if(typeof n=="string"){e.id=n;continue}if(D(n)&&x(n,"$oid")){e.id=String(n.$oid??"");continue}}e[i]=X(n);}return e},I=r=>"or"in r&&Array.isArray(r.or)?{...r,or:r.or.map(e=>I(e))}:"and"in r&&Array.isArray(r.and)?{...r,and:r.and.map(e=>I(e))}:_e(r)?{...r,field:f(r.field),value:C(r.value)}:r,Y=r=>{if(!r||typeof r!="object")return r;let e=r,t={...e},n=i=>{let o={...i};return o.localField=f(String(i?.localField??"")),o.foreignField=f(String(i?.foreignField??"")),Array.isArray(i.where)&&(o.where=i.where.map(s=>I(s))),Array.isArray(i.orderBy)&&(o.orderBy=i.orderBy.map(s=>({...s,field:f(String(s?.field??""))}))),i.groupBy&&typeof i.groupBy=="object"&&Array.isArray(i.groupBy.fields)&&(o.groupBy={...i.groupBy,fields:i.groupBy.fields.map(s=>f(String(s??"")))}),Array.isArray(i.having)&&(o.having=i.having.map(s=>({...s,field:f(String(s?.field??""))}))),Array.isArray(i.select)&&(o.select=i.select.map(s=>f(String(s??"")))),typeof i.distinctField=="string"&&(o.distinctField=f(i.distinctField)),i.vectorSearch&&typeof i.vectorSearch=="object"&&(o.vectorSearch={...i.vectorSearch,field:f(String(i.vectorSearch.field??""))}),Array.isArray(i.joins)&&(o.joins=i.joins.map(s=>n(s))),o};return Array.isArray(e.where)&&(t.where=e.where.map(i=>I(i))),Array.isArray(e.orderBy)&&(t.orderBy=e.orderBy.map(i=>({...i,field:f(String(i?.field??""))}))),e.groupBy&&typeof e.groupBy=="object"&&Array.isArray(e.groupBy.fields)&&(t.groupBy={...e.groupBy,fields:e.groupBy.fields.map(i=>f(String(i??"")))}),Array.isArray(e.having)&&(t.having=e.having.map(i=>({...i,field:f(String(i?.field??""))}))),Array.isArray(e.select)&&(t.select=e.select.map(i=>f(String(i??"")))),typeof e.distinctField=="string"&&(t.distinctField=f(e.distinctField)),e.vectorSearch&&typeof e.vectorSearch=="object"&&(t.vectorSearch={...e.vectorSearch,field:f(String(e.vectorSearch.field??""))}),Array.isArray(e.joins)&&(t.joins=e.joins.map(i=>n(i))),t};function Ee(r,e){let t=r.dataMapper;if(!t||typeof t!="object")return null;let n=t[e];return typeof n=="function"?n:null}function ae(r,e,t){let n=Ee(r,e);if(!n||t==null||typeof t!="object")return t;try{return n(t)}catch{return t}}function ce(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 o=String(i?.as??"").trim();if(!o)continue;let s=Array.isArray(i?.joins)?i.joins:[],a=n[o],l=a;Array.isArray(a)?l=a.map(c=>ce(r,c,s)):a&&typeof a=="object"&&(l=ce(r,a,s)),l=Array.isArray(l)?l.map(c=>ae(r,o,c)):ae(r,o,l),l!==a&&(n===e&&(n={...n}),n[o]=l);}return n}function P(r,e,t,n){let i=Array.isArray(n?.joins)?n.joins:[],o=s=>{let a=ce(r,X(s),i);return ae(r,e,a)};return Array.isArray(t)?t.map(s=>o(s)):o(t)}var Le=()=>typeof process<"u"&&!!process.versions?.node,w=r=>{if(r.transport==="http")return false;let e=!!(r.grpcUrl&&r.grpcUrl.trim().length>0),t=Le();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},L=r=>{try{return JSON.stringify(r??{})}catch{return "{}"}},$=r=>r?.field&&r?.op?{queryFilter:{field:String(r.field),op:String(r.op),valueJson:L(r.value)}}:Array.isArray(r?.or)?{orFilter:{or:r.or.map(e=>$(e))}}:Array.isArray(r?.and)?{andFilter:{and:r.and.map(e=>$(e))}}:{queryFilter:{field:"",op:"==",valueJson:"null"}},ee=r=>{if(!(!r||!Array.isArray(r.values)))return {valuesJson:r.values.map(e=>L(e))}},ye=r=>({from:r.from,localField:r.localField,foreignField:r.foreignField,as:r.as,single:!!r.single,where:Array.isArray(r.where)?r.where.map($):[],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(ye):[]}),Ue=r=>({where:Array.isArray(r.where)?r.where.map($):[],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:ee(r.startAt),startAfter:ee(r.startAfter),endAt:ee(r.endAt),endBefore:ee(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(ye):[],select:Array.isArray(r.select)?r.select:[],distinctField:r.distinctField??""});async function T(r){let e=await import('@grpc/grpc-js'),t=await import('@grpc/proto-loader'),n=q.dirname(fileURLToPath(import.meta.url)),i=[q.resolve(n,"../../proto"),q.resolve(n,"../proto"),q.resolve(process.cwd(),"proto")],o=i.find(m=>De.existsSync(q.join(m,"flare.proto")))??i[0],s=q.join(o,"flare.proto"),a=await t.load(s,{keepCase:false,longs:String,enums:String,defaults:true,oneofs:true,includeDirs:[o]}),c=e.loadPackageDefinition(a).flare;return new c.AdminService(r,e.credentials.createInsecure())}function R(r,e,t){return new Promise((n,i)=>{r[e](t,(o,s)=>{if(o)return i(o);n(s??{});});})}function O(r,e){if(r.error)throw new Error(`[flare-admin][grpc] ${e} failed: ${r.errorDescription||r.error}`)}async function be(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(n,"AdminQuery",{app_id:r.appId,admin_key:r.adminKey,collection:e,query:Ue(Y(t))});O(i,"admin_query");try{let o=JSON.parse(i.dataJson||"[]");return Array.isArray(o)?o:[]}catch{return []}}async function ke(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(n,"CreateCustomToken",{app_id:r.appId,admin_key:r.adminKey,uid:e,role:t.role??"user",claims_json:L(t.claims??{}),ttl:t.ttl??r.defaultTtl});if(O(i,"create_custom_token"),!i.token)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return String(i.token)}async function Se(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(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 O(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 we(r,e,t){if(!w(r))return;let n=await T(r.grpcUrl),i=await R(n,"GetDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});if(O(i,"get_document"),!i.found)return null;try{return JSON.parse(i.dataJson||"{}")}catch{return {}}}async function Ce(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(n,"CreateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,data_json:L(C(t))});return O(i,"create_document"),String(i.id??"")}async function ve(r,e,t,n){if(!w(r))return null;let i=await T(r.grpcUrl),o=await R(i,"ReplaceDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:L(C(n))});return O(o,"replace_document"),true}async function Te(r,e,t,n){if(!w(r))return null;let i=await T(r.grpcUrl),o=await R(i,"UpdateDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t,data_json:L(C(n))});return O(o,"update_document"),true}async function Re(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(n,"DeleteDocument",{app_id:r.appId,admin_key:r.adminKey,collection:e,doc_id:t});return O(i,"delete_document"),!!i.deleted}async function Oe(r,e,t){if(!w(r))return null;let n=await T(r.grpcUrl),i=await R(n,"DeleteMany",{app_id:r.appId,admin_key:r.adminKey,collection:e,where:(t??[]).map(o=>$(I(o)))});return O(i,"delete_many"),Number(i.deleted??0)}var Fe=r=>r.replace(/\/$/,""),$e=r=>{let e=String(r.httpBase??"").trim();return Fe(e||r.serverUrl)},b=(r,e)=>{let t=$e(r),n=e.startsWith("/")?e:`/${e}`;return `${t}${n}`};function te(r){let e=[];for(let[t,n]of Object.entries(r))if(typeof n=="string"){let i=n.match(/^(>=|<=|!=|>|<|==)\s*(.+)$/);if(i){let[,o,s]=i;e.push({field:t,op:o,value:Ne(s.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 Ne(r){return isNaN(Number(r))?r==="true"?true:r==="false"?false:r==="null"?null:r:Number(r)}function de(){return Math.random().toString(36).slice(2,12)+Date.now().toString(36)}var j=class{constructor(e,t,n){this.cfg=e;this.collection=t;this.id=n;}get baseUrl(){return b(this.cfg,`/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(C(t))}:{}});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (${e} ${this.baseUrl}): ${s}`)}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 we(this.cfg,this.collection,this.id);if(e!==void 0)return e===null?null:P(this.cfg,this.collection,e)??null;let t;try{t=await fetch(this.baseUrl,{headers:this.headers});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (GET ${this.baseUrl}): ${s}`)}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 P(this.cfg,this.collection,n.data)??null}async set(e){await ve(this.cfg,this.collection,this.id,e)===null&&await this.request("PUT",e);}async update(e){await Te(this.cfg,this.collection,this.id,e)===null&&await this.request("PATCH",e);}async delete(){await Re(this.cfg,this.collection,this.id)===null&&await this.request("DELETE");}parent(){return new _(this.cfg,this.collection)}};var _=class r{constructor(e,t){this.cfg=e;this.name=t;this.sq={};this.opts={allowSensitiveAuthUserFields:true};}get baseUrl(){return b(this.cfg,`/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 te(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 o=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[o,...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 o=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(o.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let s=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(o,i,s))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:o})}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 be(this.cfg,this.name,this.sq);if(e)return P(this.cfg,this.name,e,this.sq)??[];let t=new URL(this.baseUrl);t.searchParams.set("query",JSON.stringify(Y(this.sq))),t.searchParams.set("allowSensitiveAuthUserFields",this.opts.allowSensitiveAuthUserFields?"1":"0");let n;try{n=await fetch(t.toString(),{headers:this.headers});}catch(s){let a=s instanceof Error?s.message:String(s);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 P(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 Ce(this.cfg,this.name,e);if(t!==null)return new j(this.cfg,this.name,t);let n;try{n=await fetch(this.baseUrl,{method:"POST",headers:this.headers,body:JSON.stringify(C(e))});}catch(o){let s=o instanceof Error?o.message:String(o);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}): ${s}`)}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 j(this.cfg,this.name,i.id)}async update(e,t){let n=this.doc(e);return await n.update(t),n}ensureBulkOptions(e){let t=Number(e?.batchSize??250),n=Number(e?.concurrency??1);return {...e,batchSize:Number.isFinite(t)&&t>0?Math.floor(t):250,concurrency:Number.isFinite(n)&&n>0?Math.floor(n):1,continueOnError:e?.continueOnError===true}}toPercent(e,t){if(!(typeof t!="number"||t<=0))return Math.round(e/t*100)}emitBulkProgress(e,t,n){n&&n({operation:e,...t,percent:this.toPercent(t.processed,t.total)});}async*chunkIterable(e,t){let n=[];for await(let i of e)n.push(i),n.length>=t&&(yield n,n=[]);n.length>0&&(yield n);}assertBulkSignal(e){if(e?.aborted)throw new Error("Bulk write aborted")}async runChunkWorkers(e,t,n,i,o,s,a=false,l){let c=0,m=async()=>{for(;c<t.length;){this.assertBulkSignal(l);let y=c;c+=1;let k=t[y];try{let S=await i(k);o.succeeded+=1,o.processed+=1,this.emitBulkProgress(e,{processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total,lastDocId:S.docId},s);}catch(S){if(o.failed+=1,o.processed+=1,this.emitBulkProgress(e,{processed:o.processed,succeeded:o.succeeded,failed:o.failed,total:o.total,lastError:S},s),!a)throw S}}},d=Math.max(1,Math.min(n,t.length));await Promise.all(Array.from({length:d},()=>m()));}async runBulkWrite(e,t,n,i){let o=this.ensureBulkOptions(i);this.assertBulkSignal(o.signal);let s={processed:0,succeeded:0,failed:0,total:Array.isArray(t)?t.length:void 0};this.emitBulkProgress(e,{processed:0,succeeded:0,failed:0,total:s.total},o.onProgress);for await(let a of this.chunkIterable(t,o.batchSize))this.assertBulkSignal(o.signal),await this.runChunkWorkers(e,a,o.concurrency,n,s,o.onProgress,o.continueOnError,o.signal);return {operation:e,processed:s.processed,succeeded:s.succeeded,failed:s.failed,total:s.total}}async addMany(e,t){return this.runBulkWrite("addMany",e,async n=>({docId:(await this.add(n)).id}),t)}async updateMany(e,t){return this.runBulkWrite("updateMany",e,async n=>(await this.doc(n.id).update(n.data),{docId:n.id}),t)}async deleteMany(e,t){return e==null?this.deleteManyByQuery():this.runBulkWrite("deleteMany",e,async n=>(await this.doc(n).delete(),{docId:n}),t)}async deleteManyByQuery(){let e=await Oe(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??[]).map(i=>I(i))})});}catch(i){let o=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (DELETE ${this.baseUrl}): ${o}`)}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 j(this.cfg,this.name,e)}};var N=class{constructor(e){this.cfg=e;}collection(e){return new _(this.cfg,e)}};var J=class{constructor(e){this.cfg=e;}async createCustomToken(e,t={}){if(w(this.cfg)){let a=await ke(this.cfg,String(e),t);if(!a)throw new Error("[flare-admin][grpc] create_custom_token returned empty token");return a}let n=b(this.cfg,"/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}),o;try{o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(a){let l=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Could not reach FlareServer at "${n}": ${l}
|
|
2
|
+
Make sure FLARE_URL is set correctly and the server is running.`)}let s;try{s=await o.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${o.status})`)}if(!o.ok)throw new Error(`[flare-admin] createCustomToken failed (HTTP ${o.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,t={}){if(w(this.cfg)){let l=await Se(this.cfg,String(e),t);if(!l)throw new Error("[flare-admin][grpc] create_auth_ticket returned empty payload");return l}let n=b(this.cfg,"/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}),o;try{o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`},body:i});}catch(l){let c=l instanceof Error?l.message:String(l);throw new Error(`[flare-admin] Could not reach FlareServer at "${n}": ${c}
|
|
3
|
+
Make sure FLARE_URL is set correctly and the server is running.`)}let s;try{s=await o.json();}catch{throw new Error(`[flare-admin] Server returned non-JSON response (status ${o.status})`)}if(!o.ok)throw new Error(`[flare-admin] getTicket failed (HTTP ${o.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??t.role??"user"),ip:String(a.ip??"unknown")}}};var M=class{constructor(e){this.cfg=e;}get baseUrl(){return b(this.cfg,`/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 o=i instanceof Error?i.message:String(i);throw new Error(`[flare-admin] Network error (POST ${this.baseUrl}/send): ${o}`)}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 ne=class{constructor(e){this.cfg=e;}base(e){return b(this.cfg,`/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,o=this.base(t);try{i=await fetch(o,{method:e,headers:this.headers,...n!==void 0?{body:JSON.stringify(n)}:{}});}catch(a){let l=a instanceof Error?a.message:String(a);throw new Error(`[flare-admin] Network error (${e} ${o}): ${l}`)}let s=await i.json().catch(()=>({}));if(!i.ok)throw new Error(`[flare-admin] ${e} ${o} failed (HTTP ${i.status}): `+(s.error??"Unknown error"));return s}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 le(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 Je(r){return r===void 0?"":typeof r=="string"?le(new TextEncoder().encode(r)):Buffer&&Buffer.isBuffer(r)?r.toString("base64"):r instanceof Uint8Array?le(r):r instanceof ArrayBuffer?le(new Uint8Array(r)):""}function Me(r){return Buffer?Buffer.from(String(r)).toString("base64"):btoa(String(r))}function We(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 He(r){return (String(r??"").split("/").pop()??"download").replace(/["\\\r\n]/g,"")||"download"}var W=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 l=(await this.listBuckets()).find(c=>c.id===i);if(l)return l}let o;try{o=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 d=(await this.listBuckets()).find(y=>y.id===c);if(d)return d}}throw a}let s={id:o.serverId,name:n,bucket:n,kind:t.kind??"managed",prefix:t.prefix};return this._bucketCache.set(n,s.id),s}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(o){n[i]=o instanceof Error?o.message:String(o);}})),{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),n=e.encrypt??false,i=e.access??"public";if(e.contentBase64!==void 0){let d=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:e.contentBase64,contentType:e.contentType,access:i,encrypt:n});return {ok:d.ok,bucket:e.bucket,key:String(d.path??e.key),access:String(d.access??i),url:typeof d.url=="string"?d.url:void 0,size:Number(d.size??0),encrypted:!!d.encrypted}}let o=4*1024*1024,s=e.base64MaxBytes??o,a;if(typeof e.body=="string"?a=new TextEncoder().encode(e.body).length:(e.body instanceof Uint8Array||e.body instanceof ArrayBuffer||Buffer&&Buffer.isBuffer(e.body))&&(a=e.body.byteLength),a!==void 0&&a>s){let d=await this.createSignedUrl({bucket:e.bucket,key:e.key,action:"upload",expiresInSeconds:300,sizeBytes:a,contentType:e.contentType,access:i,encrypt:n}),y;typeof e.body=="string"?y=new TextEncoder().encode(e.body):y=e.body;let k=await fetch(d.url,{method:d.method??"PUT",headers:{...e.contentType?{"Content-Type":e.contentType}:{}},body:y});if(!k.ok){let E=await k.text().catch(()=>"");throw new Error(`[flare-admin] Signed-URL upload failed (HTTP ${k.status}): ${E}`)}let S=await k.text().catch(()=>""),A={};if(S)try{A=JSON.parse(S);}catch{throw new Error("[flare-admin] Failed to parse signed upload response")}return {ok:!!(A.ok??true),bucket:e.bucket,key:String(A.path??e.key),access:String(A.access??i),url:typeof A.url=="string"?A.url:void 0,size:Number(A.size??a??0),encrypted:!!(A.encrypted??n)}}let c=await Je(e.body),m=await this._svc.uploadObject({serverId:t,path:e.key,contentBase64:c,contentType:e.contentType,access:i,encrypt:n});return {ok:m.ok,bucket:e.bucket,key:String(m.path??e.key),access:String(m.access??i),url:typeof m.url=="string"?m.url:void 0,size:Number(m.size??0),encrypted:!!m.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??He(e.key),o=globalThis.document;if(!o)return {ok:true,url:n,filename:i,triggered:false};let s=o.createElement("a");return s.href=n,e.openInNewTab?s.target="_blank":s.download=i,s.rel="noopener noreferrer",o.body?.appendChild(s),s.click(),s.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"),access:typeof n.access=="string"?n.access:void 0,url:typeof n.url=="string"?n.url:void 0,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?We(e.cursor):0,i=Math.max(1,Math.min(e.limit??100,1e3)),o=await this._svc.request("POST","/object/list",{serverId:t,prefix:e.prefix,limit:i,skip:n}),s=Array.isArray(o.objects)?o.objects:[],a=!!o.hasMore,l=Number(o.count??s.length);return {bucket:e.bucket,objects:s.map(c=>({bucket:e.bucket,key:String(c.path??c.key??""),size:Number(c.size??0),contentType:String(c.contentType??"application/octet-stream"),access:typeof c.access=="string"?c.access:void 0,url:typeof c.url=="string"?c.url:void 0,encrypted:!!c.encrypted,createdAt:c.createdAt,updatedAt:c.updatedAt})),count:l,hasMore:a,cursor:a?Me(n+s.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 H=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 z=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 te(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 o=t.length===1?t[0]:{and:t};return this.clone({where:[{or:[o,...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 o=(this.sq.joins??[]).map(a=>this.cloneStructuredJoin(a));if(o.length===0)throw new Error(`joinNested parent alias "${i}" not found`);let s=this.buildStructuredJoin(t,n);if(!this.appendNestedJoinByAlias(o,i,s))throw new Error(`joinNested parent alias "${i}" not found`);return this.clone({joins:o})}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 H(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}stream(e={}){let t=this._buildSq(),n=new Set,i=[],o=new Map,s=Math.max(0,Number(e.flushMs??24)),a=Math.max(1,Number(e.maxBatchSize??200)),l=e.insertAt??"end",c=typeof e.maxDocs=="number"&&e.maxDocs>0?Math.floor(e.maxDocs):void 0,m=String(e.idField??"id"),d=[],y=false,k=false,S=0,A,E=()=>{o.clear();for(let u=0;u<d.length;u+=1){let h=me(d[u]);h&&o.set(h,u);}},me=(u,h)=>{if(h)return h;if(u==null)return;if(typeof e.getId=="function"){let F=e.getId(u);if(typeof F=="string"&&F.length>0)return F}let v=u?.[m]??u?._id??u?.docId;if(typeof v=="string"&&v.length>0)return v},pe=()=>{c==null||d.length<=c||(d=d.slice(0,c));},ge=()=>{typeof e.sort=="function"&&(d=d.slice().sort(e.sort));},he=(u,h)=>{S+=1;let v=d.slice(),F={reason:u,batchSize:h,version:S,ready:k};for(let V of Array.from(n))try{V(v,F);}catch{}},re=()=>{A!=null&&(clearTimeout(A),A=void 0);},Pe=u=>{if(u.operation==="delete"){let V=o.get(u.docId??"");if(V==null)return;d.splice(V,1),E();return}let h=u.data;if(h==null)return;let v=me(h,u.docId);if(!v)return;let F=o.get(v);if(typeof F=="number"){d[F]=h;return}l==="start"?d.unshift(h):d.push(h),pe(),E();},fe=()=>{if(y||i.length===0)return;re();let u=i.splice(0,i.length);for(let h of u)Pe(h);ge(),E(),he("change-batch",u.length);},Be=()=>{y||A!=null||(A=setTimeout(fe,s));},ie=this.conn.subscribe(this.name,void 0,t,u=>{if(!y){if(u.type==="snapshot"){d=Array.isArray(u.data)?[...u.data]:[],k=true,re(),i.length=0,ge(),pe(),E(),he("snapshot",0);return}if(i.push({docId:u.docId,operation:u.operation,data:u.data??null}),i.length>=a){fe();return}Be();}}),oe={subscribe(u,h=true){if(n.add(u),h){let v={reason:k?"change-batch":"snapshot",batchSize:0,version:S,ready:k};try{u(d.slice(),v);}catch{}}return ()=>{n.delete(u);}},getSnapshot(){return d.slice()},isReady(){return k},getVersion(){return S},close:()=>{y||(y=true,re(),i.length=0,n.clear(),ie());},onError(u){return ie.onError(u),oe},onPermissionDenied(u){return ie.onPermissionDenied(u),oe}};return oe}asStore(e={}){let t=this.stream(e);return {subscribe:n=>t.subscribe(()=>{n();},false),getSnapshot:()=>t.getSnapshot(),getServerSnapshot:()=>[],stream:t,destroy:()=>{t.close();}}}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 G=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;this._state="disconnected";this._stateListeners=[];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._setState("connecting"),this._connect();}ready(){return this._readyPromise}get connectionState(){return this._state}onConnectionStateChange(e){return this._stateListeners.push(e),()=>{this._stateListeners=this._stateListeners.filter(t=>t!==e);}}disconnect(){this.shouldReconnect=false,this.ws?.close(1e3,"Admin disconnect"),this.ws=null,this.connected=false,this._setState("disconnected");}send(e,t){return new Promise((n,i)=>{let o=de(),s={id:o,type:e,ts:Date.now(),...t},a=setTimeout(()=>{this.pendingAcks.delete(o),i(new Error(`[flare-admin] WS request timeout (${e})`));},1e4);this.pendingAcks.set(o,c=>{clearTimeout(a),c.type==="error"?i(new Error(`[flare-admin] Server error: ${c.message}`)):n(c);});let l=()=>this.ws?.send(JSON.stringify(s));this.connected&&this.ws?.readyState===Ie.OPEN?l():this.ready().then(l).catch(i);})}subscribe(e,t,n,i,o={}){let s=de(),a={baseId:s,liveId:s,collection:e,docId:t,structuredQuery:n,callback:i,options:o};this.activeSubscriptions.set(s,a),this.subscriptionErrorHandlers.set(s,new Set),this.subscriptionPermissionHandlers.set(s,new Set),this.activateSubscription(a);let l=()=>{let d=this.activeSubscriptions.get(s)?.liveId??s;this.activeSubscriptions.delete(s),this.subscriptions.delete(s),this.subscriptions.delete(d),this.subscriptionErrorHandlers.delete(s),this.subscriptionPermissionHandlers.delete(s),this.subscriptionLastErrors.delete(s),this.connected&&this.send("unsubscribe",{subscriptionId:d}).catch(()=>{});},c=l;return c.unsubscribe=l,c.onError=m=>{this.subscriptionErrorHandlers.get(s)?.add(m);let d=this.subscriptionLastErrors.get(s);if(d)try{m(d);}catch{}return c},c.onPermissionDenied=m=>{this.subscriptionPermissionHandlers.get(s)?.add(m);let d=this.subscriptionLastErrors.get(s);if(d?.permissionDenied)try{m(d);}catch{}return c},c.catch=m=>c.onError(m),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 o=i.subscriptionId;if(o&&o!==e.liveId){let s=this.subscriptions.get(e.liveId);s&&(this.subscriptions.delete(e.liveId),this.subscriptions.set(o,s),e.liveId=o);}}).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],o=(n?.[2]??t).trim()||t,s=i==="PERMISSION_DENIED"||t.includes("PERMISSION_DENIED");return {code:i,message:o,permissionDenied:s,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 o of i)try{o(t);}catch{}}}_setState(e){if(this._state!==e){this._state=e;for(let t of this._stateListeners.slice())try{t(e);}catch{}}}_connect(){this._readyPromise=new Promise(e=>{this._readyResolve=e;}),this.ws=new Ie(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?(this._setState("reconnecting"),setTimeout(()=>{this.reconnectDelay=Math.min(this.reconnectDelay*2,3e4),this._connect();},this.reconnectDelay)):this._setState("disconnected");}),this.ws.on("error",()=>{this._setState("error");});}_handle(e){let t=e.type;if(t==="auth_ok"){this.connected||(this.connected=true,this.reconnectDelay=2e3,this._setState("connected"),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 o=Array.from(this.activeSubscriptions.values()).find(s=>s.liveId===n||s.baseId===n);if(o){let s=this.toSubscriptionError(new Error(`[${String(e.code??"ERROR")}] ${String(e.message??"Unknown error")}`));this.emitSubscriptionError(o.baseId,s);}}return}if(t==="snapshot"||t==="change"){let n=e.subscriptionId,i=this.subscriptions.get(n);if(i){let o=Array.from(this.activeSubscriptions.values()).find(l=>l.liveId===n),s=String(e.collection??o?.collection??""),a=t==="change"&&e.operation==="delete"?null:P(this.cfg,s,e.data,o?.structuredQuery);i({subscriptionId:n,collection:s,docId:e.docId,data:a,type:t==="snapshot"?"snapshot":"change",operation:e.operation});}}}};var Q=class{constructor(e){this._ws=new G(e);}collection(e){return new z(this._ws,e)}ready(){return this._ws.ready()}get connectionState(){return this._ws.connectionState}onConnectionStateChange(e){return this._ws.onConnectionStateChange(e)}disconnect(){this._ws.disconnect();}};var U=class{constructor(e,t=e.appId){this.cfg=e;this.targetAppId=t;}get appId(){return this.targetAppId}get callerAppId(){return this.cfg.appId}baseUrl(e){return b(this.cfg,`/system/apps/${e??this.appId}/functions`)}get authParams(){return new URLSearchParams({appId:this.callerAppId,adminKey:this.cfg.adminKey}).toString()}get headers(){return {"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.adminKey}`}}url(e){let t=`${this.baseUrl()}${e}`;return `${t}${t.includes("?")?"&":"?"}${this.authParams}`}async request(e,t){let n=this.url(e),i;try{i=await fetch(n,{...t,headers:{...this.headers,...t?.headers??{}}});}catch(s){let a=s instanceof Error?s.message:String(s);throw new Error(`[flare-admin/functions] Network error (${t?.method??"GET"} ${n}): ${a}`)}let o=await i.json().catch(()=>({}));if(!i.ok||o.ok===false){let s=String(o.error??o.message??"unknown_error");throw new Error(`[flare-admin/functions] Request failed (HTTP ${i.status}): ${s}`)}return o}extractFunction(e){return e.function??e.item??e}async list(){let e=await this.request("");return Array.isArray(e.list)?e.list:[]}async get(e){try{let t=await this.request(`/${e}`);return this.extractFunction(t)}catch(t){let n=t instanceof Error?t.message:String(t);if(n.includes("not_found")||n.includes("HTTP 404"))return null;throw t}}async create(e){let t=await this.request("",{method:"POST",body:JSON.stringify(e)});return this.extractFunction(t)}async patch(e,t){let n=await this.request(`/${e}`,{method:"PATCH",body:JSON.stringify(t)});return this.extractFunction(n)}async upsert(e,t){return await this.get(e)?this.patch(e,{name:t.name,enabled:t.enabled,scope:t.scope,target:t.target,timeoutMs:t.timeoutMs}):this.create({...t,id:e})}async delete(e){let t=await this.request(`/${e}`,{method:"DELETE"});return {ok:!!(t.ok??true),id:String(t.id??e)}}async invoke(e,t){let n=await this.request(`/${e}/invoke`,{method:"POST",body:JSON.stringify(t??{})});return {ok:!!(n.ok??true),functionId:String(n.functionId??e),status:n.status??"success",output:n.output,error:n.error,durationMs:typeof n.durationMs=="number"?n.durationMs:void 0,executionId:n.executionId}}async executions(e){let t=new URLSearchParams;e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.cursor&&t.set("cursor",e.cursor);let n=t.size?`/executions?${t.toString()}`:"/executions",i=await this.request(n);return {list:Array.isArray(i.list)?i.list:[],total:Number(i.total??0)}}async validate(e,t){try{let n=await this.request("/validate",{method:"POST",body:JSON.stringify({source:e,functionId:t})});return {valid:!!(n.valid??!1),diagnostics:Array.isArray(n.diagnostics)?n.diagnostics:[],mode:n.mode??"server"}}catch{return {valid:false,diagnostics:[],mode:"unavailable"}}}};var jn="ServerTimeStamp",_n={$serverTimestamp:true};var ue=class{constructor(e){this.cfg={defaultTtl:"24h",transport:"auto",...e,serverUrl:e.serverUrl.replace(/\/$/,""),httpBase:e.httpBase?.replace(/\/$/,"")??"",grpcUrl:e.grpcUrl??"",dataMapper:e.dataMapper??{}};}auth(){return this._auth??(this._auth=new J(this.cfg))}db(){return this._db??(this._db=new N(this.cfg))}generateFlareId(){return crypto.randomUUID().replace(/-/g,"").substring(0,20)}doc(e){let t=this.generateFlareId(),n=this.db().collection(e).doc(t);return n.id=t,n}live(){return this._conn??(this._conn=new Q(this.cfg))}functions(){return this._functions??(this._functions=new U(this.cfg))}functionsFor(e){return new U(this.cfg,e)}notifications(){return this._notifications??(this._notifications=new M(this.cfg))}storageService(){return this._storage??(this._storage=new ne(this.cfg))}storage(){return this._storageS3||(this._storageS3=new W(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)}onConnectionStateChange(e){return this.live().onConnectionStateChange(e)}disconnect(){this._conn?.disconnect(),this._conn=void 0;}},B=new Map;function Mn(r,e="[DEFAULT]"){if(B.has(e))return B.get(e);let t=new ue(r);return B.set(e,t),t}function K(r="[DEFAULT]"){let e=B.get(r);if(!e)throw new Error(`[flare-admin] No app named "${r}" found. Call connectApp() before getApp().`);return e}function Wn(r="[DEFAULT]"){let e=B.get(r);return e?(e.disconnect(),B.delete(r),true):false}function Hn(){for(let r of B.values())r.disconnect();B.clear();}function zn(r="[DEFAULT]"){return K(r).auth()}function Gn(r="[DEFAULT]"){return K(r).db()}function Qn(r="[DEFAULT]"){return K(r).live()}function Kn(r="[DEFAULT]"){return K(r).notifications()}function Vn(r="[DEFAULT]"){return K(r).storage()}export{_ as AdminCollectionReference,j as AdminDocumentReference,z as AdminLiveCollectionReference,H as AdminLiveDocumentReference,se as AdminStorageSignedAction,ue as FlareAdminApp,J as FlareAdminAuthService,Q as FlareAdminConnection,N as FlareAdminDbService,U as FlareAdminFunctionsService,M as FlareAdminNotificationsService,W as FlareAdminStorageS3,G as FlareAdminWsConnection,jn as ServerTimeStamp,_n as ServerTimeStampField,zn as auth,Mn as connectApp,Gn as db,Hn as disconnectAllApps,Wn as disconnectApp,K as getApp,Qn as live,Kn as notifications,Vn as storage};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AdminCloudFunction, AdminCreateFunctionInput, AdminFunctionExecution, AdminFunctionValidationResult, AdminInvokeFunctionInput, AdminInvokeFunctionResult, AdminPatchFunctionInput, FlareAdminConfig, FlareAdminFunctions } from "../types";
|
|
2
|
+
export declare class FlareAdminFunctionsService implements FlareAdminFunctions {
|
|
3
|
+
private readonly cfg;
|
|
4
|
+
private readonly targetAppId;
|
|
5
|
+
constructor(cfg: Required<FlareAdminConfig>, targetAppId?: string);
|
|
6
|
+
private get appId();
|
|
7
|
+
private get callerAppId();
|
|
8
|
+
private baseUrl;
|
|
9
|
+
private get authParams();
|
|
10
|
+
private get headers();
|
|
11
|
+
private url;
|
|
12
|
+
private request;
|
|
13
|
+
private extractFunction;
|
|
14
|
+
list(): Promise<AdminCloudFunction[]>;
|
|
15
|
+
get(functionId: string): Promise<AdminCloudFunction | null>;
|
|
16
|
+
create(input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
17
|
+
patch(functionId: string, input: AdminPatchFunctionInput): Promise<AdminCloudFunction>;
|
|
18
|
+
upsert(functionId: string, input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
19
|
+
delete(functionId: string): Promise<{
|
|
20
|
+
ok: boolean;
|
|
21
|
+
id: string;
|
|
22
|
+
}>;
|
|
23
|
+
invoke(functionId: string, input?: AdminInvokeFunctionInput): Promise<AdminInvokeFunctionResult>;
|
|
24
|
+
executions(opts?: {
|
|
25
|
+
limit?: number;
|
|
26
|
+
cursor?: string;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
list: AdminFunctionExecution[];
|
|
29
|
+
total: number;
|
|
30
|
+
}>;
|
|
31
|
+
validate(source: string, functionId?: string): Promise<AdminFunctionValidationResult>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AnyFilter } from "../types";
|
|
2
|
+
export declare const toWireField: (field: string) => string;
|
|
3
|
+
export declare const fromWireField: (field: string) => string;
|
|
4
|
+
export declare const normalizeAdminOutboundData: (value: unknown) => unknown;
|
|
5
|
+
export declare const normalizeAdminInboundData: (value: unknown) => unknown;
|
|
6
|
+
export declare const normalizeAdminOutboundAnyFilter: (filter: AnyFilter) => AnyFilter;
|
|
7
|
+
export declare const normalizeAdminOutboundQuery: (query: unknown) => unknown;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -144,6 +144,7 @@ export interface AdminStorageUploadInput {
|
|
|
144
144
|
path: string;
|
|
145
145
|
contentBase64: string;
|
|
146
146
|
contentType?: string;
|
|
147
|
+
access?: "public" | "private";
|
|
147
148
|
encrypt?: boolean;
|
|
148
149
|
}
|
|
149
150
|
export interface AdminStorageDownloadInput {
|
|
@@ -159,6 +160,8 @@ export interface AdminStorageObjectResult {
|
|
|
159
160
|
ok: boolean;
|
|
160
161
|
path: string;
|
|
161
162
|
key: string;
|
|
163
|
+
access?: "public" | "private";
|
|
164
|
+
url?: string;
|
|
162
165
|
encrypted?: boolean;
|
|
163
166
|
size?: number;
|
|
164
167
|
contentBase64?: string;
|
|
@@ -177,6 +180,7 @@ export interface AdminStorageSignedUrlInput {
|
|
|
177
180
|
expiresInSeconds?: number;
|
|
178
181
|
sizeBytes?: number;
|
|
179
182
|
contentType?: string;
|
|
183
|
+
access?: "public" | "private";
|
|
180
184
|
encrypt?: boolean;
|
|
181
185
|
decrypt?: boolean;
|
|
182
186
|
forceDownload?: boolean;
|
|
@@ -341,6 +345,8 @@ export interface AdminStorageObjectMeta {
|
|
|
341
345
|
bucket: string;
|
|
342
346
|
size: number;
|
|
343
347
|
contentType: string;
|
|
348
|
+
access?: "public" | "private";
|
|
349
|
+
url?: string;
|
|
344
350
|
encrypted: boolean;
|
|
345
351
|
createdAt?: unknown;
|
|
346
352
|
updatedAt?: unknown;
|
|
@@ -352,7 +358,9 @@ export interface AdminPutObjectInput {
|
|
|
352
358
|
/** Pre-encoded base64 body. Mutually exclusive with `body`. Always uses base64 path. */
|
|
353
359
|
contentBase64?: string;
|
|
354
360
|
contentType?: string;
|
|
355
|
-
/**
|
|
361
|
+
/** Public/private object access. Defaults to public. */
|
|
362
|
+
access?: "public" | "private";
|
|
363
|
+
/** Encrypt at rest with AES-256-GCM. Defaults to false. */
|
|
356
364
|
encrypt?: boolean;
|
|
357
365
|
/**
|
|
358
366
|
* Max payload bytes for the base64-over-JSON upload path.
|
|
@@ -365,6 +373,8 @@ export interface AdminPutObjectResult {
|
|
|
365
373
|
ok: boolean;
|
|
366
374
|
bucket: string;
|
|
367
375
|
key: string;
|
|
376
|
+
access: "public" | "private";
|
|
377
|
+
url?: string;
|
|
368
378
|
size: number;
|
|
369
379
|
encrypted: boolean;
|
|
370
380
|
}
|
|
@@ -413,6 +423,105 @@ export interface AdminDeleteObjectsInput {
|
|
|
413
423
|
bucket: string;
|
|
414
424
|
keys: string[];
|
|
415
425
|
}
|
|
426
|
+
export type AdminFunctionScopeType = "collection" | "document" | "field";
|
|
427
|
+
export type AdminFunctionTargetType = "compiled_plan" | "internal" | "webhook" | "isolated_runtime";
|
|
428
|
+
export type AdminMutationOperation = "create" | "update" | "delete" | "other";
|
|
429
|
+
export type AdminFunctionExecutionStatus = "pending" | "running" | "success" | "failure" | "timeout";
|
|
430
|
+
export interface AdminFunctionScope {
|
|
431
|
+
type?: AdminFunctionScopeType;
|
|
432
|
+
collection?: string;
|
|
433
|
+
document_id?: string;
|
|
434
|
+
fields?: string[];
|
|
435
|
+
}
|
|
436
|
+
export interface AdminFunctionTarget {
|
|
437
|
+
type?: AdminFunctionTargetType;
|
|
438
|
+
source?: string;
|
|
439
|
+
handler?: string;
|
|
440
|
+
url?: string;
|
|
441
|
+
}
|
|
442
|
+
export interface AdminCloudFunction {
|
|
443
|
+
id: string;
|
|
444
|
+
appId: string;
|
|
445
|
+
name: string;
|
|
446
|
+
enabled: boolean;
|
|
447
|
+
scope: AdminFunctionScope;
|
|
448
|
+
target: AdminFunctionTarget;
|
|
449
|
+
timeoutMs?: number;
|
|
450
|
+
createdAt?: string;
|
|
451
|
+
updatedAt?: string;
|
|
452
|
+
}
|
|
453
|
+
export interface AdminCreateFunctionInput {
|
|
454
|
+
id?: string;
|
|
455
|
+
name: string;
|
|
456
|
+
enabled?: boolean;
|
|
457
|
+
scope: AdminFunctionScope;
|
|
458
|
+
target: AdminFunctionTarget;
|
|
459
|
+
timeoutMs?: number;
|
|
460
|
+
}
|
|
461
|
+
export interface AdminPatchFunctionInput {
|
|
462
|
+
name?: string;
|
|
463
|
+
enabled?: boolean;
|
|
464
|
+
scope?: AdminFunctionScope;
|
|
465
|
+
target?: AdminFunctionTarget;
|
|
466
|
+
timeoutMs?: number;
|
|
467
|
+
}
|
|
468
|
+
export interface AdminInvokeFunctionInput {
|
|
469
|
+
documentId?: string;
|
|
470
|
+
operation?: AdminMutationOperation;
|
|
471
|
+
changedFields?: string[];
|
|
472
|
+
updatedFields?: Record<string, unknown>;
|
|
473
|
+
removedFields?: string[];
|
|
474
|
+
fullDocument?: Record<string, unknown>;
|
|
475
|
+
data?: unknown;
|
|
476
|
+
auth?: unknown;
|
|
477
|
+
context?: Record<string, unknown>;
|
|
478
|
+
}
|
|
479
|
+
export interface AdminInvokeFunctionResult {
|
|
480
|
+
ok: boolean;
|
|
481
|
+
functionId: string;
|
|
482
|
+
status: AdminFunctionExecutionStatus;
|
|
483
|
+
output?: unknown;
|
|
484
|
+
error?: string;
|
|
485
|
+
durationMs?: number;
|
|
486
|
+
executionId?: string;
|
|
487
|
+
}
|
|
488
|
+
export interface AdminFunctionExecution {
|
|
489
|
+
id: string;
|
|
490
|
+
functionId: string;
|
|
491
|
+
appId: string;
|
|
492
|
+
status: AdminFunctionExecutionStatus;
|
|
493
|
+
triggeredBy?: string;
|
|
494
|
+
durationMs?: number;
|
|
495
|
+
output?: unknown;
|
|
496
|
+
error?: string;
|
|
497
|
+
createdAt?: string;
|
|
498
|
+
updatedAt?: string;
|
|
499
|
+
}
|
|
500
|
+
export interface AdminFunctionValidationResult {
|
|
501
|
+
valid: boolean;
|
|
502
|
+
diagnostics: unknown[];
|
|
503
|
+
mode?: "server" | "local_fallback" | "unavailable";
|
|
504
|
+
}
|
|
505
|
+
export interface FlareAdminFunctions {
|
|
506
|
+
list(): Promise<AdminCloudFunction[]>;
|
|
507
|
+
get(functionId: string): Promise<AdminCloudFunction | null>;
|
|
508
|
+
create(input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
509
|
+
patch(functionId: string, input: AdminPatchFunctionInput): Promise<AdminCloudFunction>;
|
|
510
|
+
upsert(functionId: string, input: AdminCreateFunctionInput): Promise<AdminCloudFunction>;
|
|
511
|
+
delete(functionId: string): Promise<{
|
|
512
|
+
ok: boolean;
|
|
513
|
+
id: string;
|
|
514
|
+
}>;
|
|
515
|
+
invoke(functionId: string, input?: AdminInvokeFunctionInput): Promise<AdminInvokeFunctionResult>;
|
|
516
|
+
executions(opts?: {
|
|
517
|
+
limit?: number;
|
|
518
|
+
cursor?: string;
|
|
519
|
+
}): Promise<{
|
|
520
|
+
list: AdminFunctionExecution[];
|
|
521
|
+
total: number;
|
|
522
|
+
}>;
|
|
523
|
+
validate(source: string, functionId?: string): Promise<AdminFunctionValidationResult>;
|
|
524
|
+
}
|
|
416
525
|
export type QueryOperator = "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "array-contains" | "array-contains-any" | "elem-match" | "like" | "not-like" | "contains" | "exists" | "not-exists";
|
|
417
526
|
export interface WhereFilter {
|
|
418
527
|
field: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zuzjs/flare-admin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Privileged server-side access for Flare. Designed for secure environments to perform administrative tasks, manage user identities at scale, and orchestrate system-wide notifications with full bypass of client-side security rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flare",
|