@lpdjs/firestore-repo-service 2.1.11 → 2.1.13

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.
@@ -1,4 +1,4 @@
1
- import {z as z$1}from'zod';function ue(e){let t=[],n=e.replace(/[.*+?^${}()|[\]\\]/g,c=>c===":"?c:`\\${c}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(c,i)=>(t.push(i),"([^/]+)"));return {pattern:new RegExp(`^${n}$`),paramNames:t}}function pe(e){let t=e.path??e.url??"/",n=t.indexOf("?");return n===-1?t:t.slice(0,n)}var G=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(t,n)=>{n.status(404).send("Not Found");};this.errorHandler=(t,n,c)=>{console.error("[MiniRouter]",t),c.status(500).send("Internal Server Error");};}use(t){return this.middlewares.push(t),this}get(t,n){return this.addRoute("GET",t,n)}post(t,n){return this.addRoute("POST",t,n)}put(t,n){return this.addRoute("PUT",t,n)}patch(t,n){return this.addRoute("PATCH",t,n)}delete(t,n){return this.addRoute("DELETE",t,n)}onNotFound(t){return this.notFoundHandler=t,this}onError(t){return this.errorHandler=t,this}addRoute(t,n,c){let{pattern:i,paramNames:d}=ue(n);return this.routes.push({method:t.toUpperCase(),pattern:i,paramNames:d,handler:c}),this}async handle(t,n){let c=(t.method??"GET").toUpperCase(),i=pe(t),d=null,u={};for(let h of this.routes){if(h.method!==c)continue;let b=i.match(h.pattern);if(b){d=h,u={},h.paramNames.forEach((x,v)=>{u[x]=decodeURIComponent(b[v+1]??"");});break}}let g=Object.assign(t,{params:u}),p=d?d.handler:this.notFoundHandler;try{await this.runMiddlewareChain(g,n,p);}catch(h){this.errorHandler(h,t,n);}}async runMiddlewareChain(t,n,c){let i=0,d=async()=>{if(i<this.middlewares.length){let u=this.middlewares[i++];await u(t,n,d);}else await c(t,n);};await d();}};var le=new Set(["<","<=",">",">=","!="]),fe=new Set(["array-contains","array-contains-any"]);function K(e){return e==="desc"?"DESCENDING":"ASCENDING"}function ye(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function ge(e,t,n,c,i){let d=[],u=new Set;for(let p of c)if(p.op==="=="||p.op==="in"||p.op==="not-in"){if(u.has(p.field))continue;u.add(p.field),d.push({fieldPath:p.field,order:"ASCENDING"});}for(let p of c)if(fe.has(p.op)){if(u.has(p.field))continue;u.add(p.field),d.push({fieldPath:p.field,arrayConfig:"CONTAINS"});}for(let p of c)if(le.has(p.op)){if(u.has(p.field))continue;u.add(p.field);let h=i?.field===p.field?K(i.dir):"ASCENDING";d.push({fieldPath:p.field,order:h});}if(i&&!u.has(i.field)&&d.push({fieldPath:i.field,order:K(i.dir)}),d.length===1&&n)return Re(e,t,d[0]);let g=i&&d.some(p=>p.fieldPath===i.field)?K(i.dir):"ASCENDING";return d.push({fieldPath:"__name__",order:g}),me(e,t,n,d)}function me(e,t,n,c,i="(default)"){let d=`projects/${e}/databases/${i}/collectionGroups/${t}/indexes/_`,u=[...M(1,d),...z(2,n?2:1)];for(let h of c)u.push(...Y(3,X(h)));let g=i==="(default)"?"-default-":i,p=encodeURIComponent(ee(u));return `https://console.firebase.google.com/project/${e}/firestore/databases/${g}/indexes?create_composite=${p}`}function he(e){return e.match(/https:\/\/console\.firebase\.google\.com[^\s)"]*/)?.[0]}function H(e){let t=[],n=e>>>0;for(;n>=128;)t.push(n&127|128),n>>>=7;return t.push(n&127),t}function W(e,t){return e<<3|t}function M(e,t){let n=Array.from(new TextEncoder().encode(t));return [W(e,2),...H(n.length),...n]}function z(e,t){return [W(e,0),...H(t)]}function Y(e,t){return [W(e,2),...H(t.length),...t]}function X(e){let t=[...M(1,e.fieldPath)];return e.arrayConfig==="CONTAINS"?t.push(...z(3,1)):t.push(...z(2,e.order==="DESCENDING"?2:1)),t}function ee(e){let t=String.fromCharCode(...e),n;if(typeof Buffer<"u")n=Buffer.from(e).toString("base64");else if(typeof btoa<"u")n=btoa(t);else throw new Error("No base64 encoder available");return n.replace(/=+$/,"")}function Re(e,t,n,c="(default)"){let i=`projects/${e}/databases/${c}/collectionGroups/${t}/fields/${n.fieldPath}`,d=[...M(1,i),...z(2,2),...Y(3,X(n))],u=c==="(default)"?"-default-":c,g=encodeURIComponent(ee(d));return `https://console.firebase.google.com/project/${e}/firestore/databases/${u}/indexes/automatic?create_exemption=${g}`}function be(e){let t=e,n=[t?.firestore?.projectId,t?.firestore?.app?.options?.projectId,t?.firestore?._settings?.projectId,t?.firestore?.databaseId?.projectId,t?._firestore?.projectId];for(let i of n)if(typeof i=="string"&&i.length>0)return i;return process.env.GCLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT||process.env.FIREBASE_PROJECT_ID||void 0}function we(e){let t=e;return t?t.code===9?true:typeof t.message=="string"?t.message.includes("requires an index"):false:false}function te(e,t){let n=e??{},c=we(e),i;if(c&&(i=n.message?he(n.message):void 0,!i)){let d=be(t.ref);if(d){let u=ye(t.path);i=ge(d,u,t.isGroup,t.filters,t.sort);}}return {type:c?"index":"error",message:c?"This query requires a composite index that does not exist yet.":n.message??"Query failed",indexUrl:i}}function Q(e,t,n=200){e.status(n).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(t));}function T(e,t,n,c=200){Q(e,{success:true,data:t,meta:n},c);}function S(e,t,n=400){Q(e,{success:false,error:t},n);}function L(e,t,n,c,i){let d=te(t,n),u=d.type==="index",g=u?424:500,h={success:false,error:u?d.message:i&&t instanceof Error?t.message:c};u&&(h.errorType="index",d.indexUrl&&(h.indexUrl=d.indexUrl)),Q(e,h,g);}var ne="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function Oe(){let e="";for(let t=0;t<20;t++)e+=ne.charAt(Math.floor(Math.random()*ne.length));return e}function Ce(e,t,n=[]){let c=e.shape,i={},d=t&&t.length>0?t:Object.keys(c);for(let u of d){if(n.includes(u))continue;let g=u.split(".")[0];g&&c[g]&&(i[g]=c[g]);}return z$1.object(i)}function re(e,t,n,c=false,i=[]){try{let d=Ce(e,n,i);return {success:!0,data:(c?d.partial():d).parse(t)}}catch(d){return d instanceof z$1.ZodError?{success:false,error:`Validation failed: ${d.issues.map(g=>`${g.path.join(".")}: ${g.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function Pe(e,t){let n=[],c=t?new Set(t):null,i={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[d,u]of Object.entries(e)){if(u===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(d))continue;let g=Array.isArray(u)?u[0]:u;if(g===void 0||g==="")continue;let p=d.match(/^(\w+)__(\w+)$/),h,b="==";if(p&&p[1]&&p[2]){h=p[1];let v=p[2];if(i[v])b=i[v];else continue}else if(!p)h=d;else continue;if(c&&!c.has(h))continue;let x=g;b==="in"||b==="not-in"||b==="array-contains-any"?x=g.split(",").map(v=>se(v.trim())):x=se(g),n.push({field:h,op:b,value:x});}return n}function se(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 U(e){return e?{docId:e.id}:null}async function oe(e,t){if(!t||typeof t!="object")return;let n=t.docId;if(typeof n=="string")try{let c=e.repo.ref;if(typeof c.doc!="function")return;let i=await c.doc(n).get();return i.exists?i:void 0}catch{return}}function ae(e,t,n){function c(m,l){return !m||!e[m]?(S(l,`Repository "${m}" not found`,404),null):e[m]}function i(m,l){if(!l)return;let y=m[l];if(typeof y!="string"||!y)return;let r=y.split("/").filter(Boolean),a=[];for(let o=1;o<r.length;o+=2)a.push(r[o]);return a.length>0?a:void 0}async function d(m,l){let y=`by${m.documentKey.charAt(0).toUpperCase()}${m.documentKey.slice(1)}`,r=m.repo.get[y];if(typeof r=="function")try{let o=await r(l);if(o)return o}catch{}return (await m.repo.query.by({where:[[m.documentKey,"==",l]],limit:1}))[0]??null}async function u(m,l){let y=m.params||{},r=c(y.repoName,l);if(!r)return;let a=[],o;try{let s=m.query??{},f=Math.min(Number(s.pageSize)||r.pageSize,100),w=s.cursor,R=s.direction?.toLowerCase()==="prev"?"prev":"next",P=s.orderBy,A=s.orderDir?.toLowerCase()==="desc"?"desc":"asc",O=s.select,C=O?O.split(",").map(N=>N.trim()):void 0,I;r.allowedIncludes&&s.includes&&(I=(typeof s.includes=="string"?s.includes.split(",").map(_=>_.trim()):Array.isArray(s.includes)?s.includes:[]).filter(_=>typeof _=="string"&&r.allowedIncludes.includes(_)),I?.length===0&&(I=void 0));let $=Pe(s,r.filterableFields);a=$.map(N=>({field:N.field,op:N.op,value:String(N.value??"")})),P&&(o={field:P,dir:A});let F={pageSize:f,direction:R};if(w)try{let N=typeof w=="string"?JSON.parse(w):w;F.cursor=await oe(r,N);}catch{}P&&(F.orderBy=[{field:P,direction:A}]),$.length>0&&(F.where=$.map(N=>[N.field,N.op,N.value])),C&&(F.select=C),I&&(F.include=I);let D=await r.repo.query.paginate(F),de={items:D.data,hasNextPage:D.hasNextPage,hasPrevPage:D.hasPrevPage,nextCursor:U(D.nextCursor),prevCursor:U(D.prevCursor)};T(l,de,{pageSize:f,hasMore:D.hasNextPage});}catch(s){L(l,s,{ref:r.repo.ref,path:r.path,isGroup:!!r.isGroup,filters:a,sort:o},"Failed to fetch documents",n);}}async function g(m,l){let y=m.params||{},r=c(y.repoName,l);if(!r)return;let a=[],o;try{let s=m.body??{},f=Math.min(s.pageSize||r.pageSize,100),w=s.direction==="prev"?"prev":"next";s.where&&(a=s.where.map(O=>({field:String(O[0]),op:O[1],value:String(O[2]??"")}))),s.orderBy&&s.orderBy[0]&&(o={field:s.orderBy[0].field,dir:s.orderBy[0].direction==="desc"?"desc":"asc"});let R={pageSize:f,direction:w};if(s.cursor)try{let O=typeof s.cursor=="string"?JSON.parse(s.cursor):s.cursor;R.cursor=await oe(r,O);}catch{}if(r.allowedIncludes&&s.includes&&s.includes.length>0){let O=s.includes.filter(C=>typeof C=="string"?r.allowedIncludes.includes(C):typeof C=="object"&&C!==null&&"relation"in C&&typeof C.relation=="string"?r.allowedIncludes.includes(C.relation):!1);O.length>0&&(R.include=O);}if(s.where&&s.where.length>0){if(r.filterableFields){let O=new Set(r.filterableFields),C=s.where.filter(I=>!O.has(I[0]));if(C.length>0){S(l,`Fields not filterable: ${C.map(I=>I[0]).join(", ")}`,400);return}}R.where=s.where;}if(s.orWhere&&s.orWhere.length>0){if(r.filterableFields){let O=new Set(r.filterableFields),C=s.orWhere.filter(I=>!O.has(I[0]));if(C.length>0){S(l,`Fields not filterable: ${C.map(I=>I[0]).join(", ")}`,400);return}}R.orWhere=s.orWhere;}if(s.orWhereGroups&&s.orWhereGroups.length>0){if(r.filterableFields){let O=new Set(r.filterableFields);for(let C of s.orWhereGroups){let I=C.filter($=>!O.has($[0]));if(I.length>0){S(l,`Fields not filterable: ${I.map($=>$[0]).join(", ")}`,400);return}}}R.orWhereGroups=s.orWhereGroups;}s.orderBy&&s.orderBy.length>0&&(R.orderBy=s.orderBy),s.select&&s.select.length>0&&(R.select=s.select);let P=await r.repo.query.paginate(R),A={items:P.data,hasNextPage:P.hasNextPage,hasPrevPage:P.hasPrevPage,nextCursor:U(P.nextCursor),prevCursor:U(P.prevCursor)};T(l,A,{pageSize:f,hasMore:P.hasNextPage});}catch(s){L(l,s,{ref:r.repo.ref,path:r.path,isGroup:!!r.isGroup,filters:a,sort:o},"Failed to query documents",n);}}async function p(m,l){let y=m.params||{},r=c(y.repoName,l);if(!r)return;let a=y.id;if(!a){S(l,"Document ID required",400);return}try{let o=await d(r,a);if(!o){S(l,"Document not found",404);return}T(l,o);}catch(o){L(l,o,{ref:r.repo.ref,path:r.path,isGroup:!!r.isGroup,filters:[{field:r.documentKey,op:"==",value:a}]},"Failed to fetch document",n);}}async function h(m,l){let y=m.params||{},r=c(y.repoName,l);if(r)try{let a=m.body??{},o=re(r.schema,a,r.createFields,!1,r.systemKeys);if(!o.success){S(l,o.error,400);return}if(r.validate){let f=await r.validate(o.data,"create");if(f){S(l,f,400);return}}let s;if(r.isGroup&&r.parentKeys&&r.parentKeys.length>0){let f={...o.data};r.createdKey&&(f[r.createdKey]=new Date);let w=r.parentKeys.filter(A=>!f[A]);if(w.length>0){S(l,`Missing parent key(s) for subcollection create: ${w.join(", ")}`,400);return}let R=r.parentKeys.map(A=>f[A]),P=f[r.documentKey]||Oe();s=await r.repo.set(...R,P,f);}else s=await r.repo.create(o.data);T(l,s,void 0,201);}catch(a){let o=n&&a instanceof Error?a.message:"Failed to create document";S(l,o,500);}}async function b(m,l,y){let r=m.params||{},a=c(r.repoName,l);if(!a)return;let o=r.id;if(!o){S(l,"Document ID required",400);return}try{let s=m.body??{},f=re(a.schema,s,a.mutableFields,y,a.systemKeys);if(!f.success){S(l,f.error,400);return}if(a.validate){let A=await a.validate(f.data,"update");if(A){S(l,A,400);return}}let w=await d(a,o),R=(w&&i(w,a.pathKey))??[o],P=await a.repo.update(...R,f.data);T(l,P);}catch(s){let f=n&&s instanceof Error?s.message:"Failed to update document";S(l,f,500);}}async function x(m,l){let y=m.params||{},r=c(y.repoName,l);if(!r)return;if(!r.allowDelete){S(l,"Delete not allowed for this repository",403);return}let a=y.id;if(!a){S(l,"Document ID required",400);return}try{let o=await d(r,a),s=(o&&i(o,r.pathKey))??[a];await r.repo.delete(...s),T(l,{deleted:!0});}catch(o){let s=n&&o instanceof Error?o.message:"Failed to delete document";S(l,s,500);}}function v(m,l){l.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:u,handleQuery:g,handleGet:p,handleCreate:h,handleUpdate:b,handleDelete:x,handleOptions:v}}function J(e){try{return z$1.toJSONSchema(e,{target:"openapi-3.1",unrepresentable:"any",override:t=>{let n=t.zodSchema?._zod?.def;n&&(n.type==="date"?(t.jsonSchema.type="string",t.jsonSchema.format="date-time"):n.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 B(e,t){return {description:e,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:t},required:["success","data"]}}}}}function ce(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 Ie(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 ve(e){let t=e.filterableFields??Object.keys(e.schema.shape),n=["eq","ne","lt","lte","gt","gte","in","nin","contains"],c=[];for(let i of t){c.push({name:i,in:"query",schema:{type:"string"},description:`Filter by ${i} (equality)`});for(let d of n)c.push({name:`${i}__${d}`,in:"query",schema:{type:"string"},description:`Filter ${i} with operator ${d}`});}return c}function Se(){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 Ae(e,t,n,c,i){let d={},u=e.name,g=`${t}/${e.name}`,p=`${g}/{${e.documentKey}}`,h={name:e.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};d[g]={get:{operationId:`list${q(e.name)}`,summary:`List ${e.name} (paginated)`,tags:[u],parameters:[...Ie(e),...ve(e)],responses:{200:ce(j(n)),500:E("Internal server error")}},post:{operationId:`create${q(e.name)}`,summary:`Create a ${k(e.name)}`,tags:[u],requestBody:{required:true,content:{"application/json":{schema:j(c??n)}}},responses:{201:B("Document created",j(n)),400:E("Validation error"),500:E("Internal server error")}}},d[`${g}/query`]={post:{operationId:`query${q(e.name)}`,summary:`Query ${e.name} with advanced filters`,tags:[u],requestBody:{required:true,content:{"application/json":{schema:j("QueryRequestBody")}}},responses:{200:ce(j(n)),400:E("Invalid query"),500:E("Internal server error")}}};let b={};return b.get={operationId:`get${q(k(e.name))}`,summary:`Get a single ${k(e.name)}`,tags:[u],parameters:[h],responses:{200:B("Document found",j(n)),404:E("Document not found"),500:E("Internal server error")}},b.put={operationId:`update${q(k(e.name))}`,summary:`Update a ${k(e.name)} (full replace)`,tags:[u],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:j(i??n)}}},responses:{200:B("Document updated",j(n)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},b.patch={operationId:`patch${q(k(e.name))}`,summary:`Partially update a ${k(e.name)}`,tags:[u],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:{allOf:[j(i??n)],description:"All fields are optional for partial updates"}}}},responses:{200:B("Document patched",j(n)),400:E("Validation error"),404:E("Document not found"),500:E("Internal server error")}},e.allowDelete&&(b.delete={operationId:`delete${q(k(e.name))}`,summary:`Delete a ${k(e.name)}`,tags:[u],parameters:[h],responses:{200:B("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:E("Document not found"),500:E("Internal server error")}}),d[p]=b,d}function V(e,t,n={}){let{title:c="CRUD API",version:i="1.0.0",description:d,servers:u,auth:g=false}=n,p=t==="/"?"":t.replace(/\/$/,""),h={},b={},x=[];h.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},h.QueryRequestBody=Se();for(let[y,r]of Object.entries(e)){let a=q(k(y)),o=`${a}Create`,s=`${a}Update`;h[a]=J(r.schema);let f=C=>{let I=C&&C.length>0?C:Object.keys(r.schema.shape),$={};for(let F of I){let D=F.split(".")[0];D&&r.schema.shape[D]&&!r.systemKeys.includes(D)&&($[D]=r.schema.shape[D]);}return $},w=null,R=f(r.createFields);Object.keys(R).length>0&&(h[o]=J(z$1.object(R)),w=o);let P=null,A=f(r.mutableFields);Object.keys(A).length>0&&(h[s]=J(z$1.object(A)),P=s);let O=Ae(r,p,a,w,P);Object.assign(b,O),x.push({name:y,description:`Operations on ${y} (collection: ${r.path})`});}let v={},m;return g==="basic"?(v.basicAuth={type:"http",scheme:"basic"},m=[{basicAuth:[]}]):g==="bearer"&&(v.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},m=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:c,version:i,...d?{description:d}:{}},...u&&u.length>0?{servers:u}:{},paths:b,components:{schemas:h,...Object.keys(v).length>0?{securitySchemes:v}:{}},...m?{security:m}:{},tags:x}}function q(e){return e.charAt(0).toUpperCase()+e.slice(1)}function k(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}function xe(e,t){return `<!DOCTYPE html>
1
+ import {z}from'zod';import {Timestamp}from'firebase-admin/firestore';function he(e){let t=[],n=e.replace(/[.*+?^${}()|[\]\\]/g,r=>r===":"?r:`\\${r}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(r,i)=>(t.push(i),"([^/]+)"));return {pattern:new RegExp(`^${n}$`),paramNames:t}}function Re(e){let t=e.path??e.url??"/",n=t.indexOf("?");return n===-1?t:t.slice(0,n)}var U=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(t,n)=>{n.status(404).send("Not Found");};this.errorHandler=(t,n,r)=>{console.error("[MiniRouter]",t),r.status(500).send("Internal Server Error");};}use(t){return this.middlewares.push(t),this}get(t,n){return this.addRoute("GET",t,n)}post(t,n){return this.addRoute("POST",t,n)}put(t,n){return this.addRoute("PUT",t,n)}patch(t,n){return this.addRoute("PATCH",t,n)}delete(t,n){return this.addRoute("DELETE",t,n)}onNotFound(t){return this.notFoundHandler=t,this}onError(t){return this.errorHandler=t,this}addRoute(t,n,r){let{pattern:i,paramNames:c}=he(n);return this.routes.push({method:t.toUpperCase(),pattern:i,paramNames:c,handler:r}),this}async handle(t,n){let r=(t.method??"GET").toUpperCase(),i=Re(t),c=null,u={};for(let h of this.routes){if(h.method!==r)continue;let b=i.match(h.pattern);if(b){c=h,u={},h.paramNames.forEach((D,x)=>{u[D]=decodeURIComponent(b[x+1]??"");});break}}let m=Object.assign(t,{params:u}),p=c?c.handler:this.notFoundHandler;try{await this.runMiddlewareChain(m,n,p);}catch(h){this.errorHandler(h,t,n);}}async runMiddlewareChain(t,n,r){let i=0,c=async()=>{if(i<this.middlewares.length){let u=this.middlewares[i++];await u(t,n,c);}else await r(t,n);};await c();}};var ne="preserve";function re(){return ne}function be(e){return typeof e=="object"&&e!==null&&typeof e._seconds=="number"&&typeof e._nanoseconds=="number"}function se(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(be(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 oe(e){return e}var Oe=new Set(["<","<=",">",">=","!="]),Pe=new Set(["array-contains","array-contains-any"]);function W(e){return e==="desc"?"DESCENDING":"ASCENDING"}function Ce(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function Ie(e,t,n,r,i){let c=[],u=new Set;for(let p of r)if(p.op==="=="||p.op==="in"||p.op==="not-in"){if(u.has(p.field))continue;u.add(p.field),c.push({fieldPath:p.field,order:"ASCENDING"});}for(let p of r)if(Pe.has(p.op)){if(u.has(p.field))continue;u.add(p.field),c.push({fieldPath:p.field,arrayConfig:"CONTAINS"});}for(let p of r)if(Oe.has(p.op)){if(u.has(p.field))continue;u.add(p.field);let h=i?.field===p.field?W(i.dir):"ASCENDING";c.push({fieldPath:p.field,order:h});}if(i&&!u.has(i.field)&&c.push({fieldPath:i.field,order:W(i.dir)}),c.length===1&&n)return Se(e,t,c[0]);let m=i&&c.some(p=>p.fieldPath===i.field)?W(i.dir):"ASCENDING";return c.push({fieldPath:"__name__",order:m}),xe(e,t,n,c)}function xe(e,t,n,r,i="(default)"){let c=`projects/${e}/databases/${i}/collectionGroups/${t}/indexes/_`,u=[...Q(1,c),...H(2,n?2:1)];for(let h of r)u.push(...ie(3,ae(h)));let m=i==="(default)"?"-default-":i,p=encodeURIComponent(ce(u));return `https://console.firebase.google.com/project/${e}/firestore/databases/${m}/indexes?create_composite=${p}`}function Ae(e){return e.match(/https:\/\/console\.firebase\.google\.com[^\s)"]*/)?.[0]}function Z(e){let t=[],n=e>>>0;for(;n>=128;)t.push(n&127|128),n>>>=7;return t.push(n&127),t}function L(e,t){return e<<3|t}function Q(e,t){let n=Array.from(new TextEncoder().encode(t));return [L(e,2),...Z(n.length),...n]}function H(e,t){return [L(e,0),...Z(t)]}function ie(e,t){return [L(e,2),...Z(t.length),...t]}function ae(e){let t=[...Q(1,e.fieldPath)];return e.arrayConfig==="CONTAINS"?t.push(...H(3,1)):t.push(...H(2,e.order==="DESCENDING"?2:1)),t}function ce(e){let t=String.fromCharCode(...e),n;if(typeof Buffer<"u")n=Buffer.from(e).toString("base64");else if(typeof btoa<"u")n=btoa(t);else throw new Error("No base64 encoder available");return n.replace(/=+$/,"")}function Se(e,t,n,r="(default)"){let i=`projects/${e}/databases/${r}/collectionGroups/${t}/fields/${n.fieldPath}`,c=[...Q(1,i),...H(2,2),...ie(3,ae(n))],u=r==="(default)"?"-default-":r,m=encodeURIComponent(ce(c));return `https://console.firebase.google.com/project/${e}/firestore/databases/${u}/indexes/automatic?create_exemption=${m}`}function De(e){let t=e,n=[t?.firestore?.projectId,t?.firestore?.app?.options?.projectId,t?.firestore?._settings?.projectId,t?.firestore?.databaseId?.projectId,t?._firestore?.projectId];for(let i of n)if(typeof i=="string"&&i.length>0)return i;return process.env.GCLOUD_PROJECT||process.env.GOOGLE_CLOUD_PROJECT||process.env.FIREBASE_PROJECT_ID||void 0}function ve(e){let t=e;return t?t.code===9?true:typeof t.message=="string"?t.message.includes("requires an index"):false:false}function de(e,t){let n=e??{},r=ve(e),i;if(r&&(i=n.message?Ae(n.message):void 0,!i)){let c=De(t.ref);if(c){let u=Ce(t.path);i=Ie(c,u,t.isGroup,t.filters,t.sort);}}return {type:r?"index":"error",message:r?"This query requires a composite index that does not exist yet.":n.message??"Query failed",indexUrl:i}}function V(e,t,n=200){let r=oe(t);e.status(n).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(r));}function q(e,t,n,r=200){V(e,{success:true,data:t,meta:n},r);}function A(e,t,n=400){V(e,{success:false,error:t},n);}function J(e,t,n,r,i){let c=de(t,n),u=c.type==="index",m=u?424:500,h={success:false,error:u?c.message:i&&t instanceof Error?t.message:r};u&&(h.errorType="index",c.indexUrl&&(h.indexUrl=c.indexUrl)),V(e,h,m);}var ue="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function Ne(){let e="";for(let t=0;t<20;t++)e+=ue.charAt(Math.floor(Math.random()*ue.length));return e}function _(e){let t=e._def??e.def;if(!t)return e;let n=t.typeName??t.type;if(n==="ZodDate"||n==="date")return z.preprocess(r=>se(r)??r,e);if(n==="ZodObject"||n==="object"){let r=e.shape,i={};for(let[c,u]of Object.entries(r))i[c]=_(u);return z.object(i)}if(n==="ZodArray"||n==="array"){let r=t.element??t.type;if(r)return z.array(_(r))}if(n==="ZodOptional"||n==="optional"){let r=t.innerType;if(r)return _(r).optional()}if(n==="ZodNullable"||n==="nullable"){let r=t.innerType;if(r)return _(r).nullable()}if(n==="ZodDefault"||n==="default"){let r=t.innerType,i=t.defaultValue;if(r){let c=_(r);return typeof i=="function"?c.default(i()):c.default(i)}}return e}function je(e,t,n=[]){let r=e.shape,i={},c=t&&t.length>0?t:Object.keys(r);for(let u of c){if(n.includes(u))continue;let m=u.split(".")[0];m&&r[m]&&(i[m]=r[m]);}return z.object(i)}function pe(e,t,n,r=false,i=[]){try{let c=je(e,n,i),u=r?c.partial():c;return {success:!0,data:(re()==="normalize"?_(u):u).parse(t)}}catch(c){return c instanceof z.ZodError?{success:false,error:`Validation failed: ${c.issues.map(m=>`${m.path.join(".")}: ${m.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function Ee(e,t){let n=[],r=t?new Set(t):null,i={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[c,u]of Object.entries(e)){if(u===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(c))continue;let m=Array.isArray(u)?u[0]:u;if(m===void 0||m==="")continue;let p=c.match(/^(\w+)__(\w+)$/),h,b="==";if(p&&p[1]&&p[2]){h=p[1];let x=p[2];if(i[x])b=i[x];else continue}else if(!p)h=c;else continue;if(r&&!r.has(h))continue;let D=m;b==="in"||b==="not-in"||b==="array-contains-any"?D=m.split(",").map(x=>le(x.trim())):D=le(m),n.push({field:h,op:b,value:D});}return n}function le(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 K(e){return e?{docId:e.id}:null}async function fe(e,t){if(!t||typeof t!="object")return;let n=t.docId;if(typeof n=="string")try{let r=e.repo.ref;if(typeof r.doc!="function")return;let i=await r.doc(n).get();return i.exists?i:void 0}catch{return}}function ye(e,t,n){function r(g,l){return !g||!e[g]?(A(l,`Repository "${g}" not found`,404),null):e[g]}function i(g,l){if(!l)return;let y=g[l];if(typeof y!="string"||!y)return;let s=y.split("/").filter(Boolean),d=[];for(let a=1;a<s.length;a+=2)d.push(s[a]);return d.length>0?d:void 0}async function c(g,l){let y=`by${g.documentKey.charAt(0).toUpperCase()}${g.documentKey.slice(1)}`,s=g.repo.get[y];if(typeof s=="function")try{let a=await s(l);if(a)return a}catch{}return (await g.repo.query.by({where:[[g.documentKey,"==",l]],limit:1}))[0]??null}async function u(g,l){let y=g.params||{},s=r(y.repoName,l);if(!s)return;let d=[],a;try{let o=g.query??{},f=Math.min(Number(o.pageSize)||s.pageSize,100),w=o.cursor,R=o.direction?.toLowerCase()==="prev"?"prev":"next",C=o.orderBy,S=o.orderDir?.toLowerCase()==="desc"?"desc":"asc",O=o.select,P=O?O.split(",").map(E=>E.trim()):void 0,I;s.allowedIncludes&&o.includes&&(I=(typeof o.includes=="string"?o.includes.split(",").map(G=>G.trim()):Array.isArray(o.includes)?o.includes:[]).filter(G=>typeof G=="string"&&s.allowedIncludes.includes(G)),I?.length===0&&(I=void 0));let N=Ee(o,s.filterableFields);d=N.map(E=>({field:E.field,op:E.op,value:String(E.value??"")})),C&&(a={field:C,dir:S});let k={pageSize:f,direction:R};if(w)try{let E=typeof w=="string"?JSON.parse(w):w;k.cursor=await fe(s,E);}catch{}C&&(k.orderBy=[{field:C,direction:S}]),N.length>0&&(k.where=N.map(E=>[E.field,E.op,E.value])),P&&(k.select=P),I&&(k.include=I);let j=await s.repo.query.paginate(k),ge={items:j.data,hasNextPage:j.hasNextPage,hasPrevPage:j.hasPrevPage,nextCursor:K(j.nextCursor),prevCursor:K(j.prevCursor)};q(l,ge,{pageSize:f,hasMore:j.hasNextPage});}catch(o){J(l,o,{ref:s.repo.ref,path:s.path,isGroup:!!s.isGroup,filters:d,sort:a},"Failed to fetch documents",n);}}async function m(g,l){let y=g.params||{},s=r(y.repoName,l);if(!s)return;let d=[],a;try{let o=g.body??{},f=Math.min(o.pageSize||s.pageSize,100),w=o.direction==="prev"?"prev":"next";o.where&&(d=o.where.map(O=>({field:String(O[0]),op:O[1],value:String(O[2]??"")}))),o.orderBy&&o.orderBy[0]&&(a={field:o.orderBy[0].field,dir:o.orderBy[0].direction==="desc"?"desc":"asc"});let R={pageSize:f,direction:w};if(o.cursor)try{let O=typeof o.cursor=="string"?JSON.parse(o.cursor):o.cursor;R.cursor=await fe(s,O);}catch{}if(s.allowedIncludes&&o.includes&&o.includes.length>0){let O=o.includes.filter(P=>typeof P=="string"?s.allowedIncludes.includes(P):typeof P=="object"&&P!==null&&"relation"in P&&typeof P.relation=="string"?s.allowedIncludes.includes(P.relation):!1);O.length>0&&(R.include=O);}if(o.where&&o.where.length>0){if(s.filterableFields){let O=new Set(s.filterableFields),P=o.where.filter(I=>!O.has(I[0]));if(P.length>0){A(l,`Fields not filterable: ${P.map(I=>I[0]).join(", ")}`,400);return}}R.where=o.where;}if(o.orWhere&&o.orWhere.length>0){if(s.filterableFields){let O=new Set(s.filterableFields),P=o.orWhere.filter(I=>!O.has(I[0]));if(P.length>0){A(l,`Fields not filterable: ${P.map(I=>I[0]).join(", ")}`,400);return}}R.orWhere=o.orWhere;}if(o.orWhereGroups&&o.orWhereGroups.length>0){if(s.filterableFields){let O=new Set(s.filterableFields);for(let P of o.orWhereGroups){let I=P.filter(N=>!O.has(N[0]));if(I.length>0){A(l,`Fields not filterable: ${I.map(N=>N[0]).join(", ")}`,400);return}}}R.orWhereGroups=o.orWhereGroups;}o.orderBy&&o.orderBy.length>0&&(R.orderBy=o.orderBy),o.select&&o.select.length>0&&(R.select=o.select);let C=await s.repo.query.paginate(R),S={items:C.data,hasNextPage:C.hasNextPage,hasPrevPage:C.hasPrevPage,nextCursor:K(C.nextCursor),prevCursor:K(C.prevCursor)};q(l,S,{pageSize:f,hasMore:C.hasNextPage});}catch(o){J(l,o,{ref:s.repo.ref,path:s.path,isGroup:!!s.isGroup,filters:d,sort:a},"Failed to query documents",n);}}async function p(g,l){let y=g.params||{},s=r(y.repoName,l);if(!s)return;let d=y.id;if(!d){A(l,"Document ID required",400);return}try{let a=await c(s,d);if(!a){A(l,"Document not found",404);return}q(l,a);}catch(a){J(l,a,{ref:s.repo.ref,path:s.path,isGroup:!!s.isGroup,filters:[{field:s.documentKey,op:"==",value:d}]},"Failed to fetch document",n);}}async function h(g,l){let y=g.params||{},s=r(y.repoName,l);if(s)try{let d=g.body??{},a=pe(s.schema,d,s.createFields,!1,s.systemKeys);if(!a.success){A(l,a.error,400);return}if(s.validate){let f=await s.validate(a.data,"create");if(f){A(l,f,400);return}}let o;if(s.isGroup&&s.parentKeys&&s.parentKeys.length>0){let f={...a.data};s.createdKey&&(f[s.createdKey]=new Date);let w=s.parentKeys.filter(S=>!f[S]);if(w.length>0){A(l,`Missing parent key(s) for subcollection create: ${w.join(", ")}`,400);return}let R=s.parentKeys.map(S=>f[S]),C=f[s.documentKey]||Ne();o=await s.repo.set(...R,C,f);}else o=await s.repo.create(a.data);q(l,o,void 0,201);}catch(d){let a=n&&d instanceof Error?d.message:"Failed to create document";A(l,a,500);}}async function b(g,l,y){let s=g.params||{},d=r(s.repoName,l);if(!d)return;let a=s.id;if(!a){A(l,"Document ID required",400);return}try{let o=g.body??{},f=pe(d.schema,o,d.mutableFields,y,d.systemKeys);if(!f.success){A(l,f.error,400);return}if(d.validate){let S=await d.validate(f.data,"update");if(S){A(l,S,400);return}}let w=await c(d,a),R=(w&&i(w,d.pathKey))??[a],C=await d.repo.update(...R,f.data);q(l,C);}catch(o){let f=n&&o instanceof Error?o.message:"Failed to update document";A(l,f,500);}}async function D(g,l){let y=g.params||{},s=r(y.repoName,l);if(!s)return;if(!s.allowDelete){A(l,"Delete not allowed for this repository",403);return}let d=y.id;if(!d){A(l,"Document ID required",400);return}try{let a=await c(s,d),o=(a&&i(a,s.pathKey))??[d];await s.repo.delete(...o),q(l,{deleted:!0});}catch(a){let o=n&&a instanceof Error?a.message:"Failed to delete document";A(l,o,500);}}function x(g,l){l.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:u,handleQuery:m,handleGet:p,handleCreate:h,handleUpdate:b,handleDelete:D,handleOptions:x}}function Y(e){try{return z.toJSONSchema(e,{target:"openapi-3.1",unrepresentable:"any",override:t=>{let n=t.zodSchema?._zod?.def;n&&(n.type==="date"?(t.jsonSchema.type="string",t.jsonSchema.format="date-time"):n.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 $(e){return {$ref:`#/components/schemas/${e}`}}function v(e){return {description:e,content:{"application/json":{schema:$("ErrorResponse")}}}}function B(e,t){return {description:e,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:t},required:["success","data"]}}}}}function me(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 $e(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 Te(e){let t=e.filterableFields??Object.keys(e.schema.shape),n=["eq","ne","lt","lte","gt","gte","in","nin","contains"],r=[];for(let i of t){r.push({name:i,in:"query",schema:{type:"string"},description:`Filter by ${i} (equality)`});for(let c of n)r.push({name:`${i}__${c}`,in:"query",schema:{type:"string"},description:`Filter ${i} with operator ${c}`});}return r}function ke(){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 Fe(e,t,n,r,i){let c={},u=e.name,m=`${t}/${e.name}`,p=`${m}/{${e.documentKey}}`,h={name:e.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};c[m]={get:{operationId:`list${F(e.name)}`,summary:`List ${e.name} (paginated)`,tags:[u],parameters:[...$e(e),...Te(e)],responses:{200:me($(n)),500:v("Internal server error")}},post:{operationId:`create${F(e.name)}`,summary:`Create a ${T(e.name)}`,tags:[u],requestBody:{required:true,content:{"application/json":{schema:$(r??n)}}},responses:{201:B("Document created",$(n)),400:v("Validation error"),500:v("Internal server error")}}},c[`${m}/query`]={post:{operationId:`query${F(e.name)}`,summary:`Query ${e.name} with advanced filters`,tags:[u],requestBody:{required:true,content:{"application/json":{schema:$("QueryRequestBody")}}},responses:{200:me($(n)),400:v("Invalid query"),500:v("Internal server error")}}};let b={};return b.get={operationId:`get${F(T(e.name))}`,summary:`Get a single ${T(e.name)}`,tags:[u],parameters:[h],responses:{200:B("Document found",$(n)),404:v("Document not found"),500:v("Internal server error")}},b.put={operationId:`update${F(T(e.name))}`,summary:`Update a ${T(e.name)} (full replace)`,tags:[u],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:$(i??n)}}},responses:{200:B("Document updated",$(n)),400:v("Validation error"),404:v("Document not found"),500:v("Internal server error")}},b.patch={operationId:`patch${F(T(e.name))}`,summary:`Partially update a ${T(e.name)}`,tags:[u],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:{allOf:[$(i??n)],description:"All fields are optional for partial updates"}}}},responses:{200:B("Document patched",$(n)),400:v("Validation error"),404:v("Document not found"),500:v("Internal server error")}},e.allowDelete&&(b.delete={operationId:`delete${F(T(e.name))}`,summary:`Delete a ${T(e.name)}`,tags:[u],parameters:[h],responses:{200:B("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:v("Document not found"),500:v("Internal server error")}}),c[p]=b,c}function ee(e,t,n={}){let{title:r="CRUD API",version:i="1.0.0",description:c,servers:u,auth:m=false}=n,p=t==="/"?"":t.replace(/\/$/,""),h={},b={},D=[];h.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},h.QueryRequestBody=ke();for(let[y,s]of Object.entries(e)){let d=F(T(y)),a=`${d}Create`,o=`${d}Update`;h[d]=Y(s.schema);let f=P=>{let I=P&&P.length>0?P:Object.keys(s.schema.shape),N={};for(let k of I){let j=k.split(".")[0];j&&s.schema.shape[j]&&!s.systemKeys.includes(j)&&(N[j]=s.schema.shape[j]);}return N},w=null,R=f(s.createFields);Object.keys(R).length>0&&(h[a]=Y(z.object(R)),w=a);let C=null,S=f(s.mutableFields);Object.keys(S).length>0&&(h[o]=Y(z.object(S)),C=o);let O=Fe(s,p,d,w,C);Object.assign(b,O),D.push({name:y,description:`Operations on ${y} (collection: ${s.path})`});}let x={},g;return m==="basic"?(x.basicAuth={type:"http",scheme:"basic"},g=[{basicAuth:[]}]):m==="bearer"&&(x.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},g=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:r,version:i,...c?{description:c}:{}},...u&&u.length>0?{servers:u}:{},paths:b,components:{schemas:h,...Object.keys(x).length>0?{securitySchemes:x}:{}},...g?{security:g}:{},tags:D}}function F(e){return e.charAt(0).toUpperCase()+e.slice(1)}function T(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}function qe(e,t){return `<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />
@@ -9,5 +9,5 @@ import {z as z$1}from'zod';function ue(e){let t=[],n=e.replace(/[.*+?^${}()|[\]\
9
9
  <script id="api-reference" data-url="${t}"></script>
10
10
  <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
11
11
  </body>
12
- </html>`}function Ee(e,t){let n=t==="/"?"":t.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let d=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",u=process.env.FUNCTION_REGION??"us-central1",g=process.env.FUNCTION_TARGET??"";return `/${d}/${u}/${g}${n}`}let c=process.env.K_SERVICE,i=e?.hostname??e?.headers?.host??"";return c&&i.includes("cloudfunctions.net")?`/${c.toLowerCase()}${n}`:n}async function $e(e){return typeof e.rawBody=="string"?e.rawBody:Buffer.isBuffer(e.rawBody)?e.rawBody.toString("utf8"):""}function Ue(e){let{basePath:t="/",repos:n,parseBody:c=true,auth:i,middleware:d=[],verbose:u=false,httpsOptions:g}=e,p=t==="/"?"":t.replace(/\/$/,""),h={};for(let[a,o]of Object.entries(n)){let s=o.schema??o.repo.schema??null;if(!s)throw new Error(`[createCrudServer] Repository "${a}" has no Zod schema. Either use createRepositoryConfig(schema)(config) or pass schema: explicitly.`);let f,w,R;if(o.fieldsConfig){let O=o.fieldsConfig;f=[],w=[],R=[];for(let[C,I]of Object.entries(O))for(let $ of I)$==="filterable"?f.push(C):$==="mutable"?w.push(C):$==="create"&&R.push(C);f.length===0&&(f=void 0),w.length===0&&(w=void 0),R.length===0&&(R=void 0);}let P=(()=>{let O=o.repo._parentKeys;return O&&O.length>0?O:void 0})();if(P&&R)for(let O of P)R.includes(O)||R.push(O);let A={name:a,path:o.path,repo:o.repo,schema:s,systemKeys:o.repo._systemKeys??[o.documentKey??"docId"],documentKey:o.documentKey??"docId",pathKey:o.repo._pathKey??void 0,isGroup:!!o.repo._isGroup,parentKeys:P,createdKey:o.repo._createdKey??void 0,pageSize:o.pageSize??25,filterableFields:f,mutableFields:w,createFields:R,allowDelete:o.allowDelete??false,allowedIncludes:o.allowedIncludes,validate:o.validate};h[a]=A;}let b=ae(h,p,u),x=e.openapi,v=x&&typeof x=="object"?x:{},m=null;function l(){if(!m){let a=i&&typeof i!="function"?"basic":i?"bearer":false;m=V(h,p,{...v,auth:v.auth??a});}return m}let y=new G;if(y.use((a,o,s)=>{o.set("Access-Control-Allow-Origin","*"),o.set("Access-Control-Allow-Credentials","true"),s();}),c&&y.use(async(a,o,s)=>{let f=a;if(String(f.headers?.["content-type"]??"").includes("application/json")){if(typeof f.body=="string")try{a.body=JSON.parse(f.body);}catch{}else if(Buffer.isBuffer(a.rawBody))try{let R=await $e(f);a.body=JSON.parse(R);}catch{}}await s();}),i)if(typeof i=="function")y.use(i);else {let a=i.realm??"API",o="Basic "+Buffer.from(`${i.username}:${i.password}`).toString("base64");y.use((s,f,w)=>{if((s.headers?.authorization??"")!==o){f.status(401).set("WWW-Authenticate",`Basic realm="${a}"`).set("Content-Type","application/json").send(JSON.stringify({success:false,error:"Unauthorized"}));return}w();});}for(let a of d)y.use(a);if(x!==false){let a=`${p}/__spec.json`,o=`${p}/__docs`;y.get(a,(s,f)=>{let w=l();f.status(200).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(w,null,2));}),y.get(o,(s,f)=>{let w=Ee(s,p)+"/__spec.json",R=xe(v.title??"CRUD API",w);f.status(200).set("Content-Type","text/html; charset=utf-8").send(R);});}y.use((a,o,s)=>{if(a.method==="OPTIONS"){b.handleOptions(a,o);return}s();}),y.get(`${p}/:repoName`,b.handleList),y.post(`${p}/:repoName/query`,b.handleQuery),y.get(`${p}/:repoName/:id`,b.handleGet),y.post(`${p}/:repoName`,b.handleCreate),y.put(`${p}/:repoName/:id`,(a,o)=>b.handleUpdate(a,o,false)),y.patch(`${p}/:repoName/:id`,(a,o)=>b.handleUpdate(a,o,true)),y.delete(`${p}/:repoName/:id`,b.handleDelete);let r=async(a,o)=>{await y.handle(a,o);};return r.spec=l,g&&(r.httpsOptions=g),r}export{Ue as createCrudServer,V as generateOpenAPISpec};//# sourceMappingURL=index.js.map
12
+ </html>`}function _e(e,t){let n=t==="/"?"":t.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let c=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",u=process.env.FUNCTION_REGION??"us-central1",m=process.env.FUNCTION_TARGET??"";return `/${c}/${u}/${m}${n}`}let r=process.env.K_SERVICE,i=e?.hostname??e?.headers?.host??"";return r&&i.includes("cloudfunctions.net")?`/${r.toLowerCase()}${n}`:n}async function ze(e){return typeof e.rawBody=="string"?e.rawBody:Buffer.isBuffer(e.rawBody)?e.rawBody.toString("utf8"):""}function et(e){let{basePath:t="/",repos:n,parseBody:r=true,auth:i,middleware:c=[],verbose:u=false,httpsOptions:m}=e,p=t==="/"?"":t.replace(/\/$/,""),h={};for(let[d,a]of Object.entries(n)){let o=a.schema??a.repo.schema??null;if(!o)throw new Error(`[createCrudServer] Repository "${d}" has no Zod schema. Either use createRepositoryConfig(schema)(config) or pass schema: explicitly.`);let f,w,R;if(a.fieldsConfig){let O=a.fieldsConfig;f=[],w=[],R=[];for(let[P,I]of Object.entries(O))for(let N of I)N==="filterable"?f.push(P):N==="mutable"?w.push(P):N==="create"&&R.push(P);f.length===0&&(f=void 0),w.length===0&&(w=void 0),R.length===0&&(R=void 0);}let C=(()=>{let O=a.repo._parentKeys;return O&&O.length>0?O:void 0})();if(C&&R)for(let O of C)R.includes(O)||R.push(O);let S={name:d,path:a.path,repo:a.repo,schema:o,systemKeys:a.repo._systemKeys??[a.documentKey??"docId"],documentKey:a.documentKey??"docId",pathKey:a.repo._pathKey??void 0,isGroup:!!a.repo._isGroup,parentKeys:C,createdKey:a.repo._createdKey??void 0,pageSize:a.pageSize??25,filterableFields:f,mutableFields:w,createFields:R,allowDelete:a.allowDelete??false,allowedIncludes:a.allowedIncludes,validate:a.validate};h[d]=S;}let b=ye(h,p,u),D=e.openapi,x=D&&typeof D=="object"?D:{},g=null;function l(){if(!g){let d=i&&typeof i!="function"?"basic":i?"bearer":false;g=ee(h,p,{...x,auth:x.auth??d});}return g}let y=new U;if(y.use((d,a,o)=>{a.set("Access-Control-Allow-Origin","*"),a.set("Access-Control-Allow-Credentials","true"),o();}),r&&y.use(async(d,a,o)=>{let f=d;if(String(f.headers?.["content-type"]??"").includes("application/json")){if(typeof f.body=="string")try{d.body=JSON.parse(f.body);}catch{}else if(Buffer.isBuffer(d.rawBody))try{let R=await ze(f);d.body=JSON.parse(R);}catch{}}await o();}),i)if(typeof i=="function")y.use(i);else {let d=i.realm??"API",a="Basic "+Buffer.from(`${i.username}:${i.password}`).toString("base64");y.use((o,f,w)=>{if((o.headers?.authorization??"")!==a){f.status(401).set("WWW-Authenticate",`Basic realm="${d}"`).set("Content-Type","application/json").send(JSON.stringify({success:false,error:"Unauthorized"}));return}w();});}for(let d of c)y.use(d);if(D!==false){let d=`${p}/__spec.json`,a=`${p}/__docs`;y.get(d,(o,f)=>{let w=l();f.status(200).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(w,null,2));}),y.get(a,(o,f)=>{let w=_e(o,p)+"/__spec.json",R=qe(x.title??"CRUD API",w);f.status(200).set("Content-Type","text/html; charset=utf-8").send(R);});}y.use((d,a,o)=>{if(d.method==="OPTIONS"){b.handleOptions(d,a);return}o();}),y.get(`${p}/:repoName`,b.handleList),y.post(`${p}/:repoName/query`,b.handleQuery),y.get(`${p}/:repoName/:id`,b.handleGet),y.post(`${p}/:repoName`,b.handleCreate),y.put(`${p}/:repoName/:id`,(d,a)=>b.handleUpdate(d,a,false)),y.patch(`${p}/:repoName/:id`,(d,a)=>b.handleUpdate(d,a,true)),y.delete(`${p}/:repoName/:id`,b.handleDelete);let s=async(d,a)=>{await y.handle(d,a);};return s.spec=l,m&&(s.httpsOptions=m),s}export{et as createCrudServer,ee as generateOpenAPISpec};//# sourceMappingURL=index.js.map
13
13
  //# sourceMappingURL=index.js.map