@lpdjs/firestore-repo-service 2.6.13 → 2.6.15

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.
Files changed (55) hide show
  1. package/dist/{create-servers-BV-E4Rp-.d.cts → create-servers-C3CIViuc.d.cts} +5 -5
  2. package/dist/{create-servers-BhUavex0.d.ts → create-servers-O2stZ-yF.d.ts} +5 -5
  3. package/dist/{firebase-auth-t1CAR-lp.d.cts → firebase-auth-DZ8lb2Ec.d.cts} +9 -0
  4. package/dist/{firebase-auth-t1CAR-lp.d.ts → firebase-auth-DZ8lb2Ec.d.ts} +9 -0
  5. package/dist/{index-CXWiqnFs.d.cts → index-D0KRndyL.d.cts} +2 -2
  6. package/dist/{index-4gzZw5m_.d.ts → index-TTSjUi4p.d.ts} +2 -2
  7. package/dist/index.cjs +54 -54
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +8 -8
  10. package/dist/index.d.ts +8 -8
  11. package/dist/index.js +54 -54
  12. package/dist/index.js.map +1 -1
  13. package/dist/{openapi-D71F-INl.d.cts → openapi-BdatGOqK.d.cts} +1 -1
  14. package/dist/{openapi-Bq6KTWCR.d.ts → openapi-uTAic4s0.d.ts} +1 -1
  15. package/dist/{queue-DP7t5Jp7.d.ts → queue-B4uwef6c.d.ts} +1 -1
  16. package/dist/{queue-Bl-S-I-7.d.cts → queue-CQyWCQBk.d.cts} +1 -1
  17. package/dist/servers/admin/index.cjs +45 -45
  18. package/dist/servers/admin/index.cjs.map +1 -1
  19. package/dist/servers/admin/index.d.cts +3 -3
  20. package/dist/servers/admin/index.d.ts +3 -3
  21. package/dist/servers/admin/index.js +45 -45
  22. package/dist/servers/admin/index.js.map +1 -1
  23. package/dist/servers/auth/index.cjs +3 -3
  24. package/dist/servers/auth/index.cjs.map +1 -1
  25. package/dist/servers/auth/index.d.cts +1 -1
  26. package/dist/servers/auth/index.d.ts +1 -1
  27. package/dist/servers/auth/index.js +3 -3
  28. package/dist/servers/auth/index.js.map +1 -1
  29. package/dist/servers/crud/index.cjs +1 -1
  30. package/dist/servers/crud/index.cjs.map +1 -1
  31. package/dist/servers/crud/index.d.cts +5 -5
  32. package/dist/servers/crud/index.d.ts +5 -5
  33. package/dist/servers/crud/index.js +1 -1
  34. package/dist/servers/crud/index.js.map +1 -1
  35. package/dist/servers/hono/index.d.cts +1 -1
  36. package/dist/servers/hono/index.d.ts +1 -1
  37. package/dist/servers/index.cjs +75 -75
  38. package/dist/servers/index.cjs.map +1 -1
  39. package/dist/servers/index.d.cts +8 -8
  40. package/dist/servers/index.d.ts +8 -8
  41. package/dist/servers/index.js +75 -75
  42. package/dist/servers/index.js.map +1 -1
  43. package/dist/sync/bigquery.d.cts +2 -2
  44. package/dist/sync/bigquery.d.ts +2 -2
  45. package/dist/sync/index.cjs +18 -18
  46. package/dist/sync/index.cjs.map +1 -1
  47. package/dist/sync/index.d.cts +5 -5
  48. package/dist/sync/index.d.ts +5 -5
  49. package/dist/sync/index.js +18 -18
  50. package/dist/sync/index.js.map +1 -1
  51. package/dist/{types-BxsdnGDM.d.cts → types-BwH1C-wi.d.cts} +1 -1
  52. package/dist/{types-CmSUreTx.d.ts → types-DT7Nypd_.d.ts} +1 -1
  53. package/dist/{types-C_alF2Xe.d.cts → types-Qd4tuEq9.d.cts} +1 -1
  54. package/dist/{types-C6I3WtJS.d.ts → types-wzqw45jH.d.ts} +1 -1
  55. package/package.json +1 -1
@@ -1,9 +1,9 @@
1
1
  import { HttpsOptions } from 'firebase-functions/v2/https';
2
- import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-C_alF2Xe.cjs';
3
- export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-C_alF2Xe.cjs';
4
- import { O as OpenAPIDocument } from '../../openapi-D71F-INl.cjs';
5
- export { g as generateOpenAPISpec } from '../../openapi-D71F-INl.cjs';
6
- import '../../firebase-auth-t1CAR-lp.cjs';
2
+ import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-Qd4tuEq9.cjs';
3
+ export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-Qd4tuEq9.cjs';
4
+ import { O as OpenAPIDocument } from '../../openapi-BdatGOqK.cjs';
5
+ export { g as generateOpenAPISpec } from '../../openapi-BdatGOqK.cjs';
6
+ import '../../firebase-auth-DZ8lb2Ec.cjs';
7
7
  import 'zod';
8
8
  import '../../read-CTWZjxyh.cjs';
9
9
  import 'firebase-admin/firestore';
@@ -1,9 +1,9 @@
1
1
  import { HttpsOptions } from 'firebase-functions/v2/https';
2
- import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-C6I3WtJS.js';
3
- export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-C6I3WtJS.js';
4
- import { O as OpenAPIDocument } from '../../openapi-Bq6KTWCR.js';
5
- export { g as generateOpenAPISpec } from '../../openapi-Bq6KTWCR.js';
6
- import '../../firebase-auth-t1CAR-lp.js';
2
+ import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-wzqw45jH.js';
3
+ export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-wzqw45jH.js';
4
+ import { O as OpenAPIDocument } from '../../openapi-uTAic4s0.js';
5
+ export { g as generateOpenAPISpec } from '../../openapi-uTAic4s0.js';
6
+ import '../../firebase-auth-DZ8lb2Ec.js';
7
7
  import 'zod';
8
8
  import '../../read-CTWZjxyh.js';
9
9
  import 'firebase-admin/firestore';
@@ -1,4 +1,4 @@
1
- import {randomBytes}from'crypto';import {z}from'zod';import {Timestamp}from'firebase-admin/firestore';function Pe(e){let t=[],r=e.replace(/[.*+?^${}()|[\]\\]/g,o=>o===":"?o:`\\${o}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(o,s)=>(t.push(s),"([^/]+)"));return {pattern:new RegExp(`^${r}$`),paramNames:t}}function ve(e){let t=e.path??e.url??"/",r=t.indexOf("?");return r===-1?t:t.slice(0,r)}var W=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(t,r)=>{r.status(404).send("Not Found");};this.errorHandler=(t,r,o)=>{console.error("[MiniRouter]",t),o.status(500).send("Internal Server Error");};}use(t){return this.middlewares.push(t),this}get(t,r){return this.addRoute("GET",t,r)}post(t,r){return this.addRoute("POST",t,r)}put(t,r){return this.addRoute("PUT",t,r)}patch(t,r){return this.addRoute("PATCH",t,r)}delete(t,r){return this.addRoute("DELETE",t,r)}onNotFound(t){return this.notFoundHandler=t,this}onError(t){return this.errorHandler=t,this}addRoute(t,r,o){let{pattern:s,paramNames:i}=Pe(r);return this.routes.push({method:t.toUpperCase(),pattern:s,paramNames:i,handler:o}),this}async handle(t,r){let o=(t.method??"GET").toUpperCase(),s=ve(t),i=null,d={};for(let g of this.routes){if(g.method!==o)continue;let k=s.match(g.pattern);if(k){i=g,d={},g.paramNames.forEach((N,C)=>{d[N]=decodeURIComponent(k[C+1]??"");});break}}let y=Object.assign(t,{params:d}),h=i?i.handler:this.notFoundHandler;try{await this.runMiddlewareChain(y,r,h);}catch(g){this.errorHandler(g,t,r);}}async runMiddlewareChain(t,r,o){let s=0,i=async()=>{if(s<this.middlewares.length){let d=this.middlewares[s++];await d(t,r,i);}else await o(t,r);};await i();}};function V(e,t){let r=t==="/"?"":t.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let i=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",d=process.env.FUNCTION_REGION??"us-central1",y=(process.env.FUNCTION_TARGET??"").replace(/\./g,"-");return `/${i}/${d}/${y}${r}`}let o=process.env.K_SERVICE,s=e?.hostname??e?.headers?.host??"";return o&&typeof s=="string"&&s.includes("cloudfunctions.net")?`/${o.toLowerCase()}${r}`:r}function J(e){return !!e&&typeof e=="object"&&e.__authExtension===true}var ue="preserve";function le(){return ue}function Te(e){return typeof e=="object"&&e!==null&&typeof e._seconds=="number"&&typeof e._nanoseconds=="number"}function pe(e){if(e==null)return null;if(e instanceof Date)return Number.isNaN(e.getTime())?null:e;if(e instanceof Timestamp)return e.toDate();if(Te(e))return new Date(e._seconds*1e3+Math.floor(e._nanoseconds/1e6));if(typeof e=="string"){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}if(typeof e=="number"){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}return null}function fe(e){return e}var Ne=new Set(["<","<=",">",">=","!="]),$e=new Set(["array-contains","array-contains-any"]);function Y(e){return e==="desc"?"DESCENDING":"ASCENDING"}function je(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function Fe(e,t,r,o,s){let i=[],d=new Set;for(let h of o)if(h.op==="=="||h.op==="in"||h.op==="not-in"){if(d.has(h.field))continue;d.add(h.field),i.push({fieldPath:h.field,order:"ASCENDING"});}for(let h of o)if($e.has(h.op)){if(d.has(h.field))continue;d.add(h.field),i.push({fieldPath:h.field,arrayConfig:"CONTAINS"});}for(let h of o)if(Ne.has(h.op)){if(d.has(h.field))continue;d.add(h.field);let g=s?.field===h.field?Y(s.dir):"ASCENDING";i.push({fieldPath:h.field,order:g});}if(s&&!d.has(s.field)&&i.push({fieldPath:s.field,order:Y(s.dir)}),i.length===1&&r)return Be(e,t,i[0]);let y=s&&i.some(h=>h.fieldPath===s.field)?Y(s.dir):"ASCENDING";return i.push({fieldPath:"__name__",order:y}),_e(e,t,r,i)}function _e(e,t,r,o,s="(default)"){let i=`projects/${e}/databases/${s}/collectionGroups/${t}/indexes/_`,d=[...ne(1,i),...Z(2,r?2:1)];for(let g of o)d.push(...ge(3,me(g)));let y=s==="(default)"?"-default-":s,h=encodeURIComponent(ye(d));return `https://console.firebase.google.com/project/${e}/firestore/databases/${y}/indexes?create_composite=${h}`}function He(e){return e.match(/https:\/\/console\.firebase\.google\.com[^\s)"]*/)?.[0]}function ee(e){let t=[],r=e>>>0;for(;r>=128;)t.push(r&127|128),r>>>=7;return t.push(r&127),t}function te(e,t){return e<<3|t}function ne(e,t){let r=Array.from(new TextEncoder().encode(t));return [te(e,2),...ee(r.length),...r]}function Z(e,t){return [te(e,0),...ee(t)]}function ge(e,t){return [te(e,2),...ee(t.length),...t]}function me(e){let t=[...ne(1,e.fieldPath)];return e.arrayConfig==="CONTAINS"?t.push(...Z(3,1)):t.push(...Z(2,e.order==="DESCENDING"?2:1)),t}function ye(e){let t=String.fromCharCode(...e),r;if(typeof Buffer<"u")r=Buffer.from(e).toString("base64");else if(typeof btoa<"u")r=btoa(t);else throw new Error("No base64 encoder available");return r.replace(/=+$/,"")}function Be(e,t,r,o="(default)"){let s=`projects/${e}/databases/${o}/collectionGroups/${t}/fields/${r.fieldPath}`,i=[...ne(1,s),...Z(2,2),...ge(3,me(r))],d=o==="(default)"?"-default-":o,y=encodeURIComponent(ye(i));return `https://console.firebase.google.com/project/${e}/firestore/databases/${d}/indexes/automatic?create_exemption=${y}`}function ze(e){let t=e,r=[t?.firestore?.projectId,t?.firestore?.app?.options?.projectId,t?.firestore?._settings?.projectId,t?.firestore?.databaseId?.projectId,t?._firestore?.projectId];for(let s of r)if(typeof s=="string"&&s.length>0)return s;return process.env.GCLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT||process.env.FIREBASE_PROJECT_ID||void 0}function Ue(e){let t=e;return t?t.code===9?true:typeof t.message=="string"?t.message.includes("requires an index"):false:false}function he(e,t){let r=e??{},o=Ue(e),s;if(o&&(s=r.message?He(r.message):void 0,!s)){let i=ze(t.ref);if(i){let d=je(t.path);s=Fe(i,d,t.isGroup,t.filters,t.sort);}}return {type:o?"index":"error",message:o?"This query requires a composite index that does not exist yet.":r.message??"Query failed",indexUrl:s}}function se(e,t,r=200){let o=fe(t);e.status(r).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(o));}function L(e,t,r,o=200){se(e,{success:true,data:t,meta:r},o);}function R(e,t,r=400){se(e,{success:false,error:t},r);}function re(e,t,r,o,s){let i=he(t,r),d=i.type==="index",y=d?424:500,g={success:false,error:d?i.message:s&&t instanceof Error?t.message:o};d&&(g.errorType="index",i.indexUrl&&(g.indexUrl=i.indexUrl)),se(e,g,y);}var oe="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function qe(){let e="";for(;e.length<20;){let t=randomBytes(20);for(let r=0;r<t.length&&e.length<20;r++){let o=t[r];o>=oe.length*4||(e+=oe.charAt(o%oe.length));}}return e}function q(e){let t=e._def??e.def;if(!t)return e;let r=t.typeName??t.type;if(r==="ZodDate"||r==="date")return z.preprocess(o=>pe(o)??o,e);if(r==="ZodObject"||r==="object"){let o=e.shape,s={};for(let[i,d]of Object.entries(o))s[i]=q(d);return z.object(s)}if(r==="ZodArray"||r==="array"){let o=t.element??t.type;if(o)return z.array(q(o))}if(r==="ZodOptional"||r==="optional"){let o=t.innerType;if(o)return q(o).optional()}if(r==="ZodNullable"||r==="nullable"){let o=t.innerType;if(o)return q(o).nullable()}if(r==="ZodDefault"||r==="default"){let o=t.innerType,s=t.defaultValue;if(o){let i=q(o);return typeof s=="function"?i.default(s()):i.default(s)}}return e}function Ge(e,t,r=[]){let o=e.shape,s={},i=t&&t.length>0?t:Object.keys(o);for(let d of i){if(r.includes(d))continue;let y=d.split(".")[0];y&&o[y]&&(s[y]=o[y]);}return z.object(s)}function be(e,t,r,o=false,s=[]){try{let i=Ge(e,r,s),d=o?i.partial():i;return {success:!0,data:(le()==="normalize"?q(d):d).parse(t)}}catch(i){return i instanceof z.ZodError?{success:false,error:`Validation failed: ${i.issues.map(y=>`${y.path.join(".")}: ${y.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function Me(e,t){let r=[],o=t?new Set(t):null,s={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[i,d]of Object.entries(e)){if(d===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(i))continue;let y=Array.isArray(d)?d[0]:d;if(y===void 0||y==="")continue;let h=i.match(/^(\w+)__(\w+)$/),g,k="==";if(h&&h[1]&&h[2]){g=h[1];let C=h[2];if(s[C])k=s[C];else continue}else if(!h)g=i;else continue;if(o&&!o.has(g))continue;let N=y;k==="in"||k==="not-in"||k==="array-contains-any"?N=y.split(",").map(C=>we(C.trim())):N=we(y),r.push({field:g,op:k,value:N});}return r}function we(e){if(e==="true")return true;if(e==="false")return false;if(e==="null")return null;let t=Number(e);return !isNaN(t)&&e!==""?t:e}function Q(e){return e?{docId:e.id}:null}async function Re(e,t){if(!t||typeof t!="object")return;let r=t.docId;if(typeof r=="string")try{let o=e.repo.ref;if(typeof o.doc!="function")return;let s=await o.doc(r).get();return s.exists?s:void 0}catch{return}}function xe(e,t,r,o=false){async function s(c,u,l,n){if(!o)return true;let f=u.rules?.[l];if(!f)return R(c,`Operation "${l}" is not allowed for this repository`,403),false;try{return await f(n)?!0:(R(c,"Forbidden",403),!1)}catch(p){let m=r&&p instanceof Error?p.message:"Forbidden";return R(c,m,403),false}}async function i(c,u,l,n){if(!o)return n;let f=c.rules?.filter;if(!f)return n;let p=[];for(let m of n)try{await f({user:u,doc:m,params:l})&&p.push(m);}catch{}return p}function d(c){return c?.user??null}function y(c,u){return !c||!e[c]?(R(u,`Repository "${c}" not found`,404),null):e[c]}function h(c,u){if(!u)return;let l=c[u];if(typeof l!="string"||!l)return;let n=l.split("/").filter(Boolean),f=[];for(let p=1;p<n.length;p+=2)f.push(n[p]);return f.length>0?f:void 0}async function g(c,u){let l=`by${c.documentKey.charAt(0).toUpperCase()}${c.documentKey.slice(1)}`,n=c.repo.get[l];if(typeof n=="function")try{let p=await n(u);if(p)return p}catch{}return (await c.repo.query.by({where:[[c.documentKey,"==",u]],limit:1}))[0]??null}async function k(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=d(c);if(!await s(u,n,"list",{user:f,query:c.query??{},params:l}))return;let p=[],m;try{let a=c.query??{},w=Math.min(Number(a.pageSize)||n.pageSize,100),S=a.cursor,O=a.direction?.toLowerCase()==="prev"?"prev":"next",b=a.orderBy,v=a.orderDir?.toLowerCase()==="desc"?"desc":"asc",T=a.select,x=T?T.split(",").map(D=>D.trim()):void 0,A;n.allowedIncludes&&a.includes&&(A=(typeof a.includes=="string"?a.includes.split(",").map(K=>K.trim()):Array.isArray(a.includes)?a.includes:[]).filter(K=>typeof K=="string"&&n.allowedIncludes.includes(K)),A?.length===0&&(A=void 0));let P=Me(a,n.filterableFields);p=P.map(D=>({field:D.field,op:D.op,value:String(D.value??"")})),b&&(m={field:b,dir:v});let F={pageSize:w,direction:O};if(S)try{let D=typeof S=="string"?JSON.parse(S):S;F.cursor=await Re(n,D);}catch{}if(b){if(n.orderableFields&&!n.orderableFields.includes(b)){R(u,`Field not orderable: ${b}`,400);return}F.orderBy=[{field:b,direction:v}];}P.length>0&&(F.where=P.map(D=>[D.field,D.op,D.value])),x&&(F.select=x),A&&(F.include=A);let U=await n.repo.query.paginate(F),Oe={items:await i(n,d(c),l,U.data),hasNextPage:U.hasNextPage,hasPrevPage:U.hasPrevPage,nextCursor:Q(U.nextCursor),prevCursor:Q(U.prevCursor)};L(u,Oe,{pageSize:w,hasMore:U.hasNextPage});}catch(a){re(u,a,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:p,sort:m},"Failed to fetch documents",r);}}async function N(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=d(c);if(!await s(u,n,"list",{user:f,query:c.body??{},params:l}))return;let p=[],m;try{let a=c.body??{},w=Math.min(a.pageSize||n.pageSize,100),S=a.direction==="prev"?"prev":"next";a.where&&(p=a.where.map(x=>({field:String(x[0]),op:x[1],value:String(x[2]??"")}))),a.orderBy&&a.orderBy[0]&&(m={field:a.orderBy[0].field,dir:a.orderBy[0].direction==="desc"?"desc":"asc"});let O={pageSize:w,direction:S};if(a.cursor)try{let x=typeof a.cursor=="string"?JSON.parse(a.cursor):a.cursor;O.cursor=await Re(n,x);}catch{}if(n.allowedIncludes&&a.includes&&a.includes.length>0){let x=a.includes.filter(A=>typeof A=="string"?n.allowedIncludes.includes(A):typeof A=="object"&&A!==null&&"relation"in A&&typeof A.relation=="string"?n.allowedIncludes.includes(A.relation):!1);x.length>0&&(O.include=x);}if(a.where&&a.where.length>0){if(n.filterableFields){let x=new Set(n.filterableFields),A=a.where.filter(P=>!x.has(P[0]));if(A.length>0){R(u,`Fields not filterable: ${A.map(P=>P[0]).join(", ")}`,400);return}}O.where=a.where;}if(a.orWhere&&a.orWhere.length>0){if(n.filterableFields){let x=new Set(n.filterableFields),A=a.orWhere.filter(P=>!x.has(P[0]));if(A.length>0){R(u,`Fields not filterable: ${A.map(P=>P[0]).join(", ")}`,400);return}}O.orWhere=a.orWhere;}if(a.orWhereGroups&&a.orWhereGroups.length>0){if(n.filterableFields){let x=new Set(n.filterableFields);for(let A of a.orWhereGroups){let P=A.filter(F=>!x.has(F[0]));if(P.length>0){R(u,`Fields not filterable: ${P.map(F=>F[0]).join(", ")}`,400);return}}}O.orWhereGroups=a.orWhereGroups;}if(a.orderBy&&a.orderBy.length>0){if(n.orderableFields){let x=new Set(n.orderableFields),A=a.orderBy.filter(P=>!x.has(P.field));if(A.length>0){R(u,`Fields not orderable: ${A.map(P=>P.field).join(", ")}`,400);return}}O.orderBy=a.orderBy;}a.select&&a.select.length>0&&(O.select=a.select);let b=await n.repo.query.paginate(O),T={items:await i(n,d(c),l,b.data),hasNextPage:b.hasNextPage,hasPrevPage:b.hasPrevPage,nextCursor:Q(b.nextCursor),prevCursor:Q(b.prevCursor)};L(u,T,{pageSize:w,hasMore:b.hasNextPage});}catch(a){re(u,a,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:p,sort:m},"Failed to query documents",r);}}async function C(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=l.id;if(!f){R(u,"Document ID required",400);return}try{let p=await g(n,f);if(!p){R(u,"Document not found",404);return}let m=d(c);if(!await s(u,n,"get",{user:m,doc:p,params:l}))return;if(o&&n.rules?.filter)try{if(!await n.rules.filter({user:m,doc:p,params:l})){R(u,"Document not found",404);return}}catch{R(u,"Document not found",404);return}L(u,p);}catch(p){re(u,p,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:[{field:n.documentKey,op:"==",value:f}]},"Failed to fetch document",r);}}async function $(c,u){let l=c.params||{},n=y(l.repoName,u);if(n)try{let f=c.body??{},p=d(c);if(!await s(u,n,"create",{user:p,body:f,params:l}))return;let m=be(n.schema,f,n.createFields,!1,n.systemKeys);if(!m.success){R(u,m.error,400);return}if(n.validate){let w=await n.validate(m.data,"create");if(w){R(u,w,400);return}}let a;if(n.isGroup&&n.parentKeys&&n.parentKeys.length>0){let w={...m.data};n.createdKey&&(w[n.createdKey]=new Date);let S=n.parentKeys.filter(v=>!w[v]);if(S.length>0){R(u,`Missing parent key(s) for subcollection create: ${S.join(", ")}`,400);return}let O=n.parentKeys.map(v=>w[v]),b=w[n.documentKey]||qe();a=await n.repo.set(...O,b,w);}else a=await n.repo.create(m.data);L(u,a,void 0,201);}catch(f){let p=r&&f instanceof Error?f.message:"Failed to create document";R(u,p,500);}}async function z(c,u,l){let n=c.params||{},f=y(n.repoName,u);if(!f)return;let p=n.id;if(!p){R(u,"Document ID required",400);return}try{let m=c.body??{},a=await g(f,p);if(!a){R(u,"Document not found",404);return}let w=d(c);if(!await s(u,f,"update",{user:w,doc:a,body:m,params:n}))return;let S=be(f.schema,m,f.mutableFields,l,f.systemKeys);if(!S.success){R(u,S.error,400);return}if(f.validate){let v=await f.validate(S.data,"update");if(v){R(u,v,400);return}}let O=h(a,f.pathKey)??[p],b=await f.repo.update(...O,S.data);L(u,b);}catch(m){let a=r&&m instanceof Error?m.message:"Failed to update document";R(u,a,500);}}async function H(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;if(!n.allowDelete){R(u,"Delete not allowed for this repository",403);return}let f=l.id;if(!f){R(u,"Document ID required",400);return}try{let p=await g(n,f);if(!p){R(u,"Document not found",404);return}let m=d(c);if(!await s(u,n,"delete",{user:m,doc:p,params:l}))return;let a=h(p,n.pathKey)??[f];await n.repo.delete(...a),L(u,{deleted:!0});}catch(p){let m=r&&p instanceof Error?p.message:"Failed to delete document";R(u,m,500);}}function I(c,u){u.status(204).set("Access-Control-Allow-Methods","GET, POST, PUT, PATCH, DELETE, OPTIONS").set("Access-Control-Allow-Headers","Content-Type, Authorization").set("Access-Control-Max-Age","86400").send("");}return {handleList:k,handleQuery:N,handleGet:C,handleCreate:$,handleUpdate:z,handleDelete:H,handleOptions:I}}function ie(e){try{return z.toJSONSchema(e,{target:"openapi-3.1",unrepresentable:"any",override:t=>{let r=t.zodSchema?._zod?.def;r&&(r.type==="date"?(t.jsonSchema.type="string",t.jsonSchema.format="date-time"):r.type==="bigint"&&(t.jsonSchema.type="string",t.jsonSchema.format="int64"));}})}catch(t){return typeof console<"u"&&console.warn&&console.warn("[generateOpenAPISpec] Failed to convert Zod schema to JSON Schema; falling back to {type:object}.",t),{type:"object"}}}function j(e){return {$ref:`#/components/schemas/${e}`}}function E(e){return {description:e,content:{"application/json":{schema:j("ErrorResponse")}}}}function M(e,t){return {description:e,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:t},required:["success","data"]}}}}}function Ae(e){return {description:"Paginated list of documents",content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:{type:"object",properties:{items:{type:"array",items:e},nextCursor:{oneOf:[{type:"object"},{type:"null"}]},prevCursor:{oneOf:[{type:"object"},{type:"null"}]},hasNextPage:{type:"boolean"},hasPrevPage:{type:"boolean"}},required:["items","hasNextPage","hasPrevPage"]},meta:{type:"object",properties:{pageSize:{type:"integer"},hasMore:{type:"boolean"},cursor:{oneOf:[{type:"string"},{type:"null"}]}}}},required:["success","data"]}}}}}function Ke(e){return [{name:"pageSize",in:"query",schema:{type:"integer",default:e.pageSize,maximum:100},description:"Number of items per page"},{name:"cursor",in:"query",schema:{type:"string"},description:"Base64 pagination cursor"},{name:"orderBy",in:"query",schema:{type:"string"},description:"Field name to order by"},{name:"orderDir",in:"query",schema:{type:"string",enum:["asc","desc"]},description:"Order direction"},{name:"select",in:"query",schema:{type:"string"},description:"Comma-separated list of fields to return"}]}function We(e){let t=e.filterableFields??Object.keys(e.schema.shape),r=["eq","ne","lt","lte","gt","gte","in","nin","contains"],o=[];for(let s of t){o.push({name:s,in:"query",schema:{type:"string"},description:`Filter by ${s} (equality)`});for(let i of r)o.push({name:`${s}__${i}`,in:"query",schema:{type:"string"},description:`Filter ${s} with operator ${i}`});}return o}function Je(){return {type:"object",properties:{where:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3},description:"AND conditions: [field, operator, value][]"},orWhere:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3},description:"Simple OR conditions (each independently OR'd)"},orWhereGroups:{type:"array",items:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3}},description:"Advanced OR groups (AND within, OR across groups)"},orderBy:{type:"array",items:{type:"object",properties:{field:{type:"string"},direction:{type:"string",enum:["asc","desc"]}},required:["field"]}},select:{type:"array",items:{type:"string"},description:"Fields to select (projection)"},pageSize:{type:"integer",maximum:100,description:"Number of items per page"},cursor:{oneOf:[{type:"string"},{type:"object"}],description:"Pagination cursor"},direction:{type:"string",enum:["next","prev"],description:"Pagination direction"},includes:{type:"array",items:{oneOf:[{type:"string"},{type:"object",properties:{relation:{type:"string"},select:{type:"array",items:{type:"string"}}},required:["relation"]}]},description:"Relations to include (populate)"}}}}function Ze(e,t,r,o,s){let i={},d=e.name,y=`${t}/${e.name}`,h=`${y}/{${e.documentKey}}`,g={name:e.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};i[y]={get:{operationId:`list${B(e.name)}`,summary:`List ${e.name} (paginated)`,tags:[d],parameters:[...Ke(e),...We(e)],responses:{200:Ae(j(r)),500:E("Internal server error")}},post:{operationId:`create${B(e.name)}`,summary:`Create a ${_(e.name)}`,tags:[d],requestBody:{required:true,content:{"application/json":{schema:j(o??r)}}},responses:{201:M("Document created",j(r)),400:E("Validation error"),500:E("Internal server error")}}},i[`${y}/query`]={post:{operationId:`query${B(e.name)}`,summary:`Query ${e.name} with advanced filters`,tags:[d],requestBody:{required:true,content:{"application/json":{schema:j("QueryRequestBody")}}},responses:{200:Ae(j(r)),400:E("Invalid query"),500:E("Internal server error")}}};let k={};return k.get={operationId:`get${B(_(e.name))}`,summary:`Get a single ${_(e.name)}`,tags:[d],parameters:[g],responses:{200:M("Document found",j(r)),404:E("Document not found"),500:E("Internal server error")}},k.put={operationId:`update${B(_(e.name))}`,summary:`Update a ${_(e.name)} (full replace)`,tags:[d],parameters:[g],requestBody:{required:true,content:{"application/json":{schema:j(s??r)}}},responses:{200:M("Document updated",j(r)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},k.patch={operationId:`patch${B(_(e.name))}`,summary:`Partially update a ${_(e.name)}`,tags:[d],parameters:[g],requestBody:{required:true,content:{"application/json":{schema:{allOf:[j(s??r)],description:"All fields are optional for partial updates"}}}},responses:{200:M("Document patched",j(r)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},e.allowDelete&&(k.delete={operationId:`delete${B(_(e.name))}`,summary:`Delete a ${_(e.name)}`,tags:[d],parameters:[g],responses:{200:M("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:E("Document not found"),500:E("Internal server error")}}),i[h]=k,i}function ce(e,t,r={}){let{title:o="CRUD API",version:s="1.0.0",description:i,servers:d,auth:y=false}=r,h=t==="/"?"":t.replace(/\/$/,""),g={},k={},N=[];g.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},g.QueryRequestBody=Je();for(let[H,I]of Object.entries(e)){let c=B(_(H)),u=`${c}Create`,l=`${c}Update`;g[c]=ie(I.schema);let n=S=>{let O=S&&S.length>0?S:Object.keys(I.schema.shape),b={};for(let v of O){let T=v.split(".")[0];T&&I.schema.shape[T]&&!I.systemKeys.includes(T)&&(b[T]=I.schema.shape[T]);}return b},f=null,p=n(I.createFields);Object.keys(p).length>0&&(g[u]=ie(z.object(p)),f=u);let m=null,a=n(I.mutableFields);Object.keys(a).length>0&&(g[l]=ie(z.object(a)),m=l);let w=Ze(I,h,c,f,m);Object.assign(k,w),N.push({name:H,description:`Operations on ${H} (collection: ${I.path})`});}let C={},$;return y==="basic"?(C.basicAuth={type:"http",scheme:"basic"},$=[{basicAuth:[]}]):y==="bearer"&&(C.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},$=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:o,version:s,...i?{description:i}:{}},...d&&d.length>0?{servers:d}:{},paths:k,components:{schemas:g,...Object.keys(C).length>0?{securitySchemes:C}:{}},...$?{security:$}:{},tags:N}}function B(e){return e.charAt(0).toUpperCase()+e.slice(1)}function _(e){return e.endsWith("ies")?e.slice(0,-3)+"y":e.endsWith("ses")||e.endsWith("xes")||e.endsWith("zes")?e.slice(0,-2):e.endsWith("s")&&!e.endsWith("ss")?e.slice(0,-1):e}var ke="https://cdn.jsdelivr.net",Ce="https://www.gstatic.com",Qe=["default-src 'self'",`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${ke} ${Ce}`,`style-src 'self' 'unsafe-inline' ${ke}`,`connect-src 'self' ${Ce} https://*.googleapis.com https://*.firebaseio.com https://identitytoolkit.googleapis.com`,"img-src 'self' data:","font-src 'self' data:","frame-ancestors 'none'","base-uri 'self'","form-action 'self'"].join("; ");function Se(e={}){let t=e.csp===void 0?Qe:e.csp,r=e.frameOptions===void 0?"DENY":e.frameOptions,o=e.referrerPolicy===void 0?"no-referrer":e.referrerPolicy,s=e.cacheControl===void 0?"private, no-store":e.cacheControl;return async(i,d,y)=>{typeof d?.setHeader=="function"&&(d.setHeader("X-Content-Type-Options","nosniff"),r&&d.setHeader("X-Frame-Options",r),o&&d.setHeader("Referrer-Policy",o),s&&d.setHeader("Cache-Control",s),t&&d.setHeader("Content-Security-Policy",t)),await y();}}function Ve(e,t){return `<!DOCTYPE html>
1
+ import {randomBytes}from'crypto';import {z}from'zod';import {Timestamp}from'firebase-admin/firestore';function Pe(e){let t=[],r=e.replace(/[.*+?^${}()|[\]\\]/g,o=>o===":"?o:`\\${o}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(o,s)=>(t.push(s),"([^/]+)"));return {pattern:new RegExp(`^${r}$`),paramNames:t}}function ve(e){let t=e.path??e.url??"/",r=t.indexOf("?");return r===-1?t:t.slice(0,r)}var W=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(t,r)=>{r.status(404).send("Not Found");};this.errorHandler=(t,r,o)=>{console.error("[MiniRouter]",t),o.status(500).send("Internal Server Error");};}use(t){return this.middlewares.push(t),this}get(t,r){return this.addRoute("GET",t,r)}post(t,r){return this.addRoute("POST",t,r)}put(t,r){return this.addRoute("PUT",t,r)}patch(t,r){return this.addRoute("PATCH",t,r)}delete(t,r){return this.addRoute("DELETE",t,r)}onNotFound(t){return this.notFoundHandler=t,this}onError(t){return this.errorHandler=t,this}addRoute(t,r,o){let{pattern:s,paramNames:i}=Pe(r);return this.routes.push({method:t.toUpperCase(),pattern:s,paramNames:i,handler:o}),this}async handle(t,r){let o=(t.method??"GET").toUpperCase(),s=ve(t),i=null,d={};for(let g of this.routes){if(g.method!==o)continue;let k=s.match(g.pattern);if(k){i=g,d={},g.paramNames.forEach((N,C)=>{d[N]=decodeURIComponent(k[C+1]??"");});break}}let y=Object.assign(t,{params:d}),h=i?i.handler:this.notFoundHandler;try{await this.runMiddlewareChain(y,r,h);}catch(g){this.errorHandler(g,t,r);}}async runMiddlewareChain(t,r,o){let s=0,i=async()=>{if(s<this.middlewares.length){let d=this.middlewares[s++];await d(t,r,i);}else await o(t,r);};await i();}};function V(e,t,r){let o=t==="/"?"":t.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let d=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",y=process.env.FUNCTION_REGION??"us-central1",h=(process.env.FUNCTION_TARGET??"").replace(/\./g,"-");return `/${d}/${y}/${h}${o}`}let s=process.env.K_SERVICE,i=e?.hostname??e?.headers?.host??"";return s&&typeof i=="string"&&i.includes("cloudfunctions.net")?`/${s.toLowerCase()}${o}`:o}function J(e){return !!e&&typeof e=="object"&&e.__authExtension===true}var ue="preserve";function le(){return ue}function Te(e){return typeof e=="object"&&e!==null&&typeof e._seconds=="number"&&typeof e._nanoseconds=="number"}function pe(e){if(e==null)return null;if(e instanceof Date)return Number.isNaN(e.getTime())?null:e;if(e instanceof Timestamp)return e.toDate();if(Te(e))return new Date(e._seconds*1e3+Math.floor(e._nanoseconds/1e6));if(typeof e=="string"){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}if(typeof e=="number"){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}return null}function fe(e){return e}var Ne=new Set(["<","<=",">",">=","!="]),$e=new Set(["array-contains","array-contains-any"]);function Y(e){return e==="desc"?"DESCENDING":"ASCENDING"}function je(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function Fe(e,t,r,o,s){let i=[],d=new Set;for(let h of o)if(h.op==="=="||h.op==="in"||h.op==="not-in"){if(d.has(h.field))continue;d.add(h.field),i.push({fieldPath:h.field,order:"ASCENDING"});}for(let h of o)if($e.has(h.op)){if(d.has(h.field))continue;d.add(h.field),i.push({fieldPath:h.field,arrayConfig:"CONTAINS"});}for(let h of o)if(Ne.has(h.op)){if(d.has(h.field))continue;d.add(h.field);let g=s?.field===h.field?Y(s.dir):"ASCENDING";i.push({fieldPath:h.field,order:g});}if(s&&!d.has(s.field)&&i.push({fieldPath:s.field,order:Y(s.dir)}),i.length===1&&r)return Be(e,t,i[0]);let y=s&&i.some(h=>h.fieldPath===s.field)?Y(s.dir):"ASCENDING";return i.push({fieldPath:"__name__",order:y}),_e(e,t,r,i)}function _e(e,t,r,o,s="(default)"){let i=`projects/${e}/databases/${s}/collectionGroups/${t}/indexes/_`,d=[...ne(1,i),...Z(2,r?2:1)];for(let g of o)d.push(...ge(3,me(g)));let y=s==="(default)"?"-default-":s,h=encodeURIComponent(ye(d));return `https://console.firebase.google.com/project/${e}/firestore/databases/${y}/indexes?create_composite=${h}`}function He(e){return e.match(/https:\/\/console\.firebase\.google\.com[^\s)"]*/)?.[0]}function ee(e){let t=[],r=e>>>0;for(;r>=128;)t.push(r&127|128),r>>>=7;return t.push(r&127),t}function te(e,t){return e<<3|t}function ne(e,t){let r=Array.from(new TextEncoder().encode(t));return [te(e,2),...ee(r.length),...r]}function Z(e,t){return [te(e,0),...ee(t)]}function ge(e,t){return [te(e,2),...ee(t.length),...t]}function me(e){let t=[...ne(1,e.fieldPath)];return e.arrayConfig==="CONTAINS"?t.push(...Z(3,1)):t.push(...Z(2,e.order==="DESCENDING"?2:1)),t}function ye(e){let t=String.fromCharCode(...e),r;if(typeof Buffer<"u")r=Buffer.from(e).toString("base64");else if(typeof btoa<"u")r=btoa(t);else throw new Error("No base64 encoder available");return r.replace(/=+$/,"")}function Be(e,t,r,o="(default)"){let s=`projects/${e}/databases/${o}/collectionGroups/${t}/fields/${r.fieldPath}`,i=[...ne(1,s),...Z(2,2),...ge(3,me(r))],d=o==="(default)"?"-default-":o,y=encodeURIComponent(ye(i));return `https://console.firebase.google.com/project/${e}/firestore/databases/${d}/indexes/automatic?create_exemption=${y}`}function ze(e){let t=e,r=[t?.firestore?.projectId,t?.firestore?.app?.options?.projectId,t?.firestore?._settings?.projectId,t?.firestore?.databaseId?.projectId,t?._firestore?.projectId];for(let s of r)if(typeof s=="string"&&s.length>0)return s;return process.env.GCLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT||process.env.FIREBASE_PROJECT_ID||void 0}function Ue(e){let t=e;return t?t.code===9?true:typeof t.message=="string"?t.message.includes("requires an index"):false:false}function he(e,t){let r=e??{},o=Ue(e),s;if(o&&(s=r.message?He(r.message):void 0,!s)){let i=ze(t.ref);if(i){let d=je(t.path);s=Fe(i,d,t.isGroup,t.filters,t.sort);}}return {type:o?"index":"error",message:o?"This query requires a composite index that does not exist yet.":r.message??"Query failed",indexUrl:s}}function se(e,t,r=200){let o=fe(t);e.status(r).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(o));}function L(e,t,r,o=200){se(e,{success:true,data:t,meta:r},o);}function R(e,t,r=400){se(e,{success:false,error:t},r);}function re(e,t,r,o,s){let i=he(t,r),d=i.type==="index",y=d?424:500,g={success:false,error:d?i.message:s&&t instanceof Error?t.message:o};d&&(g.errorType="index",i.indexUrl&&(g.indexUrl=i.indexUrl)),se(e,g,y);}var oe="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function qe(){let e="";for(;e.length<20;){let t=randomBytes(20);for(let r=0;r<t.length&&e.length<20;r++){let o=t[r];o>=oe.length*4||(e+=oe.charAt(o%oe.length));}}return e}function q(e){let t=e._def??e.def;if(!t)return e;let r=t.typeName??t.type;if(r==="ZodDate"||r==="date")return z.preprocess(o=>pe(o)??o,e);if(r==="ZodObject"||r==="object"){let o=e.shape,s={};for(let[i,d]of Object.entries(o))s[i]=q(d);return z.object(s)}if(r==="ZodArray"||r==="array"){let o=t.element??t.type;if(o)return z.array(q(o))}if(r==="ZodOptional"||r==="optional"){let o=t.innerType;if(o)return q(o).optional()}if(r==="ZodNullable"||r==="nullable"){let o=t.innerType;if(o)return q(o).nullable()}if(r==="ZodDefault"||r==="default"){let o=t.innerType,s=t.defaultValue;if(o){let i=q(o);return typeof s=="function"?i.default(s()):i.default(s)}}return e}function Ge(e,t,r=[]){let o=e.shape,s={},i=t&&t.length>0?t:Object.keys(o);for(let d of i){if(r.includes(d))continue;let y=d.split(".")[0];y&&o[y]&&(s[y]=o[y]);}return z.object(s)}function be(e,t,r,o=false,s=[]){try{let i=Ge(e,r,s),d=o?i.partial():i;return {success:!0,data:(le()==="normalize"?q(d):d).parse(t)}}catch(i){return i instanceof z.ZodError?{success:false,error:`Validation failed: ${i.issues.map(y=>`${y.path.join(".")}: ${y.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function Me(e,t){let r=[],o=t?new Set(t):null,s={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[i,d]of Object.entries(e)){if(d===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(i))continue;let y=Array.isArray(d)?d[0]:d;if(y===void 0||y==="")continue;let h=i.match(/^(\w+)__(\w+)$/),g,k="==";if(h&&h[1]&&h[2]){g=h[1];let C=h[2];if(s[C])k=s[C];else continue}else if(!h)g=i;else continue;if(o&&!o.has(g))continue;let N=y;k==="in"||k==="not-in"||k==="array-contains-any"?N=y.split(",").map(C=>we(C.trim())):N=we(y),r.push({field:g,op:k,value:N});}return r}function we(e){if(e==="true")return true;if(e==="false")return false;if(e==="null")return null;let t=Number(e);return !isNaN(t)&&e!==""?t:e}function Q(e){return e?{docId:e.id}:null}async function Re(e,t){if(!t||typeof t!="object")return;let r=t.docId;if(typeof r=="string")try{let o=e.repo.ref;if(typeof o.doc!="function")return;let s=await o.doc(r).get();return s.exists?s:void 0}catch{return}}function xe(e,t,r,o=false){async function s(c,u,l,n){if(!o)return true;let f=u.rules?.[l];if(!f)return R(c,`Operation "${l}" is not allowed for this repository`,403),false;try{return await f(n)?!0:(R(c,"Forbidden",403),!1)}catch(p){let m=r&&p instanceof Error?p.message:"Forbidden";return R(c,m,403),false}}async function i(c,u,l,n){if(!o)return n;let f=c.rules?.filter;if(!f)return n;let p=[];for(let m of n)try{await f({user:u,doc:m,params:l})&&p.push(m);}catch{}return p}function d(c){return c?.user??null}function y(c,u){return !c||!e[c]?(R(u,`Repository "${c}" not found`,404),null):e[c]}function h(c,u){if(!u)return;let l=c[u];if(typeof l!="string"||!l)return;let n=l.split("/").filter(Boolean),f=[];for(let p=1;p<n.length;p+=2)f.push(n[p]);return f.length>0?f:void 0}async function g(c,u){let l=`by${c.documentKey.charAt(0).toUpperCase()}${c.documentKey.slice(1)}`,n=c.repo.get[l];if(typeof n=="function")try{let p=await n(u);if(p)return p}catch{}return (await c.repo.query.by({where:[[c.documentKey,"==",u]],limit:1}))[0]??null}async function k(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=d(c);if(!await s(u,n,"list",{user:f,query:c.query??{},params:l}))return;let p=[],m;try{let a=c.query??{},w=Math.min(Number(a.pageSize)||n.pageSize,100),S=a.cursor,O=a.direction?.toLowerCase()==="prev"?"prev":"next",b=a.orderBy,v=a.orderDir?.toLowerCase()==="desc"?"desc":"asc",T=a.select,x=T?T.split(",").map(D=>D.trim()):void 0,A;n.allowedIncludes&&a.includes&&(A=(typeof a.includes=="string"?a.includes.split(",").map(K=>K.trim()):Array.isArray(a.includes)?a.includes:[]).filter(K=>typeof K=="string"&&n.allowedIncludes.includes(K)),A?.length===0&&(A=void 0));let P=Me(a,n.filterableFields);p=P.map(D=>({field:D.field,op:D.op,value:String(D.value??"")})),b&&(m={field:b,dir:v});let F={pageSize:w,direction:O};if(S)try{let D=typeof S=="string"?JSON.parse(S):S;F.cursor=await Re(n,D);}catch{}if(b){if(n.orderableFields&&!n.orderableFields.includes(b)){R(u,`Field not orderable: ${b}`,400);return}F.orderBy=[{field:b,direction:v}];}P.length>0&&(F.where=P.map(D=>[D.field,D.op,D.value])),x&&(F.select=x),A&&(F.include=A);let U=await n.repo.query.paginate(F),Oe={items:await i(n,d(c),l,U.data),hasNextPage:U.hasNextPage,hasPrevPage:U.hasPrevPage,nextCursor:Q(U.nextCursor),prevCursor:Q(U.prevCursor)};L(u,Oe,{pageSize:w,hasMore:U.hasNextPage});}catch(a){re(u,a,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:p,sort:m},"Failed to fetch documents",r);}}async function N(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=d(c);if(!await s(u,n,"list",{user:f,query:c.body??{},params:l}))return;let p=[],m;try{let a=c.body??{},w=Math.min(a.pageSize||n.pageSize,100),S=a.direction==="prev"?"prev":"next";a.where&&(p=a.where.map(x=>({field:String(x[0]),op:x[1],value:String(x[2]??"")}))),a.orderBy&&a.orderBy[0]&&(m={field:a.orderBy[0].field,dir:a.orderBy[0].direction==="desc"?"desc":"asc"});let O={pageSize:w,direction:S};if(a.cursor)try{let x=typeof a.cursor=="string"?JSON.parse(a.cursor):a.cursor;O.cursor=await Re(n,x);}catch{}if(n.allowedIncludes&&a.includes&&a.includes.length>0){let x=a.includes.filter(A=>typeof A=="string"?n.allowedIncludes.includes(A):typeof A=="object"&&A!==null&&"relation"in A&&typeof A.relation=="string"?n.allowedIncludes.includes(A.relation):!1);x.length>0&&(O.include=x);}if(a.where&&a.where.length>0){if(n.filterableFields){let x=new Set(n.filterableFields),A=a.where.filter(P=>!x.has(P[0]));if(A.length>0){R(u,`Fields not filterable: ${A.map(P=>P[0]).join(", ")}`,400);return}}O.where=a.where;}if(a.orWhere&&a.orWhere.length>0){if(n.filterableFields){let x=new Set(n.filterableFields),A=a.orWhere.filter(P=>!x.has(P[0]));if(A.length>0){R(u,`Fields not filterable: ${A.map(P=>P[0]).join(", ")}`,400);return}}O.orWhere=a.orWhere;}if(a.orWhereGroups&&a.orWhereGroups.length>0){if(n.filterableFields){let x=new Set(n.filterableFields);for(let A of a.orWhereGroups){let P=A.filter(F=>!x.has(F[0]));if(P.length>0){R(u,`Fields not filterable: ${P.map(F=>F[0]).join(", ")}`,400);return}}}O.orWhereGroups=a.orWhereGroups;}if(a.orderBy&&a.orderBy.length>0){if(n.orderableFields){let x=new Set(n.orderableFields),A=a.orderBy.filter(P=>!x.has(P.field));if(A.length>0){R(u,`Fields not orderable: ${A.map(P=>P.field).join(", ")}`,400);return}}O.orderBy=a.orderBy;}a.select&&a.select.length>0&&(O.select=a.select);let b=await n.repo.query.paginate(O),T={items:await i(n,d(c),l,b.data),hasNextPage:b.hasNextPage,hasPrevPage:b.hasPrevPage,nextCursor:Q(b.nextCursor),prevCursor:Q(b.prevCursor)};L(u,T,{pageSize:w,hasMore:b.hasNextPage});}catch(a){re(u,a,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:p,sort:m},"Failed to query documents",r);}}async function C(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;let f=l.id;if(!f){R(u,"Document ID required",400);return}try{let p=await g(n,f);if(!p){R(u,"Document not found",404);return}let m=d(c);if(!await s(u,n,"get",{user:m,doc:p,params:l}))return;if(o&&n.rules?.filter)try{if(!await n.rules.filter({user:m,doc:p,params:l})){R(u,"Document not found",404);return}}catch{R(u,"Document not found",404);return}L(u,p);}catch(p){re(u,p,{ref:n.repo.ref,path:n.path,isGroup:!!n.isGroup,filters:[{field:n.documentKey,op:"==",value:f}]},"Failed to fetch document",r);}}async function $(c,u){let l=c.params||{},n=y(l.repoName,u);if(n)try{let f=c.body??{},p=d(c);if(!await s(u,n,"create",{user:p,body:f,params:l}))return;let m=be(n.schema,f,n.createFields,!1,n.systemKeys);if(!m.success){R(u,m.error,400);return}if(n.validate){let w=await n.validate(m.data,"create");if(w){R(u,w,400);return}}let a;if(n.isGroup&&n.parentKeys&&n.parentKeys.length>0){let w={...m.data};n.createdKey&&(w[n.createdKey]=new Date);let S=n.parentKeys.filter(v=>!w[v]);if(S.length>0){R(u,`Missing parent key(s) for subcollection create: ${S.join(", ")}`,400);return}let O=n.parentKeys.map(v=>w[v]),b=w[n.documentKey]||qe();a=await n.repo.set(...O,b,w);}else a=await n.repo.create(m.data);L(u,a,void 0,201);}catch(f){let p=r&&f instanceof Error?f.message:"Failed to create document";R(u,p,500);}}async function z(c,u,l){let n=c.params||{},f=y(n.repoName,u);if(!f)return;let p=n.id;if(!p){R(u,"Document ID required",400);return}try{let m=c.body??{},a=await g(f,p);if(!a){R(u,"Document not found",404);return}let w=d(c);if(!await s(u,f,"update",{user:w,doc:a,body:m,params:n}))return;let S=be(f.schema,m,f.mutableFields,l,f.systemKeys);if(!S.success){R(u,S.error,400);return}if(f.validate){let v=await f.validate(S.data,"update");if(v){R(u,v,400);return}}let O=h(a,f.pathKey)??[p],b=await f.repo.update(...O,S.data);L(u,b);}catch(m){let a=r&&m instanceof Error?m.message:"Failed to update document";R(u,a,500);}}async function H(c,u){let l=c.params||{},n=y(l.repoName,u);if(!n)return;if(!n.allowDelete){R(u,"Delete not allowed for this repository",403);return}let f=l.id;if(!f){R(u,"Document ID required",400);return}try{let p=await g(n,f);if(!p){R(u,"Document not found",404);return}let m=d(c);if(!await s(u,n,"delete",{user:m,doc:p,params:l}))return;let a=h(p,n.pathKey)??[f];await n.repo.delete(...a),L(u,{deleted:!0});}catch(p){let m=r&&p instanceof Error?p.message:"Failed to delete document";R(u,m,500);}}function I(c,u){u.status(204).set("Access-Control-Allow-Methods","GET, POST, PUT, PATCH, DELETE, OPTIONS").set("Access-Control-Allow-Headers","Content-Type, Authorization").set("Access-Control-Max-Age","86400").send("");}return {handleList:k,handleQuery:N,handleGet:C,handleCreate:$,handleUpdate:z,handleDelete:H,handleOptions:I}}function ie(e){try{return z.toJSONSchema(e,{target:"openapi-3.1",unrepresentable:"any",override:t=>{let r=t.zodSchema?._zod?.def;r&&(r.type==="date"?(t.jsonSchema.type="string",t.jsonSchema.format="date-time"):r.type==="bigint"&&(t.jsonSchema.type="string",t.jsonSchema.format="int64"));}})}catch(t){return typeof console<"u"&&console.warn&&console.warn("[generateOpenAPISpec] Failed to convert Zod schema to JSON Schema; falling back to {type:object}.",t),{type:"object"}}}function j(e){return {$ref:`#/components/schemas/${e}`}}function E(e){return {description:e,content:{"application/json":{schema:j("ErrorResponse")}}}}function M(e,t){return {description:e,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:t},required:["success","data"]}}}}}function Ae(e){return {description:"Paginated list of documents",content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:{type:"object",properties:{items:{type:"array",items:e},nextCursor:{oneOf:[{type:"object"},{type:"null"}]},prevCursor:{oneOf:[{type:"object"},{type:"null"}]},hasNextPage:{type:"boolean"},hasPrevPage:{type:"boolean"}},required:["items","hasNextPage","hasPrevPage"]},meta:{type:"object",properties:{pageSize:{type:"integer"},hasMore:{type:"boolean"},cursor:{oneOf:[{type:"string"},{type:"null"}]}}}},required:["success","data"]}}}}}function Ke(e){return [{name:"pageSize",in:"query",schema:{type:"integer",default:e.pageSize,maximum:100},description:"Number of items per page"},{name:"cursor",in:"query",schema:{type:"string"},description:"Base64 pagination cursor"},{name:"orderBy",in:"query",schema:{type:"string"},description:"Field name to order by"},{name:"orderDir",in:"query",schema:{type:"string",enum:["asc","desc"]},description:"Order direction"},{name:"select",in:"query",schema:{type:"string"},description:"Comma-separated list of fields to return"}]}function We(e){let t=e.filterableFields??Object.keys(e.schema.shape),r=["eq","ne","lt","lte","gt","gte","in","nin","contains"],o=[];for(let s of t){o.push({name:s,in:"query",schema:{type:"string"},description:`Filter by ${s} (equality)`});for(let i of r)o.push({name:`${s}__${i}`,in:"query",schema:{type:"string"},description:`Filter ${s} with operator ${i}`});}return o}function Je(){return {type:"object",properties:{where:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3},description:"AND conditions: [field, operator, value][]"},orWhere:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3},description:"Simple OR conditions (each independently OR'd)"},orWhereGroups:{type:"array",items:{type:"array",items:{type:"array",items:{},minItems:3,maxItems:3}},description:"Advanced OR groups (AND within, OR across groups)"},orderBy:{type:"array",items:{type:"object",properties:{field:{type:"string"},direction:{type:"string",enum:["asc","desc"]}},required:["field"]}},select:{type:"array",items:{type:"string"},description:"Fields to select (projection)"},pageSize:{type:"integer",maximum:100,description:"Number of items per page"},cursor:{oneOf:[{type:"string"},{type:"object"}],description:"Pagination cursor"},direction:{type:"string",enum:["next","prev"],description:"Pagination direction"},includes:{type:"array",items:{oneOf:[{type:"string"},{type:"object",properties:{relation:{type:"string"},select:{type:"array",items:{type:"string"}}},required:["relation"]}]},description:"Relations to include (populate)"}}}}function Ze(e,t,r,o,s){let i={},d=e.name,y=`${t}/${e.name}`,h=`${y}/{${e.documentKey}}`,g={name:e.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};i[y]={get:{operationId:`list${B(e.name)}`,summary:`List ${e.name} (paginated)`,tags:[d],parameters:[...Ke(e),...We(e)],responses:{200:Ae(j(r)),500:E("Internal server error")}},post:{operationId:`create${B(e.name)}`,summary:`Create a ${_(e.name)}`,tags:[d],requestBody:{required:true,content:{"application/json":{schema:j(o??r)}}},responses:{201:M("Document created",j(r)),400:E("Validation error"),500:E("Internal server error")}}},i[`${y}/query`]={post:{operationId:`query${B(e.name)}`,summary:`Query ${e.name} with advanced filters`,tags:[d],requestBody:{required:true,content:{"application/json":{schema:j("QueryRequestBody")}}},responses:{200:Ae(j(r)),400:E("Invalid query"),500:E("Internal server error")}}};let k={};return k.get={operationId:`get${B(_(e.name))}`,summary:`Get a single ${_(e.name)}`,tags:[d],parameters:[g],responses:{200:M("Document found",j(r)),404:E("Document not found"),500:E("Internal server error")}},k.put={operationId:`update${B(_(e.name))}`,summary:`Update a ${_(e.name)} (full replace)`,tags:[d],parameters:[g],requestBody:{required:true,content:{"application/json":{schema:j(s??r)}}},responses:{200:M("Document updated",j(r)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},k.patch={operationId:`patch${B(_(e.name))}`,summary:`Partially update a ${_(e.name)}`,tags:[d],parameters:[g],requestBody:{required:true,content:{"application/json":{schema:{allOf:[j(s??r)],description:"All fields are optional for partial updates"}}}},responses:{200:M("Document patched",j(r)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},e.allowDelete&&(k.delete={operationId:`delete${B(_(e.name))}`,summary:`Delete a ${_(e.name)}`,tags:[d],parameters:[g],responses:{200:M("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:E("Document not found"),500:E("Internal server error")}}),i[h]=k,i}function ce(e,t,r={}){let{title:o="CRUD API",version:s="1.0.0",description:i,servers:d,auth:y=false}=r,h=t==="/"?"":t.replace(/\/$/,""),g={},k={},N=[];g.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},g.QueryRequestBody=Je();for(let[H,I]of Object.entries(e)){let c=B(_(H)),u=`${c}Create`,l=`${c}Update`;g[c]=ie(I.schema);let n=S=>{let O=S&&S.length>0?S:Object.keys(I.schema.shape),b={};for(let v of O){let T=v.split(".")[0];T&&I.schema.shape[T]&&!I.systemKeys.includes(T)&&(b[T]=I.schema.shape[T]);}return b},f=null,p=n(I.createFields);Object.keys(p).length>0&&(g[u]=ie(z.object(p)),f=u);let m=null,a=n(I.mutableFields);Object.keys(a).length>0&&(g[l]=ie(z.object(a)),m=l);let w=Ze(I,h,c,f,m);Object.assign(k,w),N.push({name:H,description:`Operations on ${H} (collection: ${I.path})`});}let C={},$;return y==="basic"?(C.basicAuth={type:"http",scheme:"basic"},$=[{basicAuth:[]}]):y==="bearer"&&(C.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},$=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:o,version:s,...i?{description:i}:{}},...d&&d.length>0?{servers:d}:{},paths:k,components:{schemas:g,...Object.keys(C).length>0?{securitySchemes:C}:{}},...$?{security:$}:{},tags:N}}function B(e){return e.charAt(0).toUpperCase()+e.slice(1)}function _(e){return e.endsWith("ies")?e.slice(0,-3)+"y":e.endsWith("ses")||e.endsWith("xes")||e.endsWith("zes")?e.slice(0,-2):e.endsWith("s")&&!e.endsWith("ss")?e.slice(0,-1):e}var ke="https://cdn.jsdelivr.net",Ce="https://www.gstatic.com",Qe=["default-src 'self'",`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${ke} ${Ce}`,`style-src 'self' 'unsafe-inline' ${ke}`,`connect-src 'self' ${Ce} https://*.googleapis.com https://*.firebaseio.com https://identitytoolkit.googleapis.com`,"img-src 'self' data:","font-src 'self' data:","frame-ancestors 'none'","base-uri 'self'","form-action 'self'"].join("; ");function Se(e={}){let t=e.csp===void 0?Qe:e.csp,r=e.frameOptions===void 0?"DENY":e.frameOptions,o=e.referrerPolicy===void 0?"no-referrer":e.referrerPolicy,s=e.cacheControl===void 0?"private, no-store":e.cacheControl;return async(i,d,y)=>{typeof d?.setHeader=="function"&&(d.setHeader("X-Content-Type-Options","nosniff"),r&&d.setHeader("X-Frame-Options",r),o&&d.setHeader("Referrer-Policy",o),s&&d.setHeader("Cache-Control",s),t&&d.setHeader("Content-Security-Policy",t)),await y();}}function Ve(e,t){return `<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />