@lpdjs/firestore-repo-service 2.1.2 → 2.1.3

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
- 'use strict';var zod=require('zod');function Y(t){let n=[],o=t.replace(/[.*+?^${}()|[\]\\]/g,c=>c===":"?c:`\\${c}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(c,d)=>(n.push(d),"([^/]+)"));return {pattern:new RegExp(`^${o}$`),paramNames:n}}function X(t){let n=t.path??t.url??"/",o=n.indexOf("?");return o===-1?n:n.slice(0,o)}var B=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(n,o)=>{o.status(404).send("Not Found");};this.errorHandler=(n,o,c)=>{console.error("[MiniRouter]",n),c.status(500).send("Internal Server Error");};}use(n){return this.middlewares.push(n),this}get(n,o){return this.addRoute("GET",n,o)}post(n,o){return this.addRoute("POST",n,o)}put(n,o){return this.addRoute("PUT",n,o)}patch(n,o){return this.addRoute("PATCH",n,o)}delete(n,o){return this.addRoute("DELETE",n,o)}onNotFound(n){return this.notFoundHandler=n,this}onError(n){return this.errorHandler=n,this}addRoute(n,o,c){let{pattern:d,paramNames:l}=Y(o);return this.routes.push({method:n.toUpperCase(),pattern:d,paramNames:l,handler:c}),this}async handle(n,o){let c=(n.method??"GET").toUpperCase(),d=X(n),l=null,f={};for(let h of this.routes){if(h.method!==c)continue;let w=d.match(h.pattern);if(w){l=h,f={},h.paramNames.forEach((I,A)=>{f[I]=decodeURIComponent(w[A+1]??"");});break}}let R=Object.assign(n,{params:f}),O=l?l.handler:this.notFoundHandler;try{await this.runMiddlewareChain(R,o,O);}catch(h){this.errorHandler(h,n,o);}}async runMiddlewareChain(n,o,c){let d=0,l=async()=>{if(d<this.middlewares.length){let f=this.middlewares[d++];await f(n,o,l);}else await c(n,o);};await l();}};function Z(t,n,o=200){t.status(o).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(n));}function F(t,n,o,c=200){Z(t,{success:true,data:n,meta:o},c);}function C(t,n,o=400){Z(t,{success:false,error:n},o);}var U="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function ee(){let t="";for(let n=0;n<20;n++)t+=U.charAt(Math.floor(Math.random()*U.length));return t}function te(t,n,o=[]){let c=t.shape,d={},l=n&&n.length>0?n:Object.keys(c);for(let f of l){if(o.includes(f))continue;let R=f.split(".")[0];R&&c[R]&&(d[R]=c[R]);}return zod.z.object(d)}function G(t,n,o,c=false,d=[]){try{let l=te(t,o,d);return {success:!0,data:(c?l.partial():l).parse(n)}}catch(l){return l instanceof zod.z.ZodError?{success:false,error:`Validation failed: ${l.issues.map(R=>`${R.path.join(".")}: ${R.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function ne(t,n){let o=[],c=n?new Set(n):null,d={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[l,f]of Object.entries(t)){if(f===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(l))continue;let R=Array.isArray(f)?f[0]:f;if(R===void 0||R==="")continue;let O=l.match(/^(\w+)__(\w+)$/),h,w="==";if(O&&O[1]&&O[2]){h=O[1];let A=O[2];if(d[A])w=d[A];else continue}else if(!O)h=l;else continue;if(c&&!c.has(h))continue;let I=R;w==="in"||w==="not-in"||w==="array-contains-any"?I=R.split(",").map(A=>M(A.trim())):I=M(R),o.push({field:h,op:w,value:I});}return o}function M(t){if(t==="true")return true;if(t==="false")return false;if(t==="null")return null;let n=Number(t);return !isNaN(n)&&t!==""?n:t}function z(t){return t?{docId:t.id}:null}async function L(t,n){if(!n||typeof n!="object")return;let o=n.docId;if(typeof o=="string")try{let c=t.repo.ref;if(typeof c.doc!="function")return;let d=await c.doc(o).get();return d.exists?d:void 0}catch{return}}function Q(t,n,o){function c(p,i){return !p||!t[p]?(C(i,`Repository "${p}" not found`,404),null):t[p]}function d(p,i){if(!i)return;let u=p[i];if(typeof u!="string"||!u)return;let s=u.split("/").filter(Boolean),e=[];for(let r=1;r<s.length;r+=2)e.push(s[r]);return e.length>0?e:void 0}async function l(p,i){let u=`by${p.documentKey.charAt(0).toUpperCase()}${p.documentKey.slice(1)}`,s=p.repo.get[u];if(typeof s=="function")try{let r=await s(i);if(r)return r}catch{}return (await p.repo.query.by({where:[[p.documentKey,"==",i]],limit:1}))[0]??null}async function f(p,i){let u=p.params||{},s=c(u.repoName,i);if(s)try{let e=p.query??{},r=Math.min(Number(e.pageSize)||s.pageSize,100),y=e.cursor,a=e.direction?.toLowerCase()==="prev"?"prev":"next",g=e.orderBy,P=e.orderDir?.toLowerCase()==="desc"?"desc":"asc",v=e.select,m=v?v.split(",").map(D=>D.trim()):void 0,b;s.allowedIncludes&&e.includes&&(b=(typeof e.includes=="string"?e.includes.split(",").map(T=>T.trim()):Array.isArray(e.includes)?e.includes:[]).filter(T=>typeof T=="string"&&s.allowedIncludes.includes(T)),b?.length===0&&(b=void 0));let j=ne(e,s.filterableFields),x={pageSize:r,direction:a};if(y)try{let D=typeof y=="string"?JSON.parse(y):y;x.cursor=await L(s,D);}catch{}g&&(x.orderBy=[{field:g,direction:P}]),j.length>0&&(x.where=j.map(D=>[D.field,D.op,D.value])),m&&(x.select=m),b&&(x.include=b);let q=await s.repo.query.paginate(x),K={items:q.data,hasNextPage:q.hasNextPage,hasPrevPage:q.hasPrevPage,nextCursor:z(q.nextCursor),prevCursor:z(q.prevCursor)};F(i,K,{pageSize:r,hasMore:q.hasNextPage});}catch(e){let r=o&&e instanceof Error?e.message:"Failed to fetch documents";C(i,r,500);}}async function R(p,i){let u=p.params||{},s=c(u.repoName,i);if(s)try{let e=p.body??{},r=Math.min(e.pageSize||s.pageSize,100),y=e.direction==="prev"?"prev":"next",a={pageSize:r,direction:y};if(e.cursor)try{let v=typeof e.cursor=="string"?JSON.parse(e.cursor):e.cursor;a.cursor=await L(s,v);}catch{}if(s.allowedIncludes&&e.includes&&e.includes.length>0){let v=e.includes.filter(m=>typeof m=="string"?s.allowedIncludes.includes(m):typeof m=="object"&&m!==null&&"relation"in m&&typeof m.relation=="string"?s.allowedIncludes.includes(m.relation):!1);v.length>0&&(a.include=v);}if(e.where&&e.where.length>0){if(s.filterableFields){let v=new Set(s.filterableFields),m=e.where.filter(b=>!v.has(b[0]));if(m.length>0){C(i,`Fields not filterable: ${m.map(b=>b[0]).join(", ")}`,400);return}}a.where=e.where;}if(e.orWhere&&e.orWhere.length>0){if(s.filterableFields){let v=new Set(s.filterableFields),m=e.orWhere.filter(b=>!v.has(b[0]));if(m.length>0){C(i,`Fields not filterable: ${m.map(b=>b[0]).join(", ")}`,400);return}}a.orWhere=e.orWhere;}if(e.orWhereGroups&&e.orWhereGroups.length>0){if(s.filterableFields){let v=new Set(s.filterableFields);for(let m of e.orWhereGroups){let b=m.filter(j=>!v.has(j[0]));if(b.length>0){C(i,`Fields not filterable: ${b.map(j=>j[0]).join(", ")}`,400);return}}}a.orWhereGroups=e.orWhereGroups;}e.orderBy&&e.orderBy.length>0&&(a.orderBy=e.orderBy),e.select&&e.select.length>0&&(a.select=e.select);let g=await s.repo.query.paginate(a),P={items:g.data,hasNextPage:g.hasNextPage,hasPrevPage:g.hasPrevPage,nextCursor:z(g.nextCursor),prevCursor:z(g.prevCursor)};F(i,P,{pageSize:r,hasMore:g.hasNextPage});}catch(e){let r=o&&e instanceof Error?e.message:"Failed to query documents";C(i,r,500);}}async function O(p,i){let u=p.params||{},s=c(u.repoName,i);if(!s)return;let e=u.id;if(!e){C(i,"Document ID required",400);return}try{let r=await l(s,e);if(!r){C(i,"Document not found",404);return}F(i,r);}catch(r){let y=o&&r instanceof Error?r.message:"Failed to fetch document";C(i,y,500);}}async function h(p,i){let u=p.params||{},s=c(u.repoName,i);if(s)try{let e=p.body??{},r=G(s.schema,e,s.createFields,!1,s.systemKeys);if(!r.success){C(i,r.error,400);return}if(s.validate){let a=await s.validate(r.data,"create");if(a){C(i,a,400);return}}let y;if(s.isGroup&&s.parentKeys&&s.parentKeys.length>0){let a={...r.data};s.createdKey&&(a[s.createdKey]=new Date);let g=s.parentKeys.filter(m=>!a[m]);if(g.length>0){C(i,`Missing parent key(s) for subcollection create: ${g.join(", ")}`,400);return}let P=s.parentKeys.map(m=>a[m]),v=a[s.documentKey]||ee();y=await s.repo.set(...P,v,a);}else y=await s.repo.create(r.data);F(i,y,void 0,201);}catch(e){let r=o&&e instanceof Error?e.message:"Failed to create document";C(i,r,500);}}async function w(p,i,u){let s=p.params||{},e=c(s.repoName,i);if(!e)return;let r=s.id;if(!r){C(i,"Document ID required",400);return}try{let y=p.body??{},a=G(e.schema,y,e.mutableFields,u,e.systemKeys);if(!a.success){C(i,a.error,400);return}if(e.validate){let m=await e.validate(a.data,"update");if(m){C(i,m,400);return}}let g=await l(e,r),P=(g&&d(g,e.pathKey))??[r],v=await e.repo.update(...P,a.data);F(i,v);}catch(y){let a=o&&y instanceof Error?y.message:"Failed to update document";C(i,a,500);}}async function I(p,i){let u=p.params||{},s=c(u.repoName,i);if(!s)return;if(!s.allowDelete){C(i,"Delete not allowed for this repository",403);return}let e=u.id;if(!e){C(i,"Document ID required",400);return}try{let r=await l(s,e),y=(r&&d(r,s.pathKey))??[e];await s.repo.delete(...y),F(i,{deleted:!0});}catch(r){let y=o&&r instanceof Error?r.message:"Failed to delete document";C(i,y,500);}}function A(p,i){i.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:f,handleQuery:R,handleGet:O,handleCreate:h,handleUpdate:w,handleDelete:I,handleOptions:A}}function _(t){try{return zod.z.toJSONSchema(t,{target:"openapi-3.1"})}catch{return {type:"object"}}}function S(t){return {$ref:`#/components/schemas/${t}`}}function $(t){return {description:t,content:{"application/json":{schema:S("ErrorResponse")}}}}function N(t,n){return {description:t,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:n},required:["success","data"]}}}}}function V(t){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:t},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 re(t){return [{name:"pageSize",in:"query",schema:{type:"integer",default:t.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 se(t){let n=t.filterableFields??Object.keys(t.schema.shape),o=["eq","ne","lt","lte","gt","gte","in","nin","contains"],c=[];for(let d of n){c.push({name:d,in:"query",schema:{type:"string"},description:`Filter by ${d} (equality)`});for(let l of o)c.push({name:`${d}__${l}`,in:"query",schema:{type:"string"},description:`Filter ${d} with operator ${l}`});}return c}function oe(){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 ie(t,n,o,c,d){let l={},f=t.name,R=`${n}/${t.name}`,O=`${R}/{${t.documentKey}}`,h={name:t.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};l[R]={get:{operationId:`list${E(t.name)}`,summary:`List ${t.name} (paginated)`,tags:[f],parameters:[...re(t),...se(t)],responses:{200:V(S(o)),500:$("Internal server error")}},post:{operationId:`create${E(t.name)}`,summary:`Create a ${k(t.name)}`,tags:[f],requestBody:{required:true,content:{"application/json":{schema:S(c??o)}}},responses:{201:N("Document created",S(o)),400:$("Validation error"),500:$("Internal server error")}}},l[`${R}/query`]={post:{operationId:`query${E(t.name)}`,summary:`Query ${t.name} with advanced filters`,tags:[f],requestBody:{required:true,content:{"application/json":{schema:S("QueryRequestBody")}}},responses:{200:V(S(o)),400:$("Invalid query"),500:$("Internal server error")}}};let w={};return w.get={operationId:`get${E(k(t.name))}`,summary:`Get a single ${k(t.name)}`,tags:[f],parameters:[h],responses:{200:N("Document found",S(o)),404:$("Document not found"),500:$("Internal server error")}},w.put={operationId:`update${E(k(t.name))}`,summary:`Update a ${k(t.name)} (full replace)`,tags:[f],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:S(d??o)}}},responses:{200:N("Document updated",S(o)),400:$("Validation error"),404:$("Document not found"),500:$("Internal server error")}},w.patch={operationId:`patch${E(k(t.name))}`,summary:`Partially update a ${k(t.name)}`,tags:[f],parameters:[h],requestBody:{required:true,content:{"application/json":{schema:{allOf:[S(d??o)],description:"All fields are optional for partial updates"}}}},responses:{200:N("Document patched",S(o)),400:$("Validation error"),404:$("Document not found"),500:$("Internal server error")}},t.allowDelete&&(w.delete={operationId:`delete${E(k(t.name))}`,summary:`Delete a ${k(t.name)}`,tags:[f],parameters:[h],responses:{200:N("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:$("Document not found"),500:$("Internal server error")}}),l[O]=w,l}function W(t,n,o={}){let{title:c="CRUD API",version:d="1.0.0",description:l,servers:f,auth:R=false}=o,O=n==="/"?"":n.replace(/\/$/,""),h={},w={},I=[];h.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},h.QueryRequestBody=oe();for(let[u,s]of Object.entries(t)){let e=E(k(u)),r=`${e}Create`,y=`${e}Update`;h[e]=_(s.schema);let a=j=>{let x=j&&j.length>0?j:Object.keys(s.schema.shape),q={};for(let K of x){let D=K.split(".")[0];D&&s.schema.shape[D]&&!s.systemKeys.includes(D)&&(q[D]=s.schema.shape[D]);}return q},g=null,P=a(s.createFields);Object.keys(P).length>0&&(h[r]=_(zod.z.object(P)),g=r);let v=null,m=a(s.mutableFields);Object.keys(m).length>0&&(h[y]=_(zod.z.object(m)),v=y);let b=ie(s,O,e,g,v);Object.assign(w,b),I.push({name:u,description:`Operations on ${u} (collection: ${s.path})`});}let A={},p;return R==="basic"?(A.basicAuth={type:"http",scheme:"basic"},p=[{basicAuth:[]}]):R==="bearer"&&(A.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},p=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:c,version:d,...l?{description:l}:{}},...f&&f.length>0?{servers:f}:{},paths:w,components:{schemas:h,...Object.keys(A).length>0?{securitySchemes:A}:{}},...p?{security:p}:{},tags:I}}function E(t){return t.charAt(0).toUpperCase()+t.slice(1)}function k(t){return t.endsWith("ies")?t.slice(0,-3)+"y":t.endsWith("ses")||t.endsWith("xes")||t.endsWith("zes")?t.slice(0,-2):t.endsWith("s")&&!t.endsWith("ss")?t.slice(0,-1):t}function ae(t,n){return `<!DOCTYPE html>
1
+ 'use strict';var zod=require('zod');function Y(t){let n=[],o=t.replace(/[.*+?^${}()|[\]\\]/g,a=>a===":"?a:`\\${a}`).replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,(a,d)=>(n.push(d),"([^/]+)"));return {pattern:new RegExp(`^${o}$`),paramNames:n}}function X(t){let n=t.path??t.url??"/",o=n.indexOf("?");return o===-1?n:n.slice(0,o)}var B=class{constructor(){this.routes=[];this.middlewares=[];this.notFoundHandler=(n,o)=>{o.status(404).send("Not Found");};this.errorHandler=(n,o,a)=>{console.error("[MiniRouter]",n),a.status(500).send("Internal Server Error");};}use(n){return this.middlewares.push(n),this}get(n,o){return this.addRoute("GET",n,o)}post(n,o){return this.addRoute("POST",n,o)}put(n,o){return this.addRoute("PUT",n,o)}patch(n,o){return this.addRoute("PATCH",n,o)}delete(n,o){return this.addRoute("DELETE",n,o)}onNotFound(n){return this.notFoundHandler=n,this}onError(n){return this.errorHandler=n,this}addRoute(n,o,a){let{pattern:d,paramNames:p}=Y(o);return this.routes.push({method:n.toUpperCase(),pattern:d,paramNames:p,handler:a}),this}async handle(n,o){let a=(n.method??"GET").toUpperCase(),d=X(n),p=null,f={};for(let R of this.routes){if(R.method!==a)continue;let w=d.match(R.pattern);if(w){p=R,f={},R.paramNames.forEach((I,A)=>{f[I]=decodeURIComponent(w[A+1]??"");});break}}let m=Object.assign(n,{params:f}),O=p?p.handler:this.notFoundHandler;try{await this.runMiddlewareChain(m,o,O);}catch(R){this.errorHandler(R,n,o);}}async runMiddlewareChain(n,o,a){let d=0,p=async()=>{if(d<this.middlewares.length){let f=this.middlewares[d++];await f(n,o,p);}else await a(n,o);};await p();}};function Z(t,n,o=200){t.status(o).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(n));}function F(t,n,o,a=200){Z(t,{success:true,data:n,meta:o},a);}function C(t,n,o=400){Z(t,{success:false,error:n},o);}var U="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";function ee(){let t="";for(let n=0;n<20;n++)t+=U.charAt(Math.floor(Math.random()*U.length));return t}function te(t,n,o=[]){let a=t.shape,d={},p=n&&n.length>0?n:Object.keys(a);for(let f of p){if(o.includes(f))continue;let m=f.split(".")[0];m&&a[m]&&(d[m]=a[m]);}return zod.z.object(d)}function G(t,n,o,a=false,d=[]){try{let p=te(t,o,d);return {success:!0,data:(a?p.partial():p).parse(n)}}catch(p){return p instanceof zod.z.ZodError?{success:false,error:`Validation failed: ${p.issues.map(m=>`${m.path.join(".")}: ${m.message}`).join(", ")}`}:{success:false,error:"Validation failed"}}}function ne(t,n){let o=[],a=n?new Set(n):null,d={eq:"==",ne:"!=",lt:"<",lte:"<=",gt:">",gte:">=",in:"in",nin:"not-in",contains:"array-contains",containsAny:"array-contains-any"};for(let[p,f]of Object.entries(t)){if(f===void 0||["cursor","limit","pageSize","orderBy","orderDir","select"].includes(p))continue;let m=Array.isArray(f)?f[0]:f;if(m===void 0||m==="")continue;let O=p.match(/^(\w+)__(\w+)$/),R,w="==";if(O&&O[1]&&O[2]){R=O[1];let A=O[2];if(d[A])w=d[A];else continue}else if(!O)R=p;else continue;if(a&&!a.has(R))continue;let I=m;w==="in"||w==="not-in"||w==="array-contains-any"?I=m.split(",").map(A=>M(A.trim())):I=M(m),o.push({field:R,op:w,value:I});}return o}function M(t){if(t==="true")return true;if(t==="false")return false;if(t==="null")return null;let n=Number(t);return !isNaN(n)&&t!==""?n:t}function z(t){return t?{docId:t.id}:null}async function L(t,n){if(!n||typeof n!="object")return;let o=n.docId;if(typeof o=="string")try{let a=t.repo.ref;if(typeof a.doc!="function")return;let d=await a.doc(o).get();return d.exists?d:void 0}catch{return}}function V(t,n,o){function a(l,i){return !l||!t[l]?(C(i,`Repository "${l}" not found`,404),null):t[l]}function d(l,i){if(!i)return;let u=l[i];if(typeof u!="string"||!u)return;let s=u.split("/").filter(Boolean),e=[];for(let r=1;r<s.length;r+=2)e.push(s[r]);return e.length>0?e:void 0}async function p(l,i){let u=`by${l.documentKey.charAt(0).toUpperCase()}${l.documentKey.slice(1)}`,s=l.repo.get[u];if(typeof s=="function")try{let r=await s(i);if(r)return r}catch{}return (await l.repo.query.by({where:[[l.documentKey,"==",i]],limit:1}))[0]??null}async function f(l,i){let u=l.params||{},s=a(u.repoName,i);if(s)try{let e=l.query??{},r=Math.min(Number(e.pageSize)||s.pageSize,100),y=e.cursor,c=e.direction?.toLowerCase()==="prev"?"prev":"next",g=e.orderBy,P=e.orderDir?.toLowerCase()==="desc"?"desc":"asc",v=e.select,h=v?v.split(",").map(D=>D.trim()):void 0,b;s.allowedIncludes&&e.includes&&(b=(typeof e.includes=="string"?e.includes.split(",").map(T=>T.trim()):Array.isArray(e.includes)?e.includes:[]).filter(T=>typeof T=="string"&&s.allowedIncludes.includes(T)),b?.length===0&&(b=void 0));let j=ne(e,s.filterableFields),x={pageSize:r,direction:c};if(y)try{let D=typeof y=="string"?JSON.parse(y):y;x.cursor=await L(s,D);}catch{}g&&(x.orderBy=[{field:g,direction:P}]),j.length>0&&(x.where=j.map(D=>[D.field,D.op,D.value])),h&&(x.select=h),b&&(x.include=b);let S=await s.repo.query.paginate(x),K={items:S.data,hasNextPage:S.hasNextPage,hasPrevPage:S.hasPrevPage,nextCursor:z(S.nextCursor),prevCursor:z(S.prevCursor)};F(i,K,{pageSize:r,hasMore:S.hasNextPage});}catch(e){let r=o&&e instanceof Error?e.message:"Failed to fetch documents";C(i,r,500);}}async function m(l,i){let u=l.params||{},s=a(u.repoName,i);if(s)try{let e=l.body??{},r=Math.min(e.pageSize||s.pageSize,100),y=e.direction==="prev"?"prev":"next",c={pageSize:r,direction:y};if(e.cursor)try{let v=typeof e.cursor=="string"?JSON.parse(e.cursor):e.cursor;c.cursor=await L(s,v);}catch{}if(s.allowedIncludes&&e.includes&&e.includes.length>0){let v=e.includes.filter(h=>typeof h=="string"?s.allowedIncludes.includes(h):typeof h=="object"&&h!==null&&"relation"in h&&typeof h.relation=="string"?s.allowedIncludes.includes(h.relation):!1);v.length>0&&(c.include=v);}if(e.where&&e.where.length>0){if(s.filterableFields){let v=new Set(s.filterableFields),h=e.where.filter(b=>!v.has(b[0]));if(h.length>0){C(i,`Fields not filterable: ${h.map(b=>b[0]).join(", ")}`,400);return}}c.where=e.where;}if(e.orWhere&&e.orWhere.length>0){if(s.filterableFields){let v=new Set(s.filterableFields),h=e.orWhere.filter(b=>!v.has(b[0]));if(h.length>0){C(i,`Fields not filterable: ${h.map(b=>b[0]).join(", ")}`,400);return}}c.orWhere=e.orWhere;}if(e.orWhereGroups&&e.orWhereGroups.length>0){if(s.filterableFields){let v=new Set(s.filterableFields);for(let h of e.orWhereGroups){let b=h.filter(j=>!v.has(j[0]));if(b.length>0){C(i,`Fields not filterable: ${b.map(j=>j[0]).join(", ")}`,400);return}}}c.orWhereGroups=e.orWhereGroups;}e.orderBy&&e.orderBy.length>0&&(c.orderBy=e.orderBy),e.select&&e.select.length>0&&(c.select=e.select);let g=await s.repo.query.paginate(c),P={items:g.data,hasNextPage:g.hasNextPage,hasPrevPage:g.hasPrevPage,nextCursor:z(g.nextCursor),prevCursor:z(g.prevCursor)};F(i,P,{pageSize:r,hasMore:g.hasNextPage});}catch(e){let r=o&&e instanceof Error?e.message:"Failed to query documents";C(i,r,500);}}async function O(l,i){let u=l.params||{},s=a(u.repoName,i);if(!s)return;let e=u.id;if(!e){C(i,"Document ID required",400);return}try{let r=await p(s,e);if(!r){C(i,"Document not found",404);return}F(i,r);}catch(r){let y=o&&r instanceof Error?r.message:"Failed to fetch document";C(i,y,500);}}async function R(l,i){let u=l.params||{},s=a(u.repoName,i);if(s)try{let e=l.body??{},r=G(s.schema,e,s.createFields,!1,s.systemKeys);if(!r.success){C(i,r.error,400);return}if(s.validate){let c=await s.validate(r.data,"create");if(c){C(i,c,400);return}}let y;if(s.isGroup&&s.parentKeys&&s.parentKeys.length>0){let c={...r.data};s.createdKey&&(c[s.createdKey]=new Date);let g=s.parentKeys.filter(h=>!c[h]);if(g.length>0){C(i,`Missing parent key(s) for subcollection create: ${g.join(", ")}`,400);return}let P=s.parentKeys.map(h=>c[h]),v=c[s.documentKey]||ee();y=await s.repo.set(...P,v,c);}else y=await s.repo.create(r.data);F(i,y,void 0,201);}catch(e){let r=o&&e instanceof Error?e.message:"Failed to create document";C(i,r,500);}}async function w(l,i,u){let s=l.params||{},e=a(s.repoName,i);if(!e)return;let r=s.id;if(!r){C(i,"Document ID required",400);return}try{let y=l.body??{},c=G(e.schema,y,e.mutableFields,u,e.systemKeys);if(!c.success){C(i,c.error,400);return}if(e.validate){let h=await e.validate(c.data,"update");if(h){C(i,h,400);return}}let g=await p(e,r),P=(g&&d(g,e.pathKey))??[r],v=await e.repo.update(...P,c.data);F(i,v);}catch(y){let c=o&&y instanceof Error?y.message:"Failed to update document";C(i,c,500);}}async function I(l,i){let u=l.params||{},s=a(u.repoName,i);if(!s)return;if(!s.allowDelete){C(i,"Delete not allowed for this repository",403);return}let e=u.id;if(!e){C(i,"Document ID required",400);return}try{let r=await p(s,e),y=(r&&d(r,s.pathKey))??[e];await s.repo.delete(...y),F(i,{deleted:!0});}catch(r){let y=o&&r instanceof Error?r.message:"Failed to delete document";C(i,y,500);}}function A(l,i){i.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:f,handleQuery:m,handleGet:O,handleCreate:R,handleUpdate:w,handleDelete:I,handleOptions:A}}function _(t){try{return zod.z.toJSONSchema(t,{target:"openapi-3.1"})}catch{return {type:"object"}}}function q(t){return {$ref:`#/components/schemas/${t}`}}function $(t){return {description:t,content:{"application/json":{schema:q("ErrorResponse")}}}}function N(t,n){return {description:t,content:{"application/json":{schema:{type:"object",properties:{success:{type:"boolean",enum:[true]},data:n},required:["success","data"]}}}}}function Q(t){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:t},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 re(t){return [{name:"pageSize",in:"query",schema:{type:"integer",default:t.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 se(t){let n=t.filterableFields??Object.keys(t.schema.shape),o=["eq","ne","lt","lte","gt","gte","in","nin","contains"],a=[];for(let d of n){a.push({name:d,in:"query",schema:{type:"string"},description:`Filter by ${d} (equality)`});for(let p of o)a.push({name:`${d}__${p}`,in:"query",schema:{type:"string"},description:`Filter ${d} with operator ${p}`});}return a}function oe(){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 ie(t,n,o,a,d){let p={},f=t.name,m=`${n}/${t.name}`,O=`${m}/{${t.documentKey}}`,R={name:t.documentKey,in:"path",required:true,schema:{type:"string"},description:"Unique document identifier"};p[m]={get:{operationId:`list${E(t.name)}`,summary:`List ${t.name} (paginated)`,tags:[f],parameters:[...re(t),...se(t)],responses:{200:Q(q(o)),500:$("Internal server error")}},post:{operationId:`create${E(t.name)}`,summary:`Create a ${k(t.name)}`,tags:[f],requestBody:{required:true,content:{"application/json":{schema:q(a??o)}}},responses:{201:N("Document created",q(o)),400:$("Validation error"),500:$("Internal server error")}}},p[`${m}/query`]={post:{operationId:`query${E(t.name)}`,summary:`Query ${t.name} with advanced filters`,tags:[f],requestBody:{required:true,content:{"application/json":{schema:q("QueryRequestBody")}}},responses:{200:Q(q(o)),400:$("Invalid query"),500:$("Internal server error")}}};let w={};return w.get={operationId:`get${E(k(t.name))}`,summary:`Get a single ${k(t.name)}`,tags:[f],parameters:[R],responses:{200:N("Document found",q(o)),404:$("Document not found"),500:$("Internal server error")}},w.put={operationId:`update${E(k(t.name))}`,summary:`Update a ${k(t.name)} (full replace)`,tags:[f],parameters:[R],requestBody:{required:true,content:{"application/json":{schema:q(d??o)}}},responses:{200:N("Document updated",q(o)),400:$("Validation error"),404:$("Document not found"),500:$("Internal server error")}},w.patch={operationId:`patch${E(k(t.name))}`,summary:`Partially update a ${k(t.name)}`,tags:[f],parameters:[R],requestBody:{required:true,content:{"application/json":{schema:{allOf:[q(d??o)],description:"All fields are optional for partial updates"}}}},responses:{200:N("Document patched",q(o)),400:$("Validation error"),404:$("Document not found"),500:$("Internal server error")}},t.allowDelete&&(w.delete={operationId:`delete${E(k(t.name))}`,summary:`Delete a ${k(t.name)}`,tags:[f],parameters:[R],responses:{200:N("Document deleted",{type:"object",properties:{id:{type:"string"}}}),404:$("Document not found"),500:$("Internal server error")}}),p[O]=w,p}function W(t,n,o={}){let{title:a="CRUD API",version:d="1.0.0",description:p,servers:f,auth:m=false}=o,O=n==="/"?"":n.replace(/\/$/,""),R={},w={},I=[];R.ErrorResponse={type:"object",properties:{success:{type:"boolean",enum:[false]},error:{type:"string"}},required:["success","error"]},R.QueryRequestBody=oe();for(let[u,s]of Object.entries(t)){let e=E(k(u)),r=`${e}Create`,y=`${e}Update`;R[e]=_(s.schema);let c=j=>{let x=j&&j.length>0?j:Object.keys(s.schema.shape),S={};for(let K of x){let D=K.split(".")[0];D&&s.schema.shape[D]&&!s.systemKeys.includes(D)&&(S[D]=s.schema.shape[D]);}return S},g=null,P=c(s.createFields);Object.keys(P).length>0&&(R[r]=_(zod.z.object(P)),g=r);let v=null,h=c(s.mutableFields);Object.keys(h).length>0&&(R[y]=_(zod.z.object(h)),v=y);let b=ie(s,O,e,g,v);Object.assign(w,b),I.push({name:u,description:`Operations on ${u} (collection: ${s.path})`});}let A={},l;return m==="basic"?(A.basicAuth={type:"http",scheme:"basic"},l=[{basicAuth:[]}]):m==="bearer"&&(A.bearerAuth={type:"http",scheme:"bearer",bearerFormat:"JWT"},l=[{bearerAuth:[]}]),{openapi:"3.1.0",info:{title:a,version:d,...p?{description:p}:{}},...f&&f.length>0?{servers:f}:{},paths:w,components:{schemas:R,...Object.keys(A).length>0?{securitySchemes:A}:{}},...l?{security:l}:{},tags:I}}function E(t){return t.charAt(0).toUpperCase()+t.slice(1)}function k(t){return t.endsWith("ies")?t.slice(0,-3)+"y":t.endsWith("ses")||t.endsWith("xes")||t.endsWith("zes")?t.slice(0,-2):t.endsWith("s")&&!t.endsWith("ss")?t.slice(0,-1):t}function ae(t,n){return `<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />
@@ -9,5 +9,5 @@
9
9
  <script id="api-reference" data-url="${n}"></script>
10
10
  <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
11
11
  </body>
12
- </html>`}function ce(t){let n=t==="/"?"":t.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let o=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",c=process.env.FUNCTION_REGION??"us-central1",d=process.env.FUNCTION_TARGET??"";return `/${o}/${c}/${d}${n}`}return n}async function de(t){return typeof t.rawBody=="string"?t.rawBody:Buffer.isBuffer(t.rawBody)?t.rawBody.toString("utf8"):""}function Re(t){let{basePath:n="/",repos:o,parseBody:c=true,auth:d,middleware:l=[],verbose:f=false,httpsOptions:R}=t,O=n==="/"?"":n.replace(/\/$/,""),h={};for(let[e,r]of Object.entries(o)){let y=r.schema??r.repo.schema??null;if(!y)throw new Error(`[createCrudServer] Repository "${e}" has no Zod schema. Either use createRepositoryConfig(schema)(config) or pass schema: explicitly.`);let a,g,P;if(r.fieldsConfig){let b=r.fieldsConfig;a=[],g=[],P=[];for(let[j,x]of Object.entries(b))for(let q of x)q==="filterable"?a.push(j):q==="mutable"?g.push(j):q==="create"&&P.push(j);a.length===0&&(a=void 0),g.length===0&&(g=void 0),P.length===0&&(P=void 0);}let v=(()=>{let b=r.repo._parentKeys;return b&&b.length>0?b:void 0})();if(v&&P)for(let b of v)P.includes(b)||P.push(b);let m={name:e,path:r.path,repo:r.repo,schema:y,systemKeys:r.repo._systemKeys??[r.documentKey??"docId"],documentKey:r.documentKey??"docId",pathKey:r.repo._pathKey??void 0,isGroup:!!r.repo._isGroup,parentKeys:v,createdKey:r.repo._createdKey??void 0,pageSize:r.pageSize??25,filterableFields:a,mutableFields:g,createFields:P,allowDelete:r.allowDelete??false,allowedIncludes:r.allowedIncludes,validate:r.validate};h[e]=m;}let w=Q(h,O,f),I=t.openapi,A=I&&typeof I=="object"?I:{},p=null;function i(){if(!p){let e=d&&typeof d!="function"?"basic":d?"bearer":false;p=W(h,O,{...A,auth:A.auth??e});}return p}let u=new B;if(u.use((e,r,y)=>{r.set("Access-Control-Allow-Origin","*"),r.set("Access-Control-Allow-Credentials","true"),y();}),c&&u.use(async(e,r,y)=>{let a=e;if(String(a.headers?.["content-type"]??"").includes("application/json")){if(typeof a.body=="string")try{e.body=JSON.parse(a.body);}catch{}else if(Buffer.isBuffer(e.rawBody))try{let P=await de(a);e.body=JSON.parse(P);}catch{}}await y();}),d)if(typeof d=="function")u.use(d);else {let e=d.realm??"API",r="Basic "+Buffer.from(`${d.username}:${d.password}`).toString("base64");u.use((y,a,g)=>{if((y.headers?.authorization??"")!==r){a.status(401).set("WWW-Authenticate",`Basic realm="${e}"`).set("Content-Type","application/json").send(JSON.stringify({success:false,error:"Unauthorized"}));return}g();});}for(let e of l)u.use(e);if(I!==false){let e=`${O}/__spec.json`,r=`${O}/__docs`;u.get(e,(y,a)=>{let g=i();a.status(200).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(g,null,2));}),u.get(r,(y,a)=>{let g=ce(O)+"/__spec.json",P=ae(A.title??"CRUD API",g);a.status(200).set("Content-Type","text/html; charset=utf-8").send(P);});}u.use((e,r,y)=>{if(e.method==="OPTIONS"){w.handleOptions(e,r);return}y();}),u.get(`${O}/:repoName`,w.handleList),u.post(`${O}/:repoName/query`,w.handleQuery),u.get(`${O}/:repoName/:id`,w.handleGet),u.post(`${O}/:repoName`,w.handleCreate),u.put(`${O}/:repoName/:id`,(e,r)=>w.handleUpdate(e,r,false)),u.patch(`${O}/:repoName/:id`,(e,r)=>w.handleUpdate(e,r,true)),u.delete(`${O}/:repoName/:id`,w.handleDelete);let s=async(e,r)=>{await u.handle(e,r);};return s.spec=i,R&&(s.httpsOptions=R),s}exports.createCrudServer=Re;exports.generateOpenAPISpec=W;//# sourceMappingURL=index.cjs.map
12
+ </html>`}function ce(t,n){let o=n==="/"?"":n.replace(/\/$/,"");if(process.env.FUNCTIONS_EMULATOR==="true"){let p=process.env.GCLOUD_PROJECT??process.env.GOOGLE_CLOUD_PROJECT??"demo-project",f=process.env.FUNCTION_REGION??"us-central1",m=process.env.FUNCTION_TARGET??"";return `/${p}/${f}/${m}${o}`}let a=process.env.K_SERVICE,d=t?.hostname??t?.headers?.host??"";return a&&d.includes("cloudfunctions.net")?`/${a.toLowerCase()}${o}`:o}async function de(t){return typeof t.rawBody=="string"?t.rawBody:Buffer.isBuffer(t.rawBody)?t.rawBody.toString("utf8"):""}function Re(t){let{basePath:n="/",repos:o,parseBody:a=true,auth:d,middleware:p=[],verbose:f=false,httpsOptions:m}=t,O=n==="/"?"":n.replace(/\/$/,""),R={};for(let[e,r]of Object.entries(o)){let y=r.schema??r.repo.schema??null;if(!y)throw new Error(`[createCrudServer] Repository "${e}" has no Zod schema. Either use createRepositoryConfig(schema)(config) or pass schema: explicitly.`);let c,g,P;if(r.fieldsConfig){let b=r.fieldsConfig;c=[],g=[],P=[];for(let[j,x]of Object.entries(b))for(let S of x)S==="filterable"?c.push(j):S==="mutable"?g.push(j):S==="create"&&P.push(j);c.length===0&&(c=void 0),g.length===0&&(g=void 0),P.length===0&&(P=void 0);}let v=(()=>{let b=r.repo._parentKeys;return b&&b.length>0?b:void 0})();if(v&&P)for(let b of v)P.includes(b)||P.push(b);let h={name:e,path:r.path,repo:r.repo,schema:y,systemKeys:r.repo._systemKeys??[r.documentKey??"docId"],documentKey:r.documentKey??"docId",pathKey:r.repo._pathKey??void 0,isGroup:!!r.repo._isGroup,parentKeys:v,createdKey:r.repo._createdKey??void 0,pageSize:r.pageSize??25,filterableFields:c,mutableFields:g,createFields:P,allowDelete:r.allowDelete??false,allowedIncludes:r.allowedIncludes,validate:r.validate};R[e]=h;}let w=V(R,O,f),I=t.openapi,A=I&&typeof I=="object"?I:{},l=null;function i(){if(!l){let e=d&&typeof d!="function"?"basic":d?"bearer":false;l=W(R,O,{...A,auth:A.auth??e});}return l}let u=new B;if(u.use((e,r,y)=>{r.set("Access-Control-Allow-Origin","*"),r.set("Access-Control-Allow-Credentials","true"),y();}),a&&u.use(async(e,r,y)=>{let c=e;if(String(c.headers?.["content-type"]??"").includes("application/json")){if(typeof c.body=="string")try{e.body=JSON.parse(c.body);}catch{}else if(Buffer.isBuffer(e.rawBody))try{let P=await de(c);e.body=JSON.parse(P);}catch{}}await y();}),d)if(typeof d=="function")u.use(d);else {let e=d.realm??"API",r="Basic "+Buffer.from(`${d.username}:${d.password}`).toString("base64");u.use((y,c,g)=>{if((y.headers?.authorization??"")!==r){c.status(401).set("WWW-Authenticate",`Basic realm="${e}"`).set("Content-Type","application/json").send(JSON.stringify({success:false,error:"Unauthorized"}));return}g();});}for(let e of p)u.use(e);if(I!==false){let e=`${O}/__spec.json`,r=`${O}/__docs`;u.get(e,(y,c)=>{let g=i();c.status(200).set("Content-Type","application/json; charset=utf-8").send(JSON.stringify(g,null,2));}),u.get(r,(y,c)=>{let g=ce(y,O)+"/__spec.json",P=ae(A.title??"CRUD API",g);c.status(200).set("Content-Type","text/html; charset=utf-8").send(P);});}u.use((e,r,y)=>{if(e.method==="OPTIONS"){w.handleOptions(e,r);return}y();}),u.get(`${O}/:repoName`,w.handleList),u.post(`${O}/:repoName/query`,w.handleQuery),u.get(`${O}/:repoName/:id`,w.handleGet),u.post(`${O}/:repoName`,w.handleCreate),u.put(`${O}/:repoName/:id`,(e,r)=>w.handleUpdate(e,r,false)),u.patch(`${O}/:repoName/:id`,(e,r)=>w.handleUpdate(e,r,true)),u.delete(`${O}/:repoName/:id`,w.handleDelete);let s=async(e,r)=>{await u.handle(e,r);};return s.spec=i,m&&(s.httpsOptions=m),s}exports.createCrudServer=Re;exports.generateOpenAPISpec=W;//# sourceMappingURL=index.cjs.map
13
13
  //# sourceMappingURL=index.cjs.map