@stacksjs/api 0.70.367 → 0.70.369
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generate-openapi.d.ts +33 -1
- package/dist/index.js +10 -10
- package/package.json +2 -2
|
@@ -12,6 +12,24 @@ import type { SchemaObject } from './generate-types';
|
|
|
12
12
|
export declare function ruleToSchema(rule: unknown): Record<string, unknown>;
|
|
13
13
|
/** Whether a rule says the field must be present. */
|
|
14
14
|
export declare function ruleIsRequired(rule: unknown): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The answers an operation documents: the defaults, plus whatever the action
|
|
17
|
+
* says about itself.
|
|
18
|
+
*
|
|
19
|
+
* **Merged over the defaults rather than replacing them.** An action that
|
|
20
|
+
* documents its 200 and its 404 still answers 422 for a bad request and 500
|
|
21
|
+
* when something breaks, and a document that drops those because the author
|
|
22
|
+
* wrote down two is less accurate than one that never let them write anything.
|
|
23
|
+
*
|
|
24
|
+
* A row without a `description` is ignored. A status with no sentence beside it
|
|
25
|
+
* is one a reader skims past, and emitting it makes the document longer without
|
|
26
|
+
* making it more useful.
|
|
27
|
+
*
|
|
28
|
+
* Headers apply to every answer, which is what a header on a response *is*:
|
|
29
|
+
* rate-limit headers ride on the 200 and on the 429 alike, and a client reading
|
|
30
|
+
* them only on success backs off exactly when it should not.
|
|
31
|
+
*/
|
|
32
|
+
export declare function describedResponses(action: Record<string, unknown> | null, base: ResponseMap): ResponseMap;
|
|
15
33
|
/**
|
|
16
34
|
* Build an OpenAPI 3.0 spec from the live route registry.
|
|
17
35
|
*
|
|
@@ -48,7 +66,11 @@ declare interface OpenApiPathItem {
|
|
|
48
66
|
summary?: string
|
|
49
67
|
operationId?: string
|
|
50
68
|
parameters?: Array<{ name: string, in: string, required: boolean, schema: SchemaObject }>
|
|
51
|
-
responses: Record<string, {
|
|
69
|
+
responses: Record<string, {
|
|
70
|
+
description: string
|
|
71
|
+
content?: Record<string, { schema?: SchemaObject }>
|
|
72
|
+
headers?: Record<string, { description: string, schema?: SchemaObject }>
|
|
73
|
+
}>
|
|
52
74
|
requestBody?: { content: Record<string, { schema?: SchemaObject }>, required?: boolean }
|
|
53
75
|
}
|
|
54
76
|
}
|
|
@@ -58,3 +80,13 @@ declare interface OpenApiSpec {
|
|
|
58
80
|
paths: Record<string, OpenApiPathItem>
|
|
59
81
|
components: { schemas: Record<string, SchemaObject> }
|
|
60
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Try to resolve an action's validations object given its handler
|
|
85
|
+
* path string (e.g. 'Actions/CreatePostAction'). Returns `null` on
|
|
86
|
+
* any resolution failure so generation never crashes the spec build.
|
|
87
|
+
*/
|
|
88
|
+
declare type ResponseMap = Record<string, {
|
|
89
|
+
description: string
|
|
90
|
+
content?: Record<string, { schema?: SchemaObject }>
|
|
91
|
+
headers?: Record<string, { description: string, schema?: SchemaObject }>
|
|
92
|
+
}>;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var XJ=Object.defineProperty;var YJ=($)=>$;function xJ($,J){this[$]=YJ.bind(null,J)}var x$=($,J)=>{for(var O in J)XJ($,O,{get:J[O],enumerable:!0,configurable:!0,set:xJ.bind(J,O)})};var
|
|
3
|
-
${["query","header","path","cookie"].map((O)=>{let G=$.filter((z)=>z.in===O);if(!G.length)return` ${O}?: never`;let Z=G.map((z)=>`${JSON.stringify(z.name)}${z.required?"":"?"}: ${
|
|
2
|
+
var XJ=Object.defineProperty;var YJ=($)=>$;function xJ($,J){this[$]=YJ.bind(null,J)}var x$=($,J)=>{for(var O in J)XJ($,O,{get:J[O],enumerable:!0,configurable:!0,set:xJ.bind(J,O)})};var s=($,J)=>()=>($&&(J=$($=0)),J);var l=import.meta.require;var R$={};x$(R$,{schemaType:()=>c,renderOpenApiTypes:()=>_J});function TJ($){return typeof $==="string"?JSON.stringify($):String($)}function c($){if(!$)return"unknown";if($.enum?.length)return $.enum.map(TJ).join(" | ");if($.type==="string")return"string";if($.type==="number"||$.type==="integer")return"number";if($.type==="boolean")return"boolean";if($.type==="null")return"null";if($.type==="array")return`Array<${c($.items)}>`;if($.type==="object"||$.properties||$.additionalProperties){let J=new Set($.required||[]),O=Object.entries($.properties||{}).map(([G,Z])=>`${JSON.stringify(G)}${J.has(G)?"":"?"}: ${c(Z)}`);if($.additionalProperties){let G=$.additionalProperties===!0?"unknown":c($.additionalProperties);O.push(`[key: string]: ${G}`)}return O.length?`{ ${O.join("; ")} }`:"Record<string, unknown>"}return"unknown"}function jJ($=[]){return` parameters: {
|
|
3
|
+
${["query","header","path","cookie"].map((O)=>{let G=$.filter((z)=>z.in===O);if(!G.length)return` ${O}?: never`;let Z=G.map((z)=>`${JSON.stringify(z.name)}${z.required?"":"?"}: ${c(z.schema)}`);return` ${O}${G.every((z)=>!z.required)?"?":""}: { ${Z.join("; ")} }`}).join(`
|
|
4
4
|
`)}
|
|
5
|
-
}`}function k$($){if(!$||!Object.keys($).length)return"never";return`{ ${Object.entries($).map(([J,O])=>`${JSON.stringify(J)}: ${
|
|
5
|
+
}`}function k$($){if(!$||!Object.keys($).length)return"never";return`{ ${Object.entries($).map(([J,O])=>`${JSON.stringify(J)}: ${c(O.schema)}`).join("; ")} }`}function AJ($){let J=$.requestBody?`
|
|
6
6
|
requestBody${$.requestBody.required?"":"?"}: { content: ${k$($.requestBody.content)} }`:`
|
|
7
7
|
requestBody?: never`,O=Object.entries($.responses||{}).map(([G,Z])=>` ${JSON.stringify(G)}: { content: ${k$(Z.content)} }`);return`{
|
|
8
8
|
${jJ($.parameters)}${J}
|
|
@@ -10,10 +10,10 @@ ${jJ($.parameters)}${J}
|
|
|
10
10
|
${O.join(`
|
|
11
11
|
`)}
|
|
12
12
|
}
|
|
13
|
-
}`}function _J($){let J=Object.entries($.paths||{}).map(([G,Z])=>{let z=BJ.map((K)=>{let
|
|
13
|
+
}`}function _J($){let J=Object.entries($.paths||{}).map(([G,Z])=>{let z=BJ.map((K)=>{let X=Z[K];return X?` ${K}: ${AJ(X)}`:` ${K}?: never`});return` ${JSON.stringify(G)}: {
|
|
14
14
|
${z.join(`
|
|
15
15
|
`)}
|
|
16
|
-
}`}),O=Object.entries($.components?.schemas||{}).map(([G,Z])=>` ${JSON.stringify(G)}: ${
|
|
16
|
+
}`}),O=Object.entries($.components?.schemas||{}).map(([G,Z])=>` ${JSON.stringify(G)}: ${c(Z)}`);return`/**
|
|
17
17
|
* Generated from storage/framework/api/openapi.json by @stacksjs/api.
|
|
18
18
|
* Do not edit this file directly; run bun run docs:artifacts to regenerate it.
|
|
19
19
|
*/
|
|
@@ -29,13 +29,13 @@ ${O.join(`
|
|
|
29
29
|
`)}
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
`}var BJ;var z$=
|
|
32
|
+
`}var BJ;var z$=s(()=>{BJ=["get","put","post","delete","options","head","patch","trace"]});var f$={};x$(f$,{renderApiClient:()=>DJ,methodName:()=>P$});function P$($){let J=$.replace(/[{}]/g,"").split(/[^a-z0-9]+/i).filter(Boolean),O=J[0]?.toLowerCase()==="api"?J.slice(1):J[1]?.toLowerCase()==="api"?[J[0],...J.slice(2)]:J,[G,...Z]=O;if(!G)return"call";let z=G.charAt(0).toLowerCase()+G.slice(1),K=Z.map((Q)=>Q.charAt(0).toUpperCase()+Q.slice(1)),X=[z,...K].join("");return/^[a-z_$]/i.test(X)?X:`call${X.charAt(0).toUpperCase()}${X.slice(1)}`}function HJ($){let J=$.responses??{},O=Object.keys(J).find((z)=>z.startsWith("2"));if(!O)return"unknown";let G=J[O]?.content,Z=G?.["application/json"]??Object.values(G??{})[0];return Z?.schema?c(Z.schema):"unknown"}function SJ($,J=" "){let O=$.filter(Boolean);if(!O.length)return"";return`${J}/**
|
|
33
33
|
${O.map((G)=>`${J} * ${G}`).join(`
|
|
34
34
|
`)}
|
|
35
35
|
${J} */
|
|
36
|
-
`}function UJ($,J,O,G){let Z=O.parameters??[],z=Z.filter((
|
|
37
|
-
return request(config, ${JSON.stringify(J.toUpperCase())}, ${JSON.stringify($)}, ${
|
|
38
|
-
},`}function DJ($,J={}){let O=J.name??"API",G=new Map,Z=[];for(let[z,K]of Object.entries($.paths??{}))for(let
|
|
36
|
+
`}function UJ($,J,O,G){let Z=O.parameters??[],z=Z.filter((_)=>_.in==="path"),K=Z.filter((_)=>_.in==="query"),X=O.requestBody?.content?.["application/json"]?.schema,Q=Boolean(O.requestBody?.required),L=[];for(let _ of[...z,...K]){let P=_.in==="path"||_.required;L.push(`${JSON.stringify(_.name)}${P?"":"?"}: ${c(_.schema)}`)}if(X)L.push(`body${Q?"":"?"}: ${c(X)}`);let j=[...z,...K].every((_)=>_.in!=="path"&&!_.required)&&(!X||!Q),S=L.length?`input${j?"?":""}: { ${L.join("; ")} }, `:"",U=K.length?`[${K.map((_)=>JSON.stringify(_.name)).join(", ")}]`:"[]";return`${SJ([O.summary&&O.summary!==$?O.summary:`${J.toUpperCase()} ${$}`,O.description??""])} ${G}(${S}options?: RequestOptions): Promise<ApiResult<${HJ(O)}>> {
|
|
37
|
+
return request(config, ${JSON.stringify(J.toUpperCase())}, ${JSON.stringify($)}, ${L.length?"input ?? {}":"{}"}, ${U}, ${X?"true":"false"}, options)
|
|
38
|
+
},`}function DJ($,J={}){let O=J.name??"API",G=new Map,Z=[];for(let[z,K]of Object.entries($.paths??{}))for(let X of NJ){let Q=K[X];if(!Q)continue;let L=P$(Q.operationId??`${X}_${z}`),j=G.get(L)??0;G.set(L,j+1),Z.push(UJ(z,X,Q,j===0?L:`${L}${j+1}`))}return`/* eslint-disable */
|
|
39
39
|
/**
|
|
40
40
|
* ${O} client, generated from the OpenAPI document.
|
|
41
41
|
*
|
|
@@ -136,4 +136,4 @@ ${Z.join(`
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
export type Client = ReturnType<typeof createClient>
|
|
139
|
-
`}var NJ;var B$=d(()=>{z$();NJ=["get","put","post","delete","options","head","patch"]});function EJ($){let J=$;return J?.code==="SQLITE_CONSTRAINT_UNIQUE"||J?.code==="SQLITE_CONSTRAINT"||J?.code==="23505"||J?.errno===1062||/unique|duplicate/i.test(J?.message??"")}function j$($,J,O){let G=$;if($ instanceof Error&&typeof G.status==="number"&&Number.isInteger(G.status)&&G.status>=400&&G.status<600){let Z={error:$.message};if(G.details!==void 0)Z.details=G.details;return{status:G.status,body:Z}}if(EJ($))return{status:409,body:{error:`${J} already exists`}};return{status:500,body:{error:`Failed to ${O} ${J}`,detail:String($)}}}function R($){return $.replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}function A$($){let J={};for(let[O,G]of Object.entries($))J[R(O)]=G;return J}function y$($){if(!$)return[];let J=Object.entries($.attributes??{}).filter(([,O])=>O?.fillable===!0).map(([O])=>O);for(let O of $.belongsTo??[]){if(typeof O!=="string"||!O.trim())continue;let G=R(O.trim()).split("_").filter(Boolean);if(G.length===0)continue;let Z=`${G[0]}${G.slice(1).map((z)=>`${z[0]?.toUpperCase()}${z.slice(1)}`).join("")}Id`;J.push(Z)}return[...new Set(J)]}function _$($,J){if(!$||J.length===0)return{};let O={};for(let G of J){if(G in $){O[G]=$[G];continue}let Z=R(G);if(Z!==G&&Z in $)O[G]=$[Z]}return O}function IJ($,J){if($?.name!=="date"||J instanceof Date||typeof J!=="string")return J;let O=/^(\d{4})-(\d{2})-(\d{2})$/.exec(J);if(!O)return J;let G=Number(O[1]),Z=Number(O[2]),z=Number(O[3]),K=new Date(Date.UTC(G,Z-1,z));if(K.getUTCFullYear()!==G||K.getUTCMonth()!==Z-1||K.getUTCDate()!==z)return J;return K}function N$($,J){if(!J.length)return $;let O={...$};for(let G of J)delete O[G],delete O[R(G)];return O}function r($,J){if(!$||J.length===0)return $;let O={...$};for(let G of J)delete O[G],delete O[R(G)];return O}function b$($,J){let O=new Map;for(let G of[...Object.keys($??{}),...FJ]){let Z=R(G);if(!/^\w+$/.test(Z))continue;O.set(G,Z),O.set(Z,Z)}for(let G of J)O.delete(G),O.delete(R(G));return O}function q$($,J,O){if(!J)return $;let G=String(J).split(",").map((z)=>z.trim()).filter(Boolean),Z=$;for(let z of G){let K=z.startsWith("-"),W=K?z.slice(1):z;if(!/^\w+$/.test(W))continue;let L=O.get(W);if(!L)continue;Z=Z.orderBy(L,K?"desc":"asc")}return Z}function MJ($){try{return JSON.parse($)}catch{return $}}function CJ($){try{return JSON.parse($)}catch{return[]}}function H$($,J,O){if(!$||typeof $!=="object"||!J||Object.keys(J).length===0)return $;let G={...$};for(let[Z,z]of Object.entries(J)){let K=typeof z==="string"?VJ[z]:z;if(!K||typeof K[O]!=="function")continue;if(Object.prototype.hasOwnProperty.call(G,Z))G[Z]=K[O](G[Z]);let W=R(Z);if(W!==Z&&Object.prototype.hasOwnProperty.call(G,W))G[W]=K[O](G[W])}return G}function S$($,J,O){let G=J?.attributes??{},Z={};for(let[z,K]of Object.entries(G)){let W=K?.validation?.rule;if(!W||typeof W.validate!=="function")continue;let L=Object.prototype.hasOwnProperty.call($,z);if(!L&&O==="updating")continue;let Q=K!==null&&typeof K==="object"&&Object.prototype.hasOwnProperty.call(K,"default"),j=L?$[z]:Q?K.default:void 0,U=IJ(W,j),D=W.validate(U);if(!D?.valid&&Array.isArray(D?.errors)&&D.errors.length>0)Z[z]=D.errors.map((V)=>K?.validation?.message?.[V?.code]??V?.message??"invalid")}return Object.keys(Z).length===0?{valid:!0}:{valid:!1,errors:Z}}function U$($){return $.replace(/\{[^}]*\}/g,"{}").replace(/:[^/]+/g,"{}")}function T$($){if(Array.isArray($))return $.filter((J)=>typeof J==="string"&&J.length>0);return typeof $==="string"&&$?[$]:[]}function c$($){let J=typeof $==="object"&&$!==null&&"middleware"in $,O=$?.middleware;if(!J)return{read:["auth"],write:["auth"],declared:!1};if(O&&typeof O==="object"&&!Array.isArray(O)){let Z=O;return{read:"read"in Z?T$(Z.read):["auth"],write:"write"in Z?T$(Z.write):["auth"],declared:!0}}let G=T$(O);return{read:G,write:G,declared:!0}}function w$($){let J=Number.parseInt($.get("page")||String(1),10),O=Number.isFinite(J)?Math.max(1,J):1,G=Number.parseInt($.get("per_page")||String(g$),10),Z=Math.min(Number.isFinite(G)?Math.max(1,G):g$,kJ);return{page:O,perPage:Z,offset:(O-1)*Z}}function K$($,J){let O=new URL($.toString());return O.searchParams.set("page",String(J)),`${O.pathname}${O.search}`}function Q$($,J,O,G,Z,z){let K=(J-1)*O,W=G===0,L={page:J,per_page:O,from:W?null:K+1,to:W?null:K+G,has_more_pages:Z,prev_page_url:J>1?K$($,J-1):null,next_page_url:Z?K$($,J+1):null};if(z!==void 0&&!Number.isNaN(z)){let Q=Math.max(1,Math.ceil(z/O));L.total=z,L.last_page=Q,L.first_page_url=K$($,1),L.last_page_url=K$($,Q)}return L}function D$($,J,O,G,Z,z){let{page:K,...W}=Q$($,J,O,G,Z,z);return{current_page:K,...W}}var FJ,VJ,g$=15,kJ=100;var v$=d(()=>{FJ=["id","uuid","created_at","updated_at","deleted_at"];VJ={string:{get:($)=>$!=null?String($):null,set:($)=>$!=null?String($):null},number:{get:($)=>$!=null?Number($):null,set:($)=>$!=null?Number($):null},integer:{get:($)=>$!=null?Math.trunc(Number($)):null,set:($)=>$!=null?Math.trunc(Number($)):null},float:{get:($)=>$!=null?Number.parseFloat(String($)):null,set:($)=>$!=null?Number.parseFloat(String($)):null},boolean:{get:($)=>$===1||$==="1"||$===!0||$==="true",set:($)=>$===!0||$===1||$==="1"||$==="true"?1:0},json:{get:($)=>$==null?null:typeof $==="string"?MJ($):$,set:($)=>$==null?null:typeof $==="string"?$:JSON.stringify($)},datetime:{get:($)=>$?new Date($):null,set:($)=>$ instanceof Date?$.toISOString():$},date:{get:($)=>$?new Date($):null,set:($)=>$ instanceof Date?$.toISOString().split("T")[0]:$},array:{get:($)=>$==null?[]:Array.isArray($)?$:typeof $==="string"?CJ($):[],set:($)=>$==null?null:Array.isArray($)?JSON.stringify($):$}}});import{readdirSync as RJ}from"fs";import{basename as PJ,extname as p$,join as fJ}from"path";function gJ($){let J=[],O=(G)=>{let Z;try{Z=RJ(G,{withFileTypes:!0})}catch{return}for(let z of Z){let K=fJ(G,z.name);if(z.isDirectory()){O(K);continue}if(![".ts",".js"].includes(p$(z.name)))continue;if(z.name.startsWith(".")||z.name.startsWith("index"))continue;J.push(K)}};return O($),J.sort()}async function h$($,J,O){for(let G of gJ($))try{let Z=p$(G),z=await import(`${G}?t=${Date.now()}`),K=z.default??z,W=K.name??PJ(G,Z);J[W]={...K,name:W}}catch(Z){O?.(G,Z)}}async function m$($){let J={};return await h$($.defaultsRoot,J,$.onImportError),await h$($.userRoot,J,$.onImportError),J}var i$=()=>{};import{route as m}from"@stacksjs/router";import{env as l}from"@stacksjs/env";import{projectPath as r$,storagePath as yJ}from"@stacksjs/path";import{createQueryBuilder as bJ,defaultConfig as n$,setConfig as u$}from"@stacksjs/query-builder";import{HttpError as n}from"@stacksjs/error-handling";import{log as X$}from"@stacksjs/logging";function s($,J){let O=U$(J);return m.routes.some((G)=>G.method===$&&U$(String(G.path??""))===O)}function a$($){if(!$.attributes)return[];return Object.entries($.attributes).filter(([J,O])=>O.hidden===!0).map(([J])=>J)}function o$($){if($.endsWith("y")&&!/[aeiou]y$/i.test($))return`${$.slice(0,-1)}ies`;if(/(?:s|x|z|ch|sh)$/i.test($))return`${$}es`;return`${$}s`}async function l$($,J,O,G){if(!$.length)return $;let Z=O.split(",").map((Q)=>Q.trim()).filter(Boolean);if(!Z.length)return $;let z=Array.isArray(J.belongsTo)?J.belongsTo:[],K=Array.isArray(J.hasMany)?J.hasMany:[],W=Array.isArray(J.hasOne)?J.hasOne:[],L=new Map;for(let Q of z)L.set(R(Q),{kind:"belongsTo",modelName:Q});for(let Q of W)L.set(R(Q),{kind:"hasOne",modelName:Q});for(let Q of K)L.set(o$(R(Q)),{kind:"hasMany",modelName:Q});for(let Q of Z){let j=L.get(Q);if(!j)continue;let U=G[j.modelName];if(!U)continue;let D=U.table||o$(R(j.modelName)),V=a$(U),N=(y)=>r(O$(y,U),V);if(j.kind==="belongsTo"||j.kind==="hasOne"){let y=`${R(j.modelName)}_id`,I=[...new Set($.map((H)=>H[y]).filter((H)=>H!=null))];if(!I.length){for(let H of $)H[Q]=null;continue}let q=await b.selectFrom(D).whereIn("id",I).get(),C=new Map;for(let H of q??[])C.set(String(H.id),N(H));for(let H of $)H[Q]=C.get(String(H[y]))??null}else{let y=String(J.name??""),I=`${R(y)}_id`,q=[...new Set($.map((Y)=>Y.id).filter((Y)=>Y!=null))];if(!q.length){for(let Y of $)Y[Q]=[];continue}let C=await b.selectFrom(D).whereIn(I,q).get(),H=new Map;for(let Y of C??[]){let X=String(Y[I]),x=H.get(X)??[];x.push(N(Y)),H.set(X,x)}for(let Y of $)Y[Q]=H.get(String(Y.id))??[]}}return $}async function s$($,J){let O=J?.set;if(!O||typeof O!=="object")return $;let G={...$};for(let[Z,z]of Object.entries(O)){if(typeof z!=="function"||!(Z in G))continue;try{G[Z]=await z(G)}catch{}}return G}function t$($,J){return H$($,J?.casts,"set")}function O$($,J){return H$($,J?.casts,"get")}function B($,J=200){return new Response(JSON.stringify($),{status:J,headers:{"Content-Type":"application/json"}})}async function I$($){if(Number($.headers?.get?.("content-length")??0)>L$)throw new n(413,`Request body exceeds ${L$}-byte limit`);if($.jsonBody&&typeof $.jsonBody==="object")return $.jsonBody;if($.formBody&&typeof $.formBody==="object")return $.formBody;try{let O=await $.clone().text();if(O.length>L$)throw new n(413,`Request body exceeds ${L$}-byte limit`);if(!O)return{};let G=JSON.parse(O);return G&&typeof G==="object"&&!Array.isArray(G)?G:{}}catch(O){if(O instanceof n)throw O;throw new n(400,`Invalid JSON body: ${O.message}`)}}function W$($){if($==null)return null;if(typeof $==="number")return Number.isFinite($)&&$>0?$:null;if(typeof $==="string"){let J=$.trim();if(!J)return null;if(/^\d+$/.test(J)){let O=Number(J);return Number.isFinite(O)&&O>0?O:null}return J}return null}function e$($){let J=$.bearerToken;if(typeof J==="function"){let G=J.call($);if(G)return G}let O=$.headers?.get?.("authorization")||$.headers?.get?.("Authorization")||"";if(typeof O==="string"&&O.startsWith("Bearer "))return O.substring(7);return null}async function a($){let J=$._authenticatedUser;if(J)return J;let O=e$($);if(!O)return null;try{let{Auth:G}=await import("@stacksjs/auth"),Z=await G.getUserFromToken(O);if(Z)$._authenticatedUser=Z;return Z||null}catch{return null}}function $$($,J){if($==null||J==null)return!1;if(Array.isArray(J))return J.some((O)=>String(O)===String($));return String($)===String(J)}function cJ($){let J=$?.attributes||{},O=(G)=>Object.prototype.hasOwnProperty.call(J,G);return O("teamId")||O("team_id")?"team_id":null}function wJ($){let J=e$($),O=$.headers?.get?.("cookie")||"";return{bearerToken:()=>J,cookies:{get:(G)=>{for(let Z of O.split(";")){let z=Z.indexOf("=");if(z===-1)continue;if(Z.slice(0,z).trim()===G)return decodeURIComponent(Z.slice(z+1).trim())}return null}}}}function $J($){if($?.ownership)return $.ownership;let J=cJ($);if(!J)return null;return{field:J,resolve:async(O,G)=>{let{resolveAuthenticatedTeamId:Z}=await import("@stacksjs/auth");return Z(wJ(G))}}}async function J$($,J,O){let G=$J($);if(!G||!G.field||typeof G.resolve!=="function")return{enforced:!1,value:null,field:"",bypass:!1};let Z=typeof G.bypass==="function"?!!G.bypass(J,O):!1,z=null;try{z=await G.resolve(J,O)}catch{z=null}return{enforced:!0,value:z,field:String(G.field),bypass:Z}}async function d$($,J,O,G){let Z=$?.authedFill?.[J];if(!Z)return{};if(typeof Z==="function")try{let z=await Z(O,G);return z&&typeof z==="object"?z:{}}catch{return{}}if(typeof Z==="object"){let z={};for(let[K,W]of Object.entries(Z))try{z[K]=typeof W==="function"?await W(O,G):W}catch{}return z}return{}}var qJ,E$,b,L$=1048576,JJ;var OJ=d(async()=>{v$();i$();qJ=r$("config/qb.ts");try{let $=(await import(qJ)).default;u$($??n$)}catch{X$.debug("[orm] No config/qb.ts override found \u2014 deriving config from DB_CONNECTION");let $=l.DB_CONNECTION||"sqlite";u$({...n$,dialect:$,database:$==="sqlite"?{database:l.DB_DATABASE_PATH||"database/stacks.sqlite"}:{database:l.DB_DATABASE||"stacks",host:l.DB_HOST||"127.0.0.1",port:l.DB_PORT||($==="postgres"?5432:3306),username:l.DB_USERNAME||($==="postgres"?"postgres":"root"),password:l.DB_PASSWORD||""}})}E$=await m$({defaultsRoot:yJ("framework/defaults/app/Models"),userRoot:r$("app/Models"),onImportError:($,J)=>X$.warn(`[orm] Could not load model ${$}: ${J.message}`)}),b=bJ();for(let[$,J]of Object.entries(E$)){let O=J.traits?.useApi;if(!O)continue;let G=typeof O==="object"?O:{},Z=G.uri||J.table||$.toLowerCase()+"s",z=G.routes||["index","show","store","update","destroy"],K=J.table||Z,W=y$(J),L=a$(J),Q=`/api/${Z}`,j=b$(J.attributes,L),{read:U,write:D,declared:V}=c$(O);if(["store","update","destroy"].some((Y)=>z.includes(Y))&&V&&D.length===0)X$.warn(`[orm] ${$}: registering UNAUTHENTICATED mutating routes at ${Q} (explicit \`middleware: []\` opt-out)`);if(["index","show"].some((Y)=>z.includes(Y))&&V&&U.length===0)X$.debug(`[orm] ${$}: registering public read routes at ${Q} (declared \`middleware.read: []\`)`);let I=!!$J(J),q=I&&!U.includes("auth")?["auth",...U]:U,C=(Y,X=q)=>{let x=Y;for(let T of X)if(x&&typeof x.middleware==="function")x=x.middleware(T);return x};if(z.includes("index")&&!s("GET",Q))C(m.get(Q,async(Y)=>{try{let X=new URL(Y.url),{page:x,perPage:T,offset:E}=w$(X.searchParams),_=X.searchParams.get("sort"),A=b.selectFrom(K);A=q$(A,_,j);let c=new Set(["page","per_page","sort","fields","search","include","limit","offset","with_count","withTrashed","onlyTrashed"]);for(let[f,g]of X.searchParams.entries()){if(c.has(f)||!g)continue;if(!/^[a-z_][a-z0-9_]*$/i.test(f))continue;let u=j.get(f);if(u)A=A.where(u,"=",g)}let F=X.searchParams.get("search");if(F&&W.length>0){let f=W.slice(0,5);A=A.where((g)=>{for(let u of f)g=g.orWhere(R(u),"like",`%${F}%`);return g})}let M=X.searchParams.get("fields");if(M){let f=M.split(",").map((g)=>g.trim()).filter((g)=>/^[a-z_][a-z0-9_]*$/i.test(g)).map((g)=>R(g));if(f.length>0)A=A.select(f)}let k=!!J.traits?.useSoftDeletes,P=X.searchParams.get("withTrashed")==="true",i=X.searchParams.get("onlyTrashed")==="true";if(k&&!P)A=i?A.whereNotNull("deleted_at"):A.whereNull("deleted_at");let S=I?await J$(J,await a(Y),Y):{enforced:!1,value:null,field:"",bypass:!1};if(S.enforced&&!S.bypass){if(S.value==null||Array.isArray(S.value)&&S.value.length===0){let f=D$(X,x,T,0,!1,void 0);return new Response(JSON.stringify({data:[],...f,meta:Q$(X,x,T,0,!1,void 0)}),{status:200,headers:{"Content-Type":"application/json","Cache-Control":"private, no-store",Vary:"Authorization"}})}A=Array.isArray(S.value)?A.where(S.field,"in",S.value):A.where(S.field,"=",S.value)}let h=await A.limit(T+1).offset(E).get()||[],p=h.length>T,e=(p?h.slice(0,T):h).map((f)=>r(O$(f,J),L)),V$=X.searchParams.get("include");if(V$)e=await l$(e,J,V$,E$);let LJ=X.searchParams.get("with_count")==="true",t;if(LJ)try{let f=b.selectFrom(K);if(S.enforced&&!S.bypass&&S.value!=null)f=Array.isArray(S.value)?f.where(S.field,"in",S.value):f.where(S.field,"=",S.value);let g=await f.count(),u=typeof g==="number"?g:Number(g?.count??g);if(Number.isFinite(u))t=u}catch{}let Z$={"Content-Type":"application/json"};if(t!==void 0&&!Number.isNaN(t))Z$["X-Total-Count"]=String(t);Z$["Cache-Control"]=S.enforced&&!S.bypass?"private, no-store":"public, max-age=15, must-revalidate",Z$.Vary="Authorization";let WJ=D$(X,x,T,e.length,p,t);return new Response(JSON.stringify({data:e,...WJ,meta:Q$(X,x,T,e.length,p,t)}),{status:200,headers:Z$})}catch(X){if(X instanceof n){let x={error:X.message};if(X.details!==void 0)x.details=X.details;return B(x,X.status||400)}return B({error:`Failed to fetch ${Z}`,detail:String(X)},500)}}));if(z.includes("show")&&!s("GET",`${Q}/{id}`))C(m.get(`${Q}/{id}`,async(Y)=>{try{let X=W$(Y.params?.id);if(X==null)return B({error:"Invalid ID parameter"},400);let x=await b.selectFrom(K).where({id:X}).executeTakeFirst();if(!x)return B({error:`${$} not found`},404);let T=new URL(Y.url);if(J.traits?.useSoftDeletes&&x.deleted_at&&T.searchParams.get("withTrashed")!=="true")return B({error:`${$} not found`},404);let E=I?await J$(J,await a(Y),Y):{enforced:!1,value:null,field:"",bypass:!1};if(E.enforced&&!E.bypass){if(E.value==null||!$$(x[E.field],E.value))return B({error:`${$} not found`},404)}let _=r(O$(x,J),L),A=T.searchParams.get("include");if(A){let[P]=await l$([_],J,A,E$);_=P}let c=_?.updated_at||_?.created_at,F=c?`W/"${_.id}-${String(c)}"`:void 0,M=Y.headers?.get?.("if-none-match");if(F&&M&&M===F)return new Response(null,{status:304,headers:{ETag:F}});let k={"Content-Type":"application/json"};if(F)k.ETag=F;return k["Cache-Control"]=E.enforced&&!E.bypass?"private, no-store":"public, max-age=30, must-revalidate",k.Vary="Authorization",new Response(JSON.stringify({data:_}),{status:200,headers:k})}catch(X){if(X instanceof n){let x={error:X.message};if(X.details!==void 0)x.details=X.details;return B(x,X.status||400)}return B({error:`Failed to fetch ${$}`,detail:String(X)},500)}}));if(z.includes("store")&&!s("POST",Q))C(m.post(Q,async(Y)=>{try{let X=await I$(Y),x=N$(X,L),T=_$(x,W),E=await a(Y);if(E){let k=await d$(J,"creating",E,Y);for(let[P,i]of Object.entries(k))if(i!==void 0&&i!==null&&T[P]===void 0)T[P]=i}if(Object.keys(T).length===0)return B({error:"No fillable fields provided"},422);let _=S$(T,J,"creating");if(!_.valid)return B({success:!1,message:"Validation failed",errors:_.errors},422);if(J.traits?.useTimestamps!==!1){let k=new Date().toISOString();T.created_at=k,T.updated_at=k}let A=await s$(T,J),c=A$(t$(A,J)),F=await b.insertInto(K).values(c).execute(),M=c;try{let k=F?.lastInsertRowid??F?.insertId??F;if(k){let P=await b.selectFrom(K).where({id:k}).executeTakeFirst();if(P)M=P}}catch{}return B({data:r(O$(M,J),L)},201)}catch(X){let{status:x,body:T}=j$(X,$,"create");return B(T,x)}}),D);if(z.includes("update")){let Y=async(X)=>{try{let x=W$(X.params?.id);if(x==null)return B({error:"Invalid ID parameter"},400);let T=await I$(X),E=N$(T,L),_=_$(E,W),A=await a(X);if(A){let S=await d$(J,"updating",A,X);for(let[h,p]of Object.entries(S))if(p!==void 0&&p!==null&&_[h]===void 0)_[h]=p}if(Object.keys(_).length===0)return B({error:"No fillable fields provided"},422);let c=S$(_,J,"updating");if(!c.valid)return B({success:!1,message:"Validation failed",errors:c.errors},422);let F=await b.selectFrom(K).where({id:x}).executeTakeFirst();if(!F)return B({error:`${$} not found`},404);let M=await J$(J,A,X);if(M.enforced&&!M.bypass){if(!A)return B({error:"Auth required"},401);let S=F[M.field];if(!$$(S,M.value))return B({error:`Not your ${$}`},403);let h=Object.keys(_).find((p)=>R(p)===R(M.field));if(h!==void 0&&!$$(_[h],M.value))return B({error:`Cannot reassign ${$} ownership`},403)}if(J.traits?.useTimestamps!==!1)_.updated_at=new Date().toISOString();let k=await s$(_,J),P=A$(t$(k,J));await b.updateTable(K).set(P).where({id:x}).execute();let i={...F,...P};try{let S=await b.selectFrom(K).where({id:x}).executeTakeFirst();if(S)i=S}catch{}return B({data:r(O$(i,J),L)})}catch(x){let{status:T,body:E}=j$(x,$,"update");return B(E,T)}};if(!s("PUT",`${Q}/{id}`))C(m.put(`${Q}/{id}`,Y),D);if(!s("PATCH",`${Q}/{id}`))C(m.patch(`${Q}/{id}`,Y),D)}let H=!!J.traits?.useSoftDeletes;if(z.includes("destroy")&&!s("DELETE",`${Q}/{id}`))C(m.delete(`${Q}/{id}`,async(Y)=>{try{let X=W$(Y.params?.id);if(X==null)return B({error:"Invalid ID parameter"},400);let x=await b.selectFrom(K).where({id:X}).executeTakeFirst();if(!x)return B({error:`${$} not found`},404);let T=await a(Y),E=await J$(J,T,Y);if(E.enforced&&!E.bypass){if(!T)return B({error:"Auth required"},401);let _=x[E.field];if(!$$(_,E.value))return B({error:`Not your ${$}`},403)}if(H){let _=new Date().toISOString();await b.updateTable(K).set({deleted_at:_,updated_at:_}).where({id:X}).execute()}else await b.deleteFrom(K).where({id:X}).execute();return new Response(null,{status:204})}catch(X){if(X instanceof n){let x={error:X.message};if(X.details!==void 0)x.details=X.details;return B(x,X.status||400)}return B({error:`Failed to delete ${$}`,detail:String(X)},500)}}),D);if(z.includes("destroy")&&!s("POST",`${Q}/bulk-delete`))C(m.post(`${Q}/bulk-delete`,async(Y)=>{try{let x=(await I$(Y))?.ids;if(!Array.isArray(x)||x.length===0)return B({error:"An array of IDs is required"},422);if(x.length>100)return B({error:"Cannot delete more than 100 records at once"},422);let T=[],E=[];for(let F of x){let M=W$(F);if(M!=null)T.push(M);else E.push(F)}if(E.length>0)return B({error:"Invalid IDs in batch",invalid:E},422);let _=await a(Y),A=await J$(J,_,Y);if(A.enforced&&!A.bypass){if(!_)return B({error:"Auth required"},401);if(A.value==null)return B({error:"Caller has no ownership identity"},403);let F=await b.selectFrom(K).select(["id",A.field]).execute(),M=new Set(F.filter((P)=>$$(P[A.field],A.value)).map((P)=>String(P.id))),k=T.filter((P)=>!M.has(String(P)));if(k.length>0)return B({error:`Cannot delete ${$} you don't own`,ids:k},403)}let c=new Date().toISOString();for(let F of T)if(H)await b.updateTable(K).set({deleted_at:c,updated_at:c}).where({id:F}).execute();else await b.deleteFrom(K).where({id:F}).execute();return B({message:`Successfully deleted ${T.length} ${Z}`})}catch(X){if(X instanceof n){let x={error:X.message};if(X.details!==void 0)x.details=X.details;return B(x,X.status||400)}return B({error:`Failed to bulk delete ${Z}`,detail:String(X)},500)}}),D)}JJ=m});var GJ={};x$(GJ,{default:()=>JJ});var ZJ=d(async()=>{await OJ()});class M${data;status;headers;isOk;constructor($,J,O,G){this.data=$;this.status=J;this.headers=O;this.isOk=G}ok(){return this.status===200}created(){return this.status===201}accepted(){return this.status===202}noContent(){return this.status===204}movedPermanently(){return this.status===301}found(){return this.status===302}badRequest(){return this.status===400}unauthorized(){return this.status===401}paymentRequired(){return this.status===402}forbidden(){return this.status===403}notFound(){return this.status===404}requestTimeout(){return this.status===408}conflict(){return this.status===409}unprocessableEntity(){return this.status===422}tooManyRequests(){return this.status===429}serverError(){return this.status===500}}class C${defaultHeaders={Accept:"application/json","Content-Type":"application/json"};queryParams;bodyData;isFormData=!1;customHeaders={};attachments=[];isMultipart=!1;digestAuth;withQueryParams($){return this.queryParams=$,this}withHeaders($){return this.customHeaders={...this.customHeaders,...$},this}accept($){return this.defaultHeaders.Accept=$,this}acceptJson(){return this.accept("application/json")}withToken($){return this.customHeaders.Authorization=`Bearer ${$}`,this}withBasicAuth($,J){let O=btoa(`${$}:${J}`);return this.customHeaders.Authorization=`Basic ${O}`,this}withDigestAuth($,J){return this.digestAuth={username:$,password:J},this}withBody($){return this.bodyData=$,this}asForm(){return this.isFormData=!0,this.defaultHeaders["Content-Type"]="application/x-www-form-urlencoded",this}attach($,J,O,G){let Z=typeof J==="string"?new Blob([J],{type:G?.["Content-Type"]||"text/plain"}):J;return this.attachments.push({name:$,content:Z,filename:O,headers:G}),this.isMultipart=!0,delete this.defaultHeaders["Content-Type"],this}getHeaders(){return{...this.defaultHeaders,...this.customHeaders}}addQueryParams($){if(!this.queryParams)return $;let J=new URLSearchParams;Object.entries(this.queryParams).forEach(([Z,z])=>{if(z!=null)J.append(Z,String(z))});let O=J.toString();if(!O)return $;let G=$.includes("?");return $+(G?"&":"?")+O}async formatBody($){let J=$||this.bodyData;if(this.isMultipart){let O=new FormData;if(J)Object.entries(J).forEach(([G,Z])=>{O.append(G,String(Z))});for(let G of this.attachments)if(G.headers){let Z=G.content instanceof Blob?new Blob([G.content],{type:G.headers["Content-Type"]}):G.content;O.append(G.name,Z,G.filename)}else O.append(G.name,G.content,G.filename);return O}if(this.isFormData&&J){let O=new URLSearchParams;return Object.entries(J).forEach(([G,Z])=>{if(Z!=null)O.append(G,String(Z))}),O.toString()}return J?JSON.stringify(J):void 0}resetState(){this.queryParams=void 0,this.bodyData=void 0,this.isFormData=!1,this.isMultipart=!1,this.customHeaders={},this.attachments=[],this.digestAuth=void 0,this.defaultHeaders["Content-Type"]="application/json"}async handleDigestAuth($,J,O,G){if($.status!==401||!this.digestAuth)return $;let Z=$.headers.get("WWW-Authenticate");if(!Z?.startsWith("Digest "))return $;let z=Z.substring(7).split(",").reduce((V,N)=>{let[y,I]=N.trim().split("=");if(y)V[y]=I?.replace(/["']/g,"")??"";return V},{}),K=await this.generateMD5(`${this.digestAuth.username}:${z.realm}:${this.digestAuth.password}`),W=await this.generateMD5(`${O}:${J}`),L="00000001",Q=await this.generateMD5(Date.now().toString()).then((V)=>V.substring(0,8)),j=await this.generateMD5(`${K}:${z.nonce}:${L}:${Q}:${z.qop}:${W}`),U={username:`"${this.digestAuth.username}"`,realm:`"${z.realm}"`,nonce:`"${z.nonce}"`,uri:`"${J}"`,algorithm:z.algorithm?`"${z.algorithm}"`:void 0,qop:`"${z.qop}"`,nc:L,cnonce:`"${Q}"`,response:`"${j}"`,opaque:z.opaque?`"${z.opaque}"`:void 0},D=Object.entries(U).filter(([V,N])=>N!==void 0).map(([V,N])=>`${V}=${N}`).join(", ");return this.customHeaders.Authorization=`Digest ${D}`,fetch(J,{method:O,headers:this.getHeaders(),body:G?this.formatBody(G):void 0})}async generateMD5($){let O=new TextEncoder().encode($),G=await crypto.subtle.digest("SHA-256",O);return Array.from(new Uint8Array(G)).map((z)=>z.toString(16).padStart(2,"0")).join("")}async request($,J,O){let G=this.addQueryParams($),Z=await this.formatBody(O),z=await fetch(G,{method:J,headers:this.getHeaders(),body:Z});if(this.digestAuth)z=await this.handleDigestAuth(z,G,J,O);let K=await z.json();return this.resetState(),new M$(K,z.status,z.headers,z.ok)}async get($){return this.request($,"GET")}async post($,J){return this.request($,"POST",J)}async put($,J){return this.request($,"PUT",J)}async patch($,J){return this.request($,"PATCH",J)}async delete($){return this.request($,"DELETE")}}var nJ=new C$;B$();import{path as Y$}from"@stacksjs/path";function vJ($){if(!$||typeof $!=="object")return{type:"string"};let J=$,O=Array.isArray(J.rules)?J.rules:[],G=(j)=>O.find((U)=>U.name===j),Z=(j,U)=>{let D=G(j)?.params?.[U];return typeof D==="number"?D:void 0},z=J.name??J._type??"string",K={type:z==="enum"?"string":z},W=Z("min","min")??(typeof J._min==="number"?J._min:void 0),L=Z("max","max")??(typeof J._max==="number"?J._max:void 0);if(W!==void 0)K[z==="string"?"minLength":"minimum"]=W;if(L!==void 0)K[z==="string"?"maxLength":"maximum"]=L;if(G("email")||J._email)K.format="email";if(G("url")||J._url)K.format="uri";if(G("uuid")||J._uuid)K.format="uuid";let Q=Array.isArray(J.allowedValues)?J.allowedValues:Array.isArray(J._enum)?J._enum:null;if(Q)K.enum=Q;return K}function hJ($){if(!$||typeof $!=="object")return!1;let J=$;return Boolean(J.isRequired??J._required)}async function pJ($){if(typeof $!=="string"||!$||$.includes(".."))return null;try{let{path:J}=await import("@stacksjs/path"),O=[J.appPath(`${$}.ts`),J.storagePath(`framework/defaults/app/${$}.ts`)];for(let G of O)try{if(!await Bun.file(G).exists())continue;let K=(await import(G)).default;if(K&&typeof K==="object"&&"validations"in K){let W=K.validations;return W&&typeof W==="object"?W:null}return null}catch{}}catch{}return null}async function WO($={}){let J=$.portable??!0,{listRegisteredRoutes:O}=await import("@stacksjs/router");try{let{loadRoutes:L}=await import("@stacksjs/router"),{default:Q}=await import(Y$.appPath("Routes.ts"));await L(Q)}catch(L){let Q=L instanceof Error?L.message:String(L);if(J)throw Error(`[generateOpenApi] Refusing to emit a partial spec: failed to load routes/api.ts + framework routes: ${Q}`);console.warn(`[generateOpenApi] Failed to load routes/api.ts + framework routes: ${Q}`)}try{try{await import("@stacksjs/orm/routes")}catch{await ZJ().then(() => GJ)}}catch(L){let Q=L instanceof Error?L.message:String(L);if(J)throw Error(`[generateOpenApi] Refusing to emit a partial spec: failed to load useApi-generated ORM routes: ${Q}`);console.warn(`[generateOpenApi] Failed to load useApi-generated ORM routes: ${Q}`)}let G=(L)=>L.replace(/(^|\/):(\w+)(?=$|\/)/g,"$1{$2}"),Z=[...O()].map((L)=>({route:L,oasPath:G(L.path),method:L.method.toLowerCase()})).sort((L,Q)=>{if(L.oasPath!==Q.oasPath)return L.oasPath<Q.oasPath?-1:1;return L.method<Q.method?-1:L.method>Q.method?1:0});if(J&&Z.length===0)throw Error("[generateOpenApi] Refusing to emit an empty spec: no routes were registered. This usually means route loading failed silently rather than that the app has no API.");let z="Stacks API";if(!J)try{let{config:L}=await import("@stacksjs/config");if(L.app?.name)z=`${L.app.name} API`}catch{}let K={openapi:"3.0.0",info:{title:z,version:"1.0.0"},paths:{},components:{schemas:{}}},W=new Set;for(let{route:L,oasPath:Q,method:j}of Z){if(!K.paths[Q])K.paths[Q]={};let U=[];for(let I of L.path.matchAll(/\{(\w+)\}/g))if(I[1])U.push(I[1]);for(let I of L.path.matchAll(/(?:^|\/):(\w+)(?=$|\/)/g))if(I[1])U.push(I[1]);let D=L.name??`${j}_${Q.replace(/[^a-z0-9]/gi,"_")}`,V=D;if(W.has(V)){V=`${D}_${j}`;let I=2;while(W.has(V))V=`${D}_${j}_${I++}`}W.add(V);let N={summary:L.name??L.path,operationId:V,parameters:U.map((I)=>({name:I,in:"path",required:!0,schema:{type:"string"}})),responses:{200:{description:"Successful response",content:{"application/json":{schema:{type:"object"}}}},422:{description:"Validation failed"},500:{description:"Server error"}}},y=L.handler?await pJ(L.handler):null;if(y&&Object.keys(y).length>0){let I=Object.entries(y).map(([q,C])=>{let H=C?.rule;return{field:q,schema:vJ(H),required:hJ(H)}});if(j==="get"||j==="head"||j==="delete"){let q=new Set(U);for(let{field:C,schema:H,required:Y}of I){if(q.has(C))continue;N.parameters?.push({name:C,in:"query",required:Y,schema:H})}}else{let q={type:"object",properties:{},required:[]},C=q.properties,H=q.required;for(let Y of I)if(C[Y.field]=Y.schema,Y.required)H.push(Y.field);if(H.length===0)delete q.required;N.requestBody={required:H.length>0,content:{"application/json":{schema:q}}}}}K.paths[Q][j]=N}if($.write!==!1){let Q=Bun.file(Y$.frameworkPath("api/openapi.json")).writer();Q.write(JSON.stringify(K,null,2)),await Q.end();let{renderOpenApiTypes:j}=await Promise.resolve().then(() => (z$(),R$)),{renderApiClient:U}=await Promise.resolve().then(() => (B$(),f$));await Bun.write(Y$.frameworkPath("api/api-types.ts"),j(K)),await Bun.write(Y$.frameworkPath("api/client.ts"),U(K,{name:K.info.title}))}return K}z$();class v{static instance=new v;isMissing(){return!0}}class G${data;constructor($){this.data=$}}class zJ{condition;value;defaultValue;constructor($,J,O=new v){this.condition=$;this.value=J;this.defaultValue=O}resolve(){return(typeof this.condition==="function"?this.condition():this.condition)?this.value:this.defaultValue}}class KJ{resource;additional={};request;static wrap="data";static additionalMeta={};constructor($){this.resource=$}withRequest($){return this.request=$,this}withAdditional($){return this.additional={...this.additional,...$},this}resolve($){let J=this.toArray($||this.request);return this.filterAndResolve(J)}toResponse($){let J=this.resolve($),O=this.constructor.wrap;if(O)return{[O]:J,...this.additional};return{...J,...this.additional}}toJson($){return JSON.stringify(this.toResponse($))}toJSON(){return this.toResponse()}static collection($){return new F$($,this)}when($,J,O){if(typeof $==="function"?$():$)return typeof J==="function"?J():J;return O!==void 0?O:v.instance}whenNotNull($,J){if($===null||$===void 0)return v.instance;return J?J($):$}whenLoaded($,J,O){let G=this.resource;if(!(($ in G)&&G[$]!==void 0))return O!==void 0?O:v.instance;if(J!==void 0)return typeof J==="function"?J():J;return G[$]}whenCounted($,J){let O=this.resource,G=`${$}_count`;if(G in O)return O[G];return J!==void 0?J:v.instance}merge($){return new G$($)}mergeWhen($,J){if(!(typeof $==="function"?$():$))return v.instance;let G=typeof J==="function"?J():J;return new G$(G)}static MAX_RESOLVE_DEPTH=20;filterAndResolve($,J=0){if(J>=KJ.MAX_RESOLVE_DEPTH)return $;let O={};for(let[G,Z]of Object.entries($)){if(Z instanceof v)continue;if(Z instanceof G$){Object.assign(O,this.filterAndResolve(Z.data,J+1));continue}if(Z instanceof zJ){let z=Z.resolve();if(!(z instanceof v))O[G]=z;continue}if(Z!==null&&typeof Z==="object"&&!Array.isArray(Z)&&!(Z instanceof Date)){O[G]=this.filterAndResolve(Z,J+1);continue}if(Array.isArray(Z)){O[G]=Z.filter((z)=>!(z instanceof v)).map((z)=>{if(z instanceof G$)return z.data;if(z!==null&&typeof z==="object"&&!(z instanceof Date))return this.filterAndResolve(z,J+1);return z});continue}O[G]=Z}return O}static withoutWrapping(){this.wrap=null}static wrapWith($){this.wrap=$}}class F${resources;ResourceClass;additional={};request;static wrap="data";constructor($,J){this.resources=$,this.ResourceClass=J}withRequest($){return this.request=$,this}withAdditional($){return this.additional={...this.additional,...$},this}resolve($){let J=$||this.request;return this.resources.map((O)=>{let G=new this.ResourceClass(O);if(J)G.withRequest(J);return G.resolve(J)})}toResponse($){let J=this.resolve($),O=this.constructor.wrap;if(O)return{[O]:J,...this.additional};return{data:J,...this.additional}}toJson($){return JSON.stringify(this.toResponse($))}count(){return this.resources.length}isEmpty(){return this.resources.length===0}isNotEmpty(){return this.resources.length>0}}class QJ extends F${meta;links;constructor($,J){super($.data,J);this.meta=$.meta,this.links=$.links}static fromPagination($,J,O){let{currentPage:G,perPage:Z,total:z,baseUrl:K=""}=O,W=Math.ceil(z/Z),L=z>0?(G-1)*Z+1:null,Q=z>0?Math.min(G*Z,z):null;return new QJ({data:$,meta:{current_page:G,from:L,last_page:W,per_page:Z,to:Q,total:z},links:{first:`${K}?page=1`,last:`${K}?page=${W}`,prev:G>1?`${K}?page=${G-1}`:null,next:G<W?`${K}?page=${G+1}`:null}},J)}toResponse($){return{data:this.resolve($),meta:this.meta,links:this.links,...this.additional}}}function YO($,J){let O=J($);return{toResponse:()=>({data:O}),toJson:()=>JSON.stringify({data:O})}}function xO($,J){let O=$.map(J);return{toResponse:()=>({data:O}),toJson:()=>JSON.stringify({data:O})}}export{w as schemaType,vJ as ruleToSchema,hJ as ruleIsRequired,YO as resource,_J as renderOpenApiTypes,DJ as renderApiClient,P$ as methodName,WO as generateOpenApi,nJ as fetcher,xO as collection,F$ as ResourceCollection,QJ as PaginatedResourceCollection,v as MissingValue,G$ as MergeValue,KJ as JsonResource,zJ as ConditionalValue};
|
|
139
|
+
`}var NJ;var B$=s(()=>{z$();NJ=["get","put","post","delete","options","head","patch"]});function EJ($){let J=$;return J?.code==="SQLITE_CONSTRAINT_UNIQUE"||J?.code==="SQLITE_CONSTRAINT"||J?.code==="23505"||J?.errno===1062||/unique|duplicate/i.test(J?.message??"")}function j$($,J,O){let G=$;if($ instanceof Error&&typeof G.status==="number"&&Number.isInteger(G.status)&&G.status>=400&&G.status<600){let Z={error:$.message};if(G.details!==void 0)Z.details=G.details;return{status:G.status,body:Z}}if(EJ($))return{status:409,body:{error:`${J} already exists`}};return{status:500,body:{error:`Failed to ${O} ${J}`,detail:String($)}}}function R($){return $.replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}function A$($){let J={};for(let[O,G]of Object.entries($))J[R(O)]=G;return J}function y$($){if(!$)return[];let J=Object.entries($.attributes??{}).filter(([,O])=>O?.fillable===!0).map(([O])=>O);for(let O of $.belongsTo??[]){if(typeof O!=="string"||!O.trim())continue;let G=R(O.trim()).split("_").filter(Boolean);if(G.length===0)continue;let Z=`${G[0]}${G.slice(1).map((z)=>`${z[0]?.toUpperCase()}${z.slice(1)}`).join("")}Id`;J.push(Z)}return[...new Set(J)]}function _$($,J){if(!$||J.length===0)return{};let O={};for(let G of J){if(G in $){O[G]=$[G];continue}let Z=R(G);if(Z!==G&&Z in $)O[G]=$[Z]}return O}function IJ($,J){if($?.name!=="date"||J instanceof Date||typeof J!=="string")return J;let O=/^(\d{4})-(\d{2})-(\d{2})$/.exec(J);if(!O)return J;let G=Number(O[1]),Z=Number(O[2]),z=Number(O[3]),K=new Date(Date.UTC(G,Z-1,z));if(K.getUTCFullYear()!==G||K.getUTCMonth()!==Z-1||K.getUTCDate()!==z)return J;return K}function N$($,J){if(!J.length)return $;let O={...$};for(let G of J)delete O[G],delete O[R(G)];return O}function r($,J){if(!$||J.length===0)return $;let O={...$};for(let G of J)delete O[G],delete O[R(G)];return O}function b$($,J){let O=new Map;for(let G of[...Object.keys($??{}),...FJ]){let Z=R(G);if(!/^\w+$/.test(Z))continue;O.set(G,Z),O.set(Z,Z)}for(let G of J)O.delete(G),O.delete(R(G));return O}function q$($,J,O){if(!J)return $;let G=String(J).split(",").map((z)=>z.trim()).filter(Boolean),Z=$;for(let z of G){let K=z.startsWith("-"),X=K?z.slice(1):z;if(!/^\w+$/.test(X))continue;let Q=O.get(X);if(!Q)continue;Z=Z.orderBy(Q,K?"desc":"asc")}return Z}function MJ($){try{return JSON.parse($)}catch{return $}}function CJ($){try{return JSON.parse($)}catch{return[]}}function H$($,J,O){if(!$||typeof $!=="object"||!J||Object.keys(J).length===0)return $;let G={...$};for(let[Z,z]of Object.entries(J)){let K=typeof z==="string"?VJ[z]:z;if(!K||typeof K[O]!=="function")continue;if(Object.prototype.hasOwnProperty.call(G,Z))G[Z]=K[O](G[Z]);let X=R(Z);if(X!==Z&&Object.prototype.hasOwnProperty.call(G,X))G[X]=K[O](G[X])}return G}function S$($,J,O){let G=J?.attributes??{},Z={};for(let[z,K]of Object.entries(G)){let X=K?.validation?.rule;if(!X||typeof X.validate!=="function")continue;let Q=Object.prototype.hasOwnProperty.call($,z);if(!Q&&O==="updating")continue;let L=K!==null&&typeof K==="object"&&Object.prototype.hasOwnProperty.call(K,"default"),j=Q?$[z]:L?K.default:void 0,S=IJ(X,j),U=X.validate(S);if(!U?.valid&&Array.isArray(U?.errors)&&U.errors.length>0)Z[z]=U.errors.map((F)=>K?.validation?.message?.[F?.code]??F?.message??"invalid")}return Object.keys(Z).length===0?{valid:!0}:{valid:!1,errors:Z}}function U$($){return $.replace(/\{[^}]*\}/g,"{}").replace(/:[^/]+/g,"{}")}function T$($){if(Array.isArray($))return $.filter((J)=>typeof J==="string"&&J.length>0);return typeof $==="string"&&$?[$]:[]}function w$($){let J=typeof $==="object"&&$!==null&&"middleware"in $,O=$?.middleware;if(!J)return{read:["auth"],write:["auth"],declared:!1};if(O&&typeof O==="object"&&!Array.isArray(O)){let Z=O;return{read:"read"in Z?T$(Z.read):["auth"],write:"write"in Z?T$(Z.write):["auth"],declared:!0}}let G=T$(O);return{read:G,write:G,declared:!0}}function c$($){let J=Number.parseInt($.get("page")||String(1),10),O=Number.isFinite(J)?Math.max(1,J):1,G=Number.parseInt($.get("per_page")||String(g$),10),Z=Math.min(Number.isFinite(G)?Math.max(1,G):g$,kJ);return{page:O,perPage:Z,offset:(O-1)*Z}}function K$($,J){let O=new URL($.toString());return O.searchParams.set("page",String(J)),`${O.pathname}${O.search}`}function Q$($,J,O,G,Z,z){let K=(J-1)*O,X=G===0,Q={page:J,per_page:O,from:X?null:K+1,to:X?null:K+G,has_more_pages:Z,prev_page_url:J>1?K$($,J-1):null,next_page_url:Z?K$($,J+1):null};if(z!==void 0&&!Number.isNaN(z)){let L=Math.max(1,Math.ceil(z/O));Q.total=z,Q.last_page=L,Q.first_page_url=K$($,1),Q.last_page_url=K$($,L)}return Q}function D$($,J,O,G,Z,z){let{page:K,...X}=Q$($,J,O,G,Z,z);return{current_page:K,...X}}var FJ,VJ,g$=15,kJ=100;var v$=s(()=>{FJ=["id","uuid","created_at","updated_at","deleted_at"];VJ={string:{get:($)=>$!=null?String($):null,set:($)=>$!=null?String($):null},number:{get:($)=>$!=null?Number($):null,set:($)=>$!=null?Number($):null},integer:{get:($)=>$!=null?Math.trunc(Number($)):null,set:($)=>$!=null?Math.trunc(Number($)):null},float:{get:($)=>$!=null?Number.parseFloat(String($)):null,set:($)=>$!=null?Number.parseFloat(String($)):null},boolean:{get:($)=>$===1||$==="1"||$===!0||$==="true",set:($)=>$===!0||$===1||$==="1"||$==="true"?1:0},json:{get:($)=>$==null?null:typeof $==="string"?MJ($):$,set:($)=>$==null?null:typeof $==="string"?$:JSON.stringify($)},datetime:{get:($)=>$?new Date($):null,set:($)=>$ instanceof Date?$.toISOString():$},date:{get:($)=>$?new Date($):null,set:($)=>$ instanceof Date?$.toISOString().split("T")[0]:$},array:{get:($)=>$==null?[]:Array.isArray($)?$:typeof $==="string"?CJ($):[],set:($)=>$==null?null:Array.isArray($)?JSON.stringify($):$}}});import{readdirSync as RJ}from"fs";import{basename as PJ,extname as p$,join as fJ}from"path";function gJ($){let J=[],O=(G)=>{let Z;try{Z=RJ(G,{withFileTypes:!0})}catch{return}for(let z of Z){let K=fJ(G,z.name);if(z.isDirectory()){O(K);continue}if(![".ts",".js"].includes(p$(z.name)))continue;if(z.name.startsWith(".")||z.name.startsWith("index"))continue;J.push(K)}};return O($),J.sort()}async function h$($,J,O){for(let G of gJ($))try{let Z=p$(G),z=await import(`${G}?t=${Date.now()}`),K=z.default??z,X=K.name??PJ(G,Z);J[X]={...K,name:X}}catch(Z){O?.(G,Z)}}async function m$($){let J={};return await h$($.defaultsRoot,J,$.onImportError),await h$($.userRoot,J,$.onImportError),J}var i$=()=>{};import{route as m}from"@stacksjs/router";import{env as o}from"@stacksjs/env";import{projectPath as r$,storagePath as yJ}from"@stacksjs/path";import{createQueryBuilder as bJ,defaultConfig as n$,setConfig as u$}from"@stacksjs/query-builder";import{HttpError as n}from"@stacksjs/error-handling";import{log as X$}from"@stacksjs/logging";function t($,J){let O=U$(J);return m.routes.some((G)=>G.method===$&&U$(String(G.path??""))===O)}function a$($){if(!$.attributes)return[];return Object.entries($.attributes).filter(([J,O])=>O.hidden===!0).map(([J])=>J)}function l$($){if($.endsWith("y")&&!/[aeiou]y$/i.test($))return`${$.slice(0,-1)}ies`;if(/(?:s|x|z|ch|sh)$/i.test($))return`${$}es`;return`${$}s`}async function o$($,J,O,G){if(!$.length)return $;let Z=O.split(",").map((L)=>L.trim()).filter(Boolean);if(!Z.length)return $;let z=Array.isArray(J.belongsTo)?J.belongsTo:[],K=Array.isArray(J.hasMany)?J.hasMany:[],X=Array.isArray(J.hasOne)?J.hasOne:[],Q=new Map;for(let L of z)Q.set(R(L),{kind:"belongsTo",modelName:L});for(let L of X)Q.set(R(L),{kind:"hasOne",modelName:L});for(let L of K)Q.set(l$(R(L)),{kind:"hasMany",modelName:L});for(let L of Z){let j=Q.get(L);if(!j)continue;let S=G[j.modelName];if(!S)continue;let U=S.table||l$(R(j.modelName)),F=a$(S),_=(P)=>r(O$(P,S),F);if(j.kind==="belongsTo"||j.kind==="hasOne"){let P=`${R(j.modelName)}_id`,q=[...new Set($.map((D)=>D[P]).filter((D)=>D!=null))];if(!q.length){for(let D of $)D[L]=null;continue}let C=await b.selectFrom(U).whereIn("id",q).get(),V=new Map;for(let D of C??[])V.set(String(D.id),_(D));for(let D of $)D[L]=V.get(String(D[P]))??null}else{let P=String(J.name??""),q=`${R(P)}_id`,C=[...new Set($.map((Y)=>Y.id).filter((Y)=>Y!=null))];if(!C.length){for(let Y of $)Y[L]=[];continue}let V=await b.selectFrom(U).whereIn(q,C).get(),D=new Map;for(let Y of V??[]){let W=String(Y[q]),x=D.get(W)??[];x.push(_(Y)),D.set(W,x)}for(let Y of $)Y[L]=D.get(String(Y.id))??[]}}return $}async function t$($,J){let O=J?.set;if(!O||typeof O!=="object")return $;let G={...$};for(let[Z,z]of Object.entries(O)){if(typeof z!=="function"||!(Z in G))continue;try{G[Z]=await z(G)}catch{}}return G}function d$($,J){return H$($,J?.casts,"set")}function O$($,J){return H$($,J?.casts,"get")}function B($,J=200){return new Response(JSON.stringify($),{status:J,headers:{"Content-Type":"application/json"}})}async function I$($){if(Number($.headers?.get?.("content-length")??0)>L$)throw new n(413,`Request body exceeds ${L$}-byte limit`);if($.jsonBody&&typeof $.jsonBody==="object")return $.jsonBody;if($.formBody&&typeof $.formBody==="object")return $.formBody;try{let O=await $.clone().text();if(O.length>L$)throw new n(413,`Request body exceeds ${L$}-byte limit`);if(!O)return{};let G=JSON.parse(O);return G&&typeof G==="object"&&!Array.isArray(G)?G:{}}catch(O){if(O instanceof n)throw O;throw new n(400,`Invalid JSON body: ${O.message}`)}}function W$($){if($==null)return null;if(typeof $==="number")return Number.isFinite($)&&$>0?$:null;if(typeof $==="string"){let J=$.trim();if(!J)return null;if(/^\d+$/.test(J)){let O=Number(J);return Number.isFinite(O)&&O>0?O:null}return J}return null}function e$($){let J=$.bearerToken;if(typeof J==="function"){let G=J.call($);if(G)return G}let O=$.headers?.get?.("authorization")||$.headers?.get?.("Authorization")||"";if(typeof O==="string"&&O.startsWith("Bearer "))return O.substring(7);return null}async function a($){let J=$._authenticatedUser;if(J)return J;let O=e$($);if(!O)return null;try{let{Auth:G}=await import("@stacksjs/auth"),Z=await G.getUserFromToken(O);if(Z)$._authenticatedUser=Z;return Z||null}catch{return null}}function $$($,J){if($==null||J==null)return!1;if(Array.isArray(J))return J.some((O)=>String(O)===String($));return String($)===String(J)}function wJ($){let J=$?.attributes||{},O=(G)=>Object.prototype.hasOwnProperty.call(J,G);return O("teamId")||O("team_id")?"team_id":null}function cJ($){let J=e$($),O=$.headers?.get?.("cookie")||"";return{bearerToken:()=>J,cookies:{get:(G)=>{for(let Z of O.split(";")){let z=Z.indexOf("=");if(z===-1)continue;if(Z.slice(0,z).trim()===G)return decodeURIComponent(Z.slice(z+1).trim())}return null}}}}function $J($){if($?.ownership)return $.ownership;let J=wJ($);if(!J)return null;return{field:J,resolve:async(O,G)=>{let{resolveAuthenticatedTeamId:Z}=await import("@stacksjs/auth");return Z(cJ(G))}}}async function J$($,J,O){let G=$J($);if(!G||!G.field||typeof G.resolve!=="function")return{enforced:!1,value:null,field:"",bypass:!1};let Z=typeof G.bypass==="function"?!!G.bypass(J,O):!1,z=null;try{z=await G.resolve(J,O)}catch{z=null}return{enforced:!0,value:z,field:String(G.field),bypass:Z}}async function s$($,J,O,G){let Z=$?.authedFill?.[J];if(!Z)return{};if(typeof Z==="function")try{let z=await Z(O,G);return z&&typeof z==="object"?z:{}}catch{return{}}if(typeof Z==="object"){let z={};for(let[K,X]of Object.entries(Z))try{z[K]=typeof X==="function"?await X(O,G):X}catch{}return z}return{}}var qJ,E$,b,L$=1048576,JJ;var OJ=s(async()=>{v$();i$();qJ=r$("config/qb.ts");try{let $=(await import(qJ)).default;u$($??n$)}catch{X$.debug("[orm] No config/qb.ts override found \u2014 deriving config from DB_CONNECTION");let $=o.DB_CONNECTION||"sqlite";u$({...n$,dialect:$,database:$==="sqlite"?{database:o.DB_DATABASE_PATH||"database/stacks.sqlite"}:{database:o.DB_DATABASE||"stacks",host:o.DB_HOST||"127.0.0.1",port:o.DB_PORT||($==="postgres"?5432:3306),username:o.DB_USERNAME||($==="postgres"?"postgres":"root"),password:o.DB_PASSWORD||""}})}E$=await m$({defaultsRoot:yJ("framework/defaults/app/Models"),userRoot:r$("app/Models"),onImportError:($,J)=>X$.warn(`[orm] Could not load model ${$}: ${J.message}`)}),b=bJ();for(let[$,J]of Object.entries(E$)){let O=J.traits?.useApi;if(!O)continue;let G=typeof O==="object"?O:{},Z=G.uri||J.table||$.toLowerCase()+"s",z=G.routes||["index","show","store","update","destroy"],K=J.table||Z,X=y$(J),Q=a$(J),L=`/api/${Z}`,j=b$(J.attributes,Q),{read:S,write:U,declared:F}=w$(O);if(["store","update","destroy"].some((Y)=>z.includes(Y))&&F&&U.length===0)X$.warn(`[orm] ${$}: registering UNAUTHENTICATED mutating routes at ${L} (explicit \`middleware: []\` opt-out)`);if(["index","show"].some((Y)=>z.includes(Y))&&F&&S.length===0)X$.debug(`[orm] ${$}: registering public read routes at ${L} (declared \`middleware.read: []\`)`);let q=!!$J(J),C=q&&!S.includes("auth")?["auth",...S]:S,V=(Y,W=C)=>{let x=Y;for(let T of W)if(x&&typeof x.middleware==="function")x=x.middleware(T);return x};if(z.includes("index")&&!t("GET",L))V(m.get(L,async(Y)=>{try{let W=new URL(Y.url),{page:x,perPage:T,offset:E}=c$(W.searchParams),N=W.searchParams.get("sort"),A=b.selectFrom(K);A=q$(A,N,j);let w=new Set(["page","per_page","sort","fields","search","include","limit","offset","with_count","withTrashed","onlyTrashed"]);for(let[g,y]of W.searchParams.entries()){if(w.has(g)||!y)continue;if(!/^[a-z_][a-z0-9_]*$/i.test(g))continue;let u=j.get(g);if(u)A=A.where(u,"=",y)}let I=W.searchParams.get("search");if(I&&X.length>0){let g=X.slice(0,5);A=A.where((y)=>{for(let u of g)y=y.orWhere(R(u),"like",`%${I}%`);return y})}let M=W.searchParams.get("fields");if(M){let g=M.split(",").map((y)=>y.trim()).filter((y)=>/^[a-z_][a-z0-9_]*$/i.test(y)).map((y)=>R(y));if(g.length>0)A=A.select(g)}let k=!!J.traits?.useSoftDeletes,f=W.searchParams.get("withTrashed")==="true",i=W.searchParams.get("onlyTrashed")==="true";if(k&&!f)A=i?A.whereNotNull("deleted_at"):A.whereNull("deleted_at");let H=q?await J$(J,await a(Y),Y):{enforced:!1,value:null,field:"",bypass:!1};if(H.enforced&&!H.bypass){if(H.value==null||Array.isArray(H.value)&&H.value.length===0){let g=D$(W,x,T,0,!1,void 0);return new Response(JSON.stringify({data:[],...g,meta:Q$(W,x,T,0,!1,void 0)}),{status:200,headers:{"Content-Type":"application/json","Cache-Control":"private, no-store",Vary:"Authorization"}})}A=Array.isArray(H.value)?A.where(H.field,"in",H.value):A.where(H.field,"=",H.value)}let h=await A.limit(T+1).offset(E).get()||[],p=h.length>T,e=(p?h.slice(0,T):h).map((g)=>r(O$(g,J),Q)),V$=W.searchParams.get("include");if(V$)e=await o$(e,J,V$,E$);let LJ=W.searchParams.get("with_count")==="true",d;if(LJ)try{let g=b.selectFrom(K);if(H.enforced&&!H.bypass&&H.value!=null)g=Array.isArray(H.value)?g.where(H.field,"in",H.value):g.where(H.field,"=",H.value);let y=await g.count(),u=typeof y==="number"?y:Number(y?.count??y);if(Number.isFinite(u))d=u}catch{}let Z$={"Content-Type":"application/json"};if(d!==void 0&&!Number.isNaN(d))Z$["X-Total-Count"]=String(d);Z$["Cache-Control"]=H.enforced&&!H.bypass?"private, no-store":"public, max-age=15, must-revalidate",Z$.Vary="Authorization";let WJ=D$(W,x,T,e.length,p,d);return new Response(JSON.stringify({data:e,...WJ,meta:Q$(W,x,T,e.length,p,d)}),{status:200,headers:Z$})}catch(W){if(W instanceof n){let x={error:W.message};if(W.details!==void 0)x.details=W.details;return B(x,W.status||400)}return B({error:`Failed to fetch ${Z}`,detail:String(W)},500)}}));if(z.includes("show")&&!t("GET",`${L}/{id}`))V(m.get(`${L}/{id}`,async(Y)=>{try{let W=W$(Y.params?.id);if(W==null)return B({error:"Invalid ID parameter"},400);let x=await b.selectFrom(K).where({id:W}).executeTakeFirst();if(!x)return B({error:`${$} not found`},404);let T=new URL(Y.url);if(J.traits?.useSoftDeletes&&x.deleted_at&&T.searchParams.get("withTrashed")!=="true")return B({error:`${$} not found`},404);let E=q?await J$(J,await a(Y),Y):{enforced:!1,value:null,field:"",bypass:!1};if(E.enforced&&!E.bypass){if(E.value==null||!$$(x[E.field],E.value))return B({error:`${$} not found`},404)}let N=r(O$(x,J),Q),A=T.searchParams.get("include");if(A){let[f]=await o$([N],J,A,E$);N=f}let w=N?.updated_at||N?.created_at,I=w?`W/"${N.id}-${String(w)}"`:void 0,M=Y.headers?.get?.("if-none-match");if(I&&M&&M===I)return new Response(null,{status:304,headers:{ETag:I}});let k={"Content-Type":"application/json"};if(I)k.ETag=I;return k["Cache-Control"]=E.enforced&&!E.bypass?"private, no-store":"public, max-age=30, must-revalidate",k.Vary="Authorization",new Response(JSON.stringify({data:N}),{status:200,headers:k})}catch(W){if(W instanceof n){let x={error:W.message};if(W.details!==void 0)x.details=W.details;return B(x,W.status||400)}return B({error:`Failed to fetch ${$}`,detail:String(W)},500)}}));if(z.includes("store")&&!t("POST",L))V(m.post(L,async(Y)=>{try{let W=await I$(Y),x=N$(W,Q),T=_$(x,X),E=await a(Y);if(E){let k=await s$(J,"creating",E,Y);for(let[f,i]of Object.entries(k))if(i!==void 0&&i!==null&&T[f]===void 0)T[f]=i}if(Object.keys(T).length===0)return B({error:"No fillable fields provided"},422);let N=S$(T,J,"creating");if(!N.valid)return B({success:!1,message:"Validation failed",errors:N.errors},422);if(J.traits?.useTimestamps!==!1){let k=new Date().toISOString();T.created_at=k,T.updated_at=k}let A=await t$(T,J),w=A$(d$(A,J)),I=await b.insertInto(K).values(w).execute(),M=w;try{let k=I?.lastInsertRowid??I?.insertId??I;if(k){let f=await b.selectFrom(K).where({id:k}).executeTakeFirst();if(f)M=f}}catch{}return B({data:r(O$(M,J),Q)},201)}catch(W){let{status:x,body:T}=j$(W,$,"create");return B(T,x)}}),U);if(z.includes("update")){let Y=async(W)=>{try{let x=W$(W.params?.id);if(x==null)return B({error:"Invalid ID parameter"},400);let T=await I$(W),E=N$(T,Q),N=_$(E,X),A=await a(W);if(A){let H=await s$(J,"updating",A,W);for(let[h,p]of Object.entries(H))if(p!==void 0&&p!==null&&N[h]===void 0)N[h]=p}if(Object.keys(N).length===0)return B({error:"No fillable fields provided"},422);let w=S$(N,J,"updating");if(!w.valid)return B({success:!1,message:"Validation failed",errors:w.errors},422);let I=await b.selectFrom(K).where({id:x}).executeTakeFirst();if(!I)return B({error:`${$} not found`},404);let M=await J$(J,A,W);if(M.enforced&&!M.bypass){if(!A)return B({error:"Auth required"},401);let H=I[M.field];if(!$$(H,M.value))return B({error:`Not your ${$}`},403);let h=Object.keys(N).find((p)=>R(p)===R(M.field));if(h!==void 0&&!$$(N[h],M.value))return B({error:`Cannot reassign ${$} ownership`},403)}if(J.traits?.useTimestamps!==!1)N.updated_at=new Date().toISOString();let k=await t$(N,J),f=A$(d$(k,J));await b.updateTable(K).set(f).where({id:x}).execute();let i={...I,...f};try{let H=await b.selectFrom(K).where({id:x}).executeTakeFirst();if(H)i=H}catch{}return B({data:r(O$(i,J),Q)})}catch(x){let{status:T,body:E}=j$(x,$,"update");return B(E,T)}};if(!t("PUT",`${L}/{id}`))V(m.put(`${L}/{id}`,Y),U);if(!t("PATCH",`${L}/{id}`))V(m.patch(`${L}/{id}`,Y),U)}let D=!!J.traits?.useSoftDeletes;if(z.includes("destroy")&&!t("DELETE",`${L}/{id}`))V(m.delete(`${L}/{id}`,async(Y)=>{try{let W=W$(Y.params?.id);if(W==null)return B({error:"Invalid ID parameter"},400);let x=await b.selectFrom(K).where({id:W}).executeTakeFirst();if(!x)return B({error:`${$} not found`},404);let T=await a(Y),E=await J$(J,T,Y);if(E.enforced&&!E.bypass){if(!T)return B({error:"Auth required"},401);let N=x[E.field];if(!$$(N,E.value))return B({error:`Not your ${$}`},403)}if(D){let N=new Date().toISOString();await b.updateTable(K).set({deleted_at:N,updated_at:N}).where({id:W}).execute()}else await b.deleteFrom(K).where({id:W}).execute();return new Response(null,{status:204})}catch(W){if(W instanceof n){let x={error:W.message};if(W.details!==void 0)x.details=W.details;return B(x,W.status||400)}return B({error:`Failed to delete ${$}`,detail:String(W)},500)}}),U);if(z.includes("destroy")&&!t("POST",`${L}/bulk-delete`))V(m.post(`${L}/bulk-delete`,async(Y)=>{try{let x=(await I$(Y))?.ids;if(!Array.isArray(x)||x.length===0)return B({error:"An array of IDs is required"},422);if(x.length>100)return B({error:"Cannot delete more than 100 records at once"},422);let T=[],E=[];for(let I of x){let M=W$(I);if(M!=null)T.push(M);else E.push(I)}if(E.length>0)return B({error:"Invalid IDs in batch",invalid:E},422);let N=await a(Y),A=await J$(J,N,Y);if(A.enforced&&!A.bypass){if(!N)return B({error:"Auth required"},401);if(A.value==null)return B({error:"Caller has no ownership identity"},403);let I=await b.selectFrom(K).select(["id",A.field]).execute(),M=new Set(I.filter((f)=>$$(f[A.field],A.value)).map((f)=>String(f.id))),k=T.filter((f)=>!M.has(String(f)));if(k.length>0)return B({error:`Cannot delete ${$} you don't own`,ids:k},403)}let w=new Date().toISOString();for(let I of T)if(D)await b.updateTable(K).set({deleted_at:w,updated_at:w}).where({id:I}).execute();else await b.deleteFrom(K).where({id:I}).execute();return B({message:`Successfully deleted ${T.length} ${Z}`})}catch(W){if(W instanceof n){let x={error:W.message};if(W.details!==void 0)x.details=W.details;return B(x,W.status||400)}return B({error:`Failed to bulk delete ${Z}`,detail:String(W)},500)}}),U)}JJ=m});var GJ={};x$(GJ,{default:()=>JJ});var ZJ=s(async()=>{await OJ()});class M${data;status;headers;isOk;constructor($,J,O,G){this.data=$;this.status=J;this.headers=O;this.isOk=G}ok(){return this.status===200}created(){return this.status===201}accepted(){return this.status===202}noContent(){return this.status===204}movedPermanently(){return this.status===301}found(){return this.status===302}badRequest(){return this.status===400}unauthorized(){return this.status===401}paymentRequired(){return this.status===402}forbidden(){return this.status===403}notFound(){return this.status===404}requestTimeout(){return this.status===408}conflict(){return this.status===409}unprocessableEntity(){return this.status===422}tooManyRequests(){return this.status===429}serverError(){return this.status===500}}class C${defaultHeaders={Accept:"application/json","Content-Type":"application/json"};queryParams;bodyData;isFormData=!1;customHeaders={};attachments=[];isMultipart=!1;digestAuth;withQueryParams($){return this.queryParams=$,this}withHeaders($){return this.customHeaders={...this.customHeaders,...$},this}accept($){return this.defaultHeaders.Accept=$,this}acceptJson(){return this.accept("application/json")}withToken($){return this.customHeaders.Authorization=`Bearer ${$}`,this}withBasicAuth($,J){let O=btoa(`${$}:${J}`);return this.customHeaders.Authorization=`Basic ${O}`,this}withDigestAuth($,J){return this.digestAuth={username:$,password:J},this}withBody($){return this.bodyData=$,this}asForm(){return this.isFormData=!0,this.defaultHeaders["Content-Type"]="application/x-www-form-urlencoded",this}attach($,J,O,G){let Z=typeof J==="string"?new Blob([J],{type:G?.["Content-Type"]||"text/plain"}):J;return this.attachments.push({name:$,content:Z,filename:O,headers:G}),this.isMultipart=!0,delete this.defaultHeaders["Content-Type"],this}getHeaders(){return{...this.defaultHeaders,...this.customHeaders}}addQueryParams($){if(!this.queryParams)return $;let J=new URLSearchParams;Object.entries(this.queryParams).forEach(([Z,z])=>{if(z!=null)J.append(Z,String(z))});let O=J.toString();if(!O)return $;let G=$.includes("?");return $+(G?"&":"?")+O}async formatBody($){let J=$||this.bodyData;if(this.isMultipart){let O=new FormData;if(J)Object.entries(J).forEach(([G,Z])=>{O.append(G,String(Z))});for(let G of this.attachments)if(G.headers){let Z=G.content instanceof Blob?new Blob([G.content],{type:G.headers["Content-Type"]}):G.content;O.append(G.name,Z,G.filename)}else O.append(G.name,G.content,G.filename);return O}if(this.isFormData&&J){let O=new URLSearchParams;return Object.entries(J).forEach(([G,Z])=>{if(Z!=null)O.append(G,String(Z))}),O.toString()}return J?JSON.stringify(J):void 0}resetState(){this.queryParams=void 0,this.bodyData=void 0,this.isFormData=!1,this.isMultipart=!1,this.customHeaders={},this.attachments=[],this.digestAuth=void 0,this.defaultHeaders["Content-Type"]="application/json"}async handleDigestAuth($,J,O,G){if($.status!==401||!this.digestAuth)return $;let Z=$.headers.get("WWW-Authenticate");if(!Z?.startsWith("Digest "))return $;let z=Z.substring(7).split(",").reduce((F,_)=>{let[P,q]=_.trim().split("=");if(P)F[P]=q?.replace(/["']/g,"")??"";return F},{}),K=await this.generateMD5(`${this.digestAuth.username}:${z.realm}:${this.digestAuth.password}`),X=await this.generateMD5(`${O}:${J}`),Q="00000001",L=await this.generateMD5(Date.now().toString()).then((F)=>F.substring(0,8)),j=await this.generateMD5(`${K}:${z.nonce}:${Q}:${L}:${z.qop}:${X}`),S={username:`"${this.digestAuth.username}"`,realm:`"${z.realm}"`,nonce:`"${z.nonce}"`,uri:`"${J}"`,algorithm:z.algorithm?`"${z.algorithm}"`:void 0,qop:`"${z.qop}"`,nc:Q,cnonce:`"${L}"`,response:`"${j}"`,opaque:z.opaque?`"${z.opaque}"`:void 0},U=Object.entries(S).filter(([F,_])=>_!==void 0).map(([F,_])=>`${F}=${_}`).join(", ");return this.customHeaders.Authorization=`Digest ${U}`,fetch(J,{method:O,headers:this.getHeaders(),body:G?this.formatBody(G):void 0})}async generateMD5($){let O=new TextEncoder().encode($),G=await crypto.subtle.digest("SHA-256",O);return Array.from(new Uint8Array(G)).map((z)=>z.toString(16).padStart(2,"0")).join("")}async request($,J,O){let G=this.addQueryParams($),Z=await this.formatBody(O),z=await fetch(G,{method:J,headers:this.getHeaders(),body:Z});if(this.digestAuth)z=await this.handleDigestAuth(z,G,J,O);let K=await z.json();return this.resetState(),new M$(K,z.status,z.headers,z.ok)}async get($){return this.request($,"GET")}async post($,J){return this.request($,"POST",J)}async put($,J){return this.request($,"PUT",J)}async patch($,J){return this.request($,"PATCH",J)}async delete($){return this.request($,"DELETE")}}var uJ=new C$;B$();import{path as Y$}from"@stacksjs/path";function vJ($){if(!$||typeof $!=="object")return{type:"string"};let J=$,O=Array.isArray(J.rules)?J.rules:[],G=(j)=>O.find((S)=>S.name===j),Z=(j,S)=>{let U=G(j)?.params?.[S];return typeof U==="number"?U:void 0},z=J.name??J._type??"string",K={type:z==="enum"?"string":z},X=Z("min","min")??(typeof J._min==="number"?J._min:void 0),Q=Z("max","max")??(typeof J._max==="number"?J._max:void 0);if(X!==void 0)K[z==="string"?"minLength":"minimum"]=X;if(Q!==void 0)K[z==="string"?"maxLength":"maximum"]=Q;if(G("email")||J._email)K.format="email";if(G("url")||J._url)K.format="uri";if(G("uuid")||J._uuid)K.format="uuid";let L=Array.isArray(J.allowedValues)?J.allowedValues:Array.isArray(J._enum)?J._enum:null;if(L)K.enum=L;return K}function hJ($){if(!$||typeof $!=="object")return!1;let J=$;return Boolean(J.isRequired??J._required)}function pJ($,J){let O={...J},G=$?.responses;if(G&&typeof G==="object")for(let[z,K]of Object.entries(G)){let X=K;if(!X||typeof X!=="object"||typeof X.description!=="string")continue;O[String(z)]={description:X.description,...X.schema&&typeof X.schema==="object"?{content:{"application/json":{schema:X.schema}}}:{}}}let Z=$?.responseHeaders;if(Z&&typeof Z==="object"){let z={};for(let[K,X]of Object.entries(Z)){let Q=X;if(!Q||typeof Q!=="object"||typeof Q.description!=="string")continue;z[K]={description:Q.description,...Q.schema&&typeof Q.schema==="object"?{schema:Q.schema}:{}}}if(Object.keys(z).length>0)for(let K of Object.keys(O))O[K]={...O[K],headers:z}}return O}async function mJ($){if(typeof $!=="string"||!$||$.includes(".."))return null;try{let{path:J}=await import("@stacksjs/path"),O=[J.appPath(`${$}.ts`),J.storagePath(`framework/defaults/app/${$}.ts`)];for(let G of O)try{if(!await Bun.file(G).exists())continue;let K=(await import(G)).default;return K&&typeof K==="object"?K:null}catch{}}catch{}return null}async function XO($={}){let J=$.portable??!0,{listRegisteredRoutes:O}=await import("@stacksjs/router");try{let{loadRoutes:Q}=await import("@stacksjs/router"),{default:L}=await import(Y$.appPath("Routes.ts"));await Q(L)}catch(Q){let L=Q instanceof Error?Q.message:String(Q);if(J)throw Error(`[generateOpenApi] Refusing to emit a partial spec: failed to load routes/api.ts + framework routes: ${L}`);console.warn(`[generateOpenApi] Failed to load routes/api.ts + framework routes: ${L}`)}try{try{await import("@stacksjs/orm/routes")}catch{await ZJ().then(() => GJ)}}catch(Q){let L=Q instanceof Error?Q.message:String(Q);if(J)throw Error(`[generateOpenApi] Refusing to emit a partial spec: failed to load useApi-generated ORM routes: ${L}`);console.warn(`[generateOpenApi] Failed to load useApi-generated ORM routes: ${L}`)}let G=(Q)=>Q.replace(/(^|\/):(\w+)(?=$|\/)/g,"$1{$2}"),Z=[...O()].map((Q)=>({route:Q,oasPath:G(Q.path),method:Q.method.toLowerCase()})).sort((Q,L)=>{if(Q.oasPath!==L.oasPath)return Q.oasPath<L.oasPath?-1:1;return Q.method<L.method?-1:Q.method>L.method?1:0});if(J&&Z.length===0)throw Error("[generateOpenApi] Refusing to emit an empty spec: no routes were registered. This usually means route loading failed silently rather than that the app has no API.");let z="Stacks API";if(!J)try{let{config:Q}=await import("@stacksjs/config");if(Q.app?.name)z=`${Q.app.name} API`}catch{}let K={openapi:"3.0.0",info:{title:z,version:"1.0.0"},paths:{},components:{schemas:{}}},X=new Set;for(let{route:Q,oasPath:L,method:j}of Z){if(!K.paths[L])K.paths[L]={};let S=[];for(let C of Q.path.matchAll(/\{(\w+)\}/g))if(C[1])S.push(C[1]);for(let C of Q.path.matchAll(/(?:^|\/):(\w+)(?=$|\/)/g))if(C[1])S.push(C[1]);let U=Q.name??`${j}_${L.replace(/[^a-z0-9]/gi,"_")}`,F=U;if(X.has(F)){F=`${U}_${j}`;let C=2;while(X.has(F))F=`${U}_${j}_${C++}`}X.add(F);let _={summary:Q.name??Q.path,operationId:F,parameters:S.map((C)=>({name:C,in:"path",required:!0,schema:{type:"string"}})),responses:{200:{description:"Successful response",content:{"application/json":{schema:{type:"object"}}}},422:{description:"Validation failed"},500:{description:"Server error"}}},P=Q.handler?await mJ(Q.handler):null,q=P&&typeof P.validations==="object"&&P.validations!==null?P.validations:null;if(_.responses=pJ(P,_.responses),q&&Object.keys(q).length>0){let C=Object.entries(q).map(([V,D])=>{let Y=D?.rule;return{field:V,schema:vJ(Y),required:hJ(Y)}});if(j==="get"||j==="head"||j==="delete"){let V=new Set(S);for(let{field:D,schema:Y,required:W}of C){if(V.has(D))continue;_.parameters?.push({name:D,in:"query",required:W,schema:Y})}}else{let V={type:"object",properties:{},required:[]},D=V.properties,Y=V.required;for(let W of C)if(D[W.field]=W.schema,W.required)Y.push(W.field);if(Y.length===0)delete V.required;_.requestBody={required:Y.length>0,content:{"application/json":{schema:V}}}}}K.paths[L][j]=_}if($.write!==!1){let L=Bun.file(Y$.frameworkPath("api/openapi.json")).writer();L.write(JSON.stringify(K,null,2)),await L.end();let{renderOpenApiTypes:j}=await Promise.resolve().then(() => (z$(),R$)),{renderApiClient:S}=await Promise.resolve().then(() => (B$(),f$));await Bun.write(Y$.frameworkPath("api/api-types.ts"),j(K)),await Bun.write(Y$.frameworkPath("api/client.ts"),S(K,{name:K.info.title}))}return K}z$();class v{static instance=new v;isMissing(){return!0}}class G${data;constructor($){this.data=$}}class zJ{condition;value;defaultValue;constructor($,J,O=new v){this.condition=$;this.value=J;this.defaultValue=O}resolve(){return(typeof this.condition==="function"?this.condition():this.condition)?this.value:this.defaultValue}}class KJ{resource;additional={};request;static wrap="data";static additionalMeta={};constructor($){this.resource=$}withRequest($){return this.request=$,this}withAdditional($){return this.additional={...this.additional,...$},this}resolve($){let J=this.toArray($||this.request);return this.filterAndResolve(J)}toResponse($){let J=this.resolve($),O=this.constructor.wrap;if(O)return{[O]:J,...this.additional};return{...J,...this.additional}}toJson($){return JSON.stringify(this.toResponse($))}toJSON(){return this.toResponse()}static collection($){return new F$($,this)}when($,J,O){if(typeof $==="function"?$():$)return typeof J==="function"?J():J;return O!==void 0?O:v.instance}whenNotNull($,J){if($===null||$===void 0)return v.instance;return J?J($):$}whenLoaded($,J,O){let G=this.resource;if(!(($ in G)&&G[$]!==void 0))return O!==void 0?O:v.instance;if(J!==void 0)return typeof J==="function"?J():J;return G[$]}whenCounted($,J){let O=this.resource,G=`${$}_count`;if(G in O)return O[G];return J!==void 0?J:v.instance}merge($){return new G$($)}mergeWhen($,J){if(!(typeof $==="function"?$():$))return v.instance;let G=typeof J==="function"?J():J;return new G$(G)}static MAX_RESOLVE_DEPTH=20;filterAndResolve($,J=0){if(J>=KJ.MAX_RESOLVE_DEPTH)return $;let O={};for(let[G,Z]of Object.entries($)){if(Z instanceof v)continue;if(Z instanceof G$){Object.assign(O,this.filterAndResolve(Z.data,J+1));continue}if(Z instanceof zJ){let z=Z.resolve();if(!(z instanceof v))O[G]=z;continue}if(Z!==null&&typeof Z==="object"&&!Array.isArray(Z)&&!(Z instanceof Date)){O[G]=this.filterAndResolve(Z,J+1);continue}if(Array.isArray(Z)){O[G]=Z.filter((z)=>!(z instanceof v)).map((z)=>{if(z instanceof G$)return z.data;if(z!==null&&typeof z==="object"&&!(z instanceof Date))return this.filterAndResolve(z,J+1);return z});continue}O[G]=Z}return O}static withoutWrapping(){this.wrap=null}static wrapWith($){this.wrap=$}}class F${resources;ResourceClass;additional={};request;static wrap="data";constructor($,J){this.resources=$,this.ResourceClass=J}withRequest($){return this.request=$,this}withAdditional($){return this.additional={...this.additional,...$},this}resolve($){let J=$||this.request;return this.resources.map((O)=>{let G=new this.ResourceClass(O);if(J)G.withRequest(J);return G.resolve(J)})}toResponse($){let J=this.resolve($),O=this.constructor.wrap;if(O)return{[O]:J,...this.additional};return{data:J,...this.additional}}toJson($){return JSON.stringify(this.toResponse($))}count(){return this.resources.length}isEmpty(){return this.resources.length===0}isNotEmpty(){return this.resources.length>0}}class QJ extends F${meta;links;constructor($,J){super($.data,J);this.meta=$.meta,this.links=$.links}static fromPagination($,J,O){let{currentPage:G,perPage:Z,total:z,baseUrl:K=""}=O,X=Math.ceil(z/Z),Q=z>0?(G-1)*Z+1:null,L=z>0?Math.min(G*Z,z):null;return new QJ({data:$,meta:{current_page:G,from:Q,last_page:X,per_page:Z,to:L,total:z},links:{first:`${K}?page=1`,last:`${K}?page=${X}`,prev:G>1?`${K}?page=${G-1}`:null,next:G<X?`${K}?page=${G+1}`:null}},J)}toResponse($){return{data:this.resolve($),meta:this.meta,links:this.links,...this.additional}}}function xO($,J){let O=J($);return{toResponse:()=>({data:O}),toJson:()=>JSON.stringify({data:O})}}function BO($,J){let O=$.map(J);return{toResponse:()=>({data:O}),toJson:()=>JSON.stringify({data:O})}}export{c as schemaType,vJ as ruleToSchema,hJ as ruleIsRequired,xO as resource,_J as renderOpenApiTypes,DJ as renderApiClient,P$ as methodName,XO as generateOpenApi,uJ as fetcher,pJ as describedResponses,BO as collection,F$ as ResourceCollection,QJ as PaginatedResourceCollection,v as MissingValue,G$ as MergeValue,KJ as JsonResource,zJ as ConditionalValue};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/api",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.369",
|
|
6
6
|
"description": "The Stacks API utilities.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -62,6 +62,6 @@
|
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"better-dx": "^0.2.17",
|
|
65
|
-
"@stacksjs/utils": "0.70.
|
|
65
|
+
"@stacksjs/utils": "0.70.369"
|
|
66
66
|
}
|
|
67
67
|
}
|