diff --git a/bun.lock b/bun.lock index 47e9efbe..f4f9abc8 100644 --- a/bun.lock +++ b/bun.lock @@ -312,6 +312,9 @@ "unrs-resolver", "@parcel/watcher", ], + "patchedDependencies": { + "@prover-coder-ai/openapi-effect@1.0.27": "patches/@prover-coder-ai%2Fopenapi-effect@1.0.27.patch", + }, "overrides": { "react": "19.2.4", "react-dom": "19.2.4", diff --git a/package.json b/package.json index fe7d4725..9ac582b9 100644 --- a/package.json +++ b/package.json @@ -80,5 +80,8 @@ "url": "https://github.com/ProverCoderAI/docker-git/issues" }, "homepage": "https://github.com/ProverCoderAI/docker-git#readme", - "license": "MIT" + "license": "MIT", + "patchedDependencies": { + "@prover-coder-ai/openapi-effect@1.0.27": "patches/@prover-coder-ai%2Fopenapi-effect@1.0.27.patch" + } } diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile index d4fc30e8..82543d7d 100644 --- a/packages/api/Dockerfile +++ b/packages/api/Dockerfile @@ -76,6 +76,7 @@ RUN set -eu; \ FROM controller-base AS workspace-deps COPY package.json bun.lock bunfig.toml tsconfig.base.json tsconfig.json ./ +COPY patches ./patches RUN mkdir -p packages/api packages/app packages/auth-oauth packages/container packages/docker-git-session-sync packages/lib packages/openapi packages/terminal COPY packages/api/package.json ./packages/api/package.json COPY packages/app/package.json ./packages/app/package.json @@ -108,7 +109,6 @@ RUN set -eu; \ FROM workspace-deps AS workspace-static -COPY patches ./patches COPY scripts ./scripts COPY packages/container ./packages/container COPY packages/auth-oauth ./packages/auth-oauth diff --git a/packages/app/tests/docker-git/openapi-effect-client.test.ts b/packages/app/tests/docker-git/openapi-effect-client.test.ts index 1a9e6a82..6b6c74cf 100644 --- a/packages/app/tests/docker-git/openapi-effect-client.test.ts +++ b/packages/app/tests/docker-git/openapi-effect-client.test.ts @@ -3,6 +3,7 @@ import { createClient } from "@prover-coder-ai/docker-git-openapi" import type { ApiFailure } from "@prover-coder-ai/docker-git-openapi" import { Effect } from "effect" import * as fc from "fast-check" +import { afterEach, vi } from "vitest" import type { JsonValue } from "../../src/shared/json-schema.js" import { renderDockerGitOpenApiFailure } from "../../src/web/api-http.js" @@ -95,6 +96,11 @@ const assertOpenApiClientProperty = (property: fc.IAsyncProperty

fc.assert(property, { numRuns: 25 }) }) +afterEach(() => { + vi.restoreAllMocks() + vi.unstubAllGlobals() +}) + describe("docker-git OpenAPI Effect client", () => { it.effect("executes typed GET requests directly through openapi-effect", () => Effect.gen(function*(_) { @@ -223,4 +229,70 @@ describe("docker-git OpenAPI Effect client", () => { expect(requests[0]?.method).toBe("POST") expect(new URL(requests[0]?.url ?? "").pathname).toBe("/projects/down-all") })) + + it.effect("falls back to getRandomValues when randomUUID is unavailable", () => + Effect.gen(function*(_) { + const requests: Array = [] + const capturedIds: Array = [] + vi.stubGlobal("crypto", { + getRandomValues: (values: Uint8Array): Uint8Array => { + values.set([0x10, 0x32, 0x54, 0x76, 0x98]) + return values + } + }) + + const api = createClient({ + baseUrl: "https://docker-git.example.test", + fetch: createMockFetch( + requests, + createJsonResponse(200, { + cwd: "/workspace", + ok: true, + projectsRoot: "/workspace/projects", + revision: null + }) + ) + }) + api.use({ + onRequest: ({ id }) => { + capturedIds.push(id) + } + }) + + const success = yield* _(api.GET("/health")) + + expect(success.status).toBe(200) + expect(capturedIds).toEqual(["103254769"]) + expect(requests).toHaveLength(1) + })) + + it.effect("falls back to a clock-based request id when Web Crypto is missing", () => + Effect.gen(function*(_) { + const capturedIds: Array = [] + vi.stubGlobal("crypto", undefined) + vi.spyOn(Date, "now").mockReturnValue(0x1234567) + + const api = createClient({ + baseUrl: "https://docker-git.example.test", + fetch: createMockFetch( + [], + createJsonResponse(200, { + cwd: "/workspace", + ok: true, + projectsRoot: "/workspace/projects", + revision: null + }) + ) + }) + api.use({ + onRequest: ({ id }) => { + capturedIds.push(id) + } + }) + + const success = yield* _(api.GET("/health")) + + expect(success.status).toBe(200) + expect(capturedIds).toEqual(["123456700"]) + })) }) diff --git a/patches/@prover-coder-ai%2Fopenapi-effect@1.0.27.patch b/patches/@prover-coder-ai%2Fopenapi-effect@1.0.27.patch new file mode 100644 index 00000000..46b140eb --- /dev/null +++ b/patches/@prover-coder-ai%2Fopenapi-effect@1.0.27.patch @@ -0,0 +1,8 @@ +diff --git a/dist/index.js b/dist/index.js +index c9ae6933b8d4fe919a5147dec4d194bea3122a8a..26fa1929f3cedc3007017e13529cf03dd6270d6f 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -1,2 +1,2 @@ +-import{Effect as o}from"effect";const Xe=e=>{throw new Error(`Unexpected value: ${JSON.stringify(e)}`)},N=e=>e,x=e=>e,_=e=>e,f=e=>e instanceof Error?e:new Error(String(e)),u=e=>({_tag:"TransportError",error:f(e)}),T=e=>o.tryPromise({try:()=>e.text(),catch:u}),k=e=>e.headers.get("Transfer-Encoding")?.includes("chunked")===!0,V=(e,t,r)=>t.status===204||e.method==="HEAD"||r==="0"&&!k(t),O=e=>e?.split(";")[0]?.trim().toLowerCase(),E=(e,t)=>O(e.headers.get("content-type"))??t,J=(e,t,r,n)=>({_tag:"ParseError",status:e,contentType:t,error:f(n),body:r}),Y=(e,t)=>({_tag:"UnexpectedContentType",status:e.status,expected:["application/json"],actual:e.headers.get("content-type")??void 0,body:t}),G=(e,t)=>{const r=e.headers.get("content-type");return O(r)!=="application/json"?o.fail(Y(e,t)):t.length===0?o.void:o.try({try:()=>N(JSON.parse(t)),catch:n=>J(e.status,"application/json",t,n)})},U=(e,t)=>t.pipe(o.map(r=>({contentType:E(e,"application/octet-stream"),body:r}))),Q=e=>U(e,o.tryPromise({try:()=>e.blob(),catch:u})),K=e=>U(e,o.tryPromise({try:()=>e.arrayBuffer(),catch:u})),X=(e,t)=>t==="stream"?o.succeed({contentType:E(e,"stream"),body:e.body}):t==="text"?T(e).pipe(o.map(r=>({contentType:E(e,"text/plain"),body:r}))):t==="blob"?Q(e):t==="arrayBuffer"?K(e):T(e).pipe(o.flatMap(r=>G(e,r).pipe(o.map(n=>({contentType:"application/json",body:n}))))),Z=(e,t)=>({status:e.status,contentType:t.contentType,body:t.body}),z=e=>({_tag:"HttpError",...e}),v=(e,t,r)=>{const n=t.headers.get("Content-Length");if(V(e,t,n)){const s={status:t.status,contentType:"none",body:void 0};return t.ok?o.succeed(s):o.fail(z(s))}return X(t,r).pipe(o.flatMap(s=>{const i=Z(t,s);return t.ok?o.succeed(i):o.fail(z(i))}))},ee=e=>typeof e=="object"&&e!==null&&"then"in e&&typeof Reflect.get(e,"then")=="function",q=e=>e===void 0?o.sync(()=>{}):o.succeed(_(e)),R=e=>ee(e)?o.async(t=>{e.then(r=>{t(q(r))},r=>{t(o.fail(f(r)))})}):q(e),C=e=>{const t=[];for(let r=e.length-1;r>=0;r-=1){const n=e[r];n!==void 0&&t.push(n)}return t},S=(e,t)=>({request:e,schemaPath:t.schemaPath,params:t.params,options:t.options,id:t.id}),te=(e,t)=>o.gen(function*(){let r=e;for(const n of t.middleware){if(typeof n.onRequest!="function")continue;const s=yield*R(n.onRequest(S(r,t)));if(s!==void 0){if(s instanceof Request){r=s;continue}return s instanceof Response?{request:r,response:s}:yield*o.fail(new Error("onRequest: must return new Request() or Response() when modifying the request"))}}return{request:r}}),re=(e,t,r)=>o.gen(function*(){let n=t;for(const s of C(r.middleware)){if(typeof s.onResponse!="function")continue;const i=yield*R(s.onResponse({...S(e,r),response:n}));if(i!==void 0){if(!(i instanceof Response))return yield*o.fail(new Error("onResponse: must return new Response() when modifying the response"));n=i}}return n}),ne=e=>e===void 0||e instanceof Response||e instanceof Error?o.succeed(e):o.fail(new Error("onError: must return new Response() or instance of Error")),se=(e,t,r)=>o.gen(function*(){let n=t;for(const s of C(r.middleware)){if(typeof s.onError!="function")continue;const i=yield*R(s.onError({...S(e,r),error:n})),a=yield*ne(i);if(a instanceof Response)return a;a instanceof Error&&(n=a)}return yield*o.fail(n)}),d=e=>typeof e=="string"||typeof e=="number"||typeof e=="boolean",p=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),ie={simple:",",label:".",matrix:";",form:"&",deepObject:"&"},w={simple:{explodeFalse:",",explodeTrue:","},label:{explodeFalse:",",explodeTrue:"."},matrix:{explodeFalse:",",explodeTrue:";"},form:{explodeFalse:",",explodeTrue:"&"},spaceDelimited:{explodeFalse:"%20",explodeTrue:"&"},pipeDelimited:{explodeFalse:"|",explodeTrue:"&"}},b=(e,t)=>t?String(e):encodeURIComponent(String(e)),oe=(e,t,r)=>t==="simple"?r:t==="label"?`.${r}`:t==="matrix"?`;${e}=${r}`:`${e}=${r}`,ae=(e,t,r)=>e==="label"||e==="matrix"?`${t}${r}`:r,ce=e=>{const t=[];for(const r of e)d(r)&&t.push(r);return t},le=e=>p(e)?Object.entries(e):[],fe=(e,t,r,n,s)=>{const i=[];for(const[a,c]of Object.entries(t)){if(!d(c))continue;if(!n){i.push(a,b(c,r));continue}const l=s==="deepObject"?`${e}[${a}]`:a;i.push(y(l,c,{allowReserved:r}))}return i},ue=(e,t,r,n,s)=>{const i=[];for(const a of ce(t)){if(s&&r!=="simple"&&r!=="label"){i.push(y(e,a,{allowReserved:n}));continue}i.push(b(a,n))}return i},H=e=>{const t=e.explode?e.joinerWhenExplodeTrue:e.joinerWhenExplodeFalse,r=e.values.join(t);return e.explode?ae(e.style,e.joinerWhenExplodeTrue,r):oe(e.name,e.style,r)},y=(e,t,r)=>`${e}=${b(t,r?.allowReserved===!0)}`,M=(e,t,r)=>{if(!p(t))return"";const n=fe(e,t,r.allowReserved===!0,r.explode,r.style);return H({name:e,style:r.style,explode:r.explode,values:n,joinerWhenExplodeFalse:",",joinerWhenExplodeTrue:ie[r.style]})},I=(e,t,r)=>{if(!Array.isArray(t))return"";const n=ue(e,t,r.style,r.allowReserved===!0,r.explode);return H({name:e,style:r.style,explode:r.explode,values:n,joinerWhenExplodeFalse:w[r.style].explodeFalse,joinerWhenExplodeTrue:w[r.style].explodeTrue})},de=(e,t,r)=>{if(t!=null)return Array.isArray(t)?pe(e,t,r):ye(e,t,r)},pe=(e,t,r)=>{if(t.length!==0)return I(e,t,{style:"form",explode:!0,...r?.array,allowReserved:r?.allowReserved===!0})},ye=(e,t,r)=>{if(p(t))return M(e,t,{style:"deepObject",explode:!0,...r?.object,allowReserved:r?.allowReserved===!0});if(d(t))return y(e,t,r)},A=e=>t=>{const r=[];for(const[n,s]of le(t)){const i=de(n,s,e);i!==void 0&&r.push(i)}return r.join("&")},me=/\{[^{}]+\}/g,he=e=>{let t=e,r=!1,n="simple";return t.endsWith("*")&&(r=!0,t=t.slice(0,Math.max(0,t.length-1))),t.startsWith(".")?(n="label",t=t.slice(1)):t.startsWith(";")&&(n="matrix",t=t.slice(1)),{name:t,explode:r,style:n}},Ee=(e,t,r)=>{if(Array.isArray(t))return I(e,t,{style:r.style,explode:r.explode});if(p(t))return M(e,t,{style:r.style,explode:r.explode});if(!d(t))return;if(r.style==="matrix")return`;${y(e,t)}`;const n=encodeURIComponent(String(t));return r.style==="label"?`.${n}`:n},xe=(e,t)=>{let r=e;for(const n of e.match(me)??[]){const s=n.slice(1,-1),i=he(s),a=t[i.name];if(a==null)continue;const c=Ee(i.name,a,i);c!==void 0&&(r=r.replace(n,c))}return r},Re=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),Se=e=>{if(!Re(e))return{};const t={};for(const[r,n]of Object.entries(e))t[r]=String(n);return t},$=e=>!(e instanceof Headers)&&!Array.isArray(e),g=(e,t)=>{if(e===void 0)return;if(e instanceof Headers)return e.get(t)??void 0;if(!$(e))return;const r=e[t];if(!(r==null||Array.isArray(r)))return String(r)},be=e=>JSON.stringify(e),Te=(e,t)=>e===void 0?"":(g(t,"Content-Type")??g(t,"content-type"))==="application/x-www-form-urlencoded"?new URLSearchParams(Se(e)).toString():be(e),ze=(e,t)=>{let r=`${t.baseUrl}${e}`;t.params.path&&(r=t.pathSerializer(r,t.params.path));let n=t.querySerializer(t.params.query??{});return n.startsWith("?")&&(n=n.slice(1)),n.length>0&&(r=`${r}?${n}`),r},qe=(e,t,r)=>{if(r===null){e.delete(t);return}if(Array.isArray(r)){for(const n of r)e.append(t,String(n));return}r!==void 0&&e.set(t,String(r))},we=(e,t)=>{if(t instanceof Headers){for(const[r,n]of t.entries())e.set(r,n);return}if($(t))for(const[r,n]of Object.entries(t))qe(e,r,n)},j=(...e)=>{const t=new Headers;for(const r of e)r===void 0||typeof r!="object"||we(t,r);return t},F=e=>e.endsWith("/")?e.slice(0,Math.max(0,e.length-1)):e,Ae=()=>typeof process=="object"&&Number.parseInt(process.versions.node.slice(0,2),10)>=18&&typeof process.versions.undici=="string",ge=()=>globalThis.crypto.randomUUID().replaceAll("-","").slice(0,9),je=e=>e!==void 0&&typeof e=="object",Pe=(e,t)=>{let r=typeof e=="function"?e:A(e);return t&&(r=typeof t=="function"?t:A({...je(e)?e:{},...t})),r},P=e=>typeof e=="string"||typeof e=="number"||typeof e=="boolean",Be=e=>{if(e===void 0)return{};const t={};for(const[r,n]of Object.entries(e)){if(n==null||P(n)){t[r]=n;continue}Array.isArray(n)&&(t[r]=n.filter(s=>P(s)))}return t},Oe=e=>typeof e=="string"||e instanceof Blob||e instanceof URLSearchParams||e instanceof ArrayBuffer||e instanceof FormData||e instanceof ReadableStream,Ue=(e,t,r)=>e===void 0?{hasBody:!1}:Oe(e)?{hasBody:!0,value:e}:{hasBody:!0,value:t(e,r)},Ce=(e,t)=>{for(const r in t)r in e||Reflect.set(e,r,t[r])},B=(e,t,r)=>{const n=x(e);return o.tryPromise({try:()=>n(t,r),catch:f})},He=e=>Object.freeze({baseUrl:e.baseUrl,parseAs:e.parseAs,querySerializer:e.querySerializer,bodySerializer:e.bodySerializer,pathSerializer:e.pathSerializer,fetch:x(e.fetch)}),Me=e=>"onRequest"in e||"onResponse"in e||"onError"in e,Ie=(e,t)=>({request:(r,n,s)=>e(n,{...s,method:r.toUpperCase()}),GET:(r,n)=>e(r,{...n,method:"GET"}),PUT:(r,n)=>e(r,{...n,method:"PUT"}),POST:(r,n)=>e(r,{...n,method:"POST"}),DELETE:(r,n)=>e(r,{...n,method:"DELETE"}),OPTIONS:(r,n)=>e(r,{...n,method:"OPTIONS"}),HEAD:(r,n)=>e(r,{...n,method:"HEAD"}),PATCH:(r,n)=>e(r,{...n,method:"PATCH"}),TRACE:(r,n)=>e(r,{...n,method:"TRACE"}),use:(...r)=>{for(const n of r){if(!Me(n))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");t.push(n)}},eject:(...r)=>{for(const n of r){const s=t.indexOf(n);s!==-1&&t.splice(s,1)}}}),$e=(e,t)=>t?F(t):e,Fe=(e,t)=>t??e??Te,Le=(e,t)=>t??e??xe,We=(e,t)=>[...e,...t],De=(e,t)=>{const{Request:r=e.Request,baseUrl:n,body:s,bodySerializer:i,fetch:a=e.fetch,headers:c,middleware:l=[],params:m={},parseAs:h="json",pathSerializer:L,querySerializer:W,...D}=t??{};return{Request:r,fetch:a,parseAs:h,params:m,body:s,bodySerializer:Fe(e.bodySerializer,i),headers:c,init:D,finalBaseUrl:$e(e.baseUrl,n),pathSerializer:Le(e.pathSerializer,L),querySerializer:Pe(e.querySerializer,W),middleware:We(e.globalMiddlewares,l)}},Ne=(e,t)=>{const r=Be(t.params.header),n=Ue(t.body,t.bodySerializer,j(e.headers,t.headers,r)),s=j(!n.hasBody||n.value instanceof FormData?{}:{"Content-Type":"application/json"},e.headers,t.headers,r);return{serializedBody:n,finalHeaders:s}},_e=(e,t,r,n)=>{const s={redirect:"follow",...e.baseOptions,...r.init,...n.serializedBody.hasBody?{body:n.serializedBody.value}:{},headers:n.finalHeaders},i=new r.Request(ze(t,{baseUrl:r.finalBaseUrl,params:r.params,querySerializer:r.querySerializer,pathSerializer:r.pathSerializer}),s);return Ce(i,r.init),i},ke=(e,t)=>({schemaPath:e,params:t.params,id:ge(),options:He({baseUrl:t.finalBaseUrl,parseAs:t.parseAs,querySerializer:t.querySerializer,bodySerializer:t.bodySerializer,pathSerializer:t.pathSerializer,fetch:t.fetch}),middleware:t.middleware}),Ve=(e,t,r)=>{const n=De(e,r),s=Ne(e,n);return{request:_e(e,t,n,s),fetch:n.fetch,parseAs:n.parseAs,middleware:n.middleware,requestInitExt:e.requestInitExt,context:ke(t,n)}},Je=e=>e.middleware.length===0?B(e.fetch,e.request,e.requestInitExt).pipe(o.map(t=>({request:e.request,response:t}))):o.gen(function*(){const t=yield*te(e.request,e.context),r=t.request,n=t.response??(yield*B(e.fetch,r,e.requestInitExt).pipe(o.matchEffect({onFailure:i=>se(r,i,e.context),onSuccess:i=>o.succeed(i)}))),s=yield*re(r,n,e.context);return{request:r,response:s}}),Ye=e=>(t,r)=>o.gen(function*(){const n=Ve(e,t,r),s=yield*Je(n).pipe(o.mapError(u));return yield*v(s.request,s.response,n.parseAs)}),Ge=(e,t)=>{const{Request:r=globalThis.Request,baseUrl:n="",bodySerializer:s,fetch:i=globalThis.fetch,headers:a,pathSerializer:c,querySerializer:l,requestInitExt:m,...h}={...e};return{Request:r,baseUrl:F(n),bodySerializer:s,fetch:i,headers:a,pathSerializer:c,querySerializer:l,requestInitExt:Ae()?m:void 0,baseOptions:h,globalMiddlewares:t}},Qe=e=>{const t=[],r=Ge(e,t),n=Ye(r);return Ie(n,t)},Ze=e=>x(Qe(e));export{Xe as assertNever,Ze as createClientEffect,ze as createFinalURL,A as createQuerySerializer,Te as defaultBodySerializer,xe as defaultPathSerializer,j as mergeHeaders,F as removeTrailingSlash,I as serializeArrayParam,M as serializeObjectParam,y as serializePrimitiveParam}; ++import{Effect as i}from"effect";const st=e=>{throw new Error(`Unexpected value: ${JSON.stringify(e)}`)},J=e=>e,x=e=>e,Y=e=>e,d=e=>e instanceof Error?e:new Error(String(e)),u=e=>({_tag:"TransportError",error:d(e)}),q=e=>i.tryPromise({try:()=>e.text(),catch:u}),G=e=>e.headers.get("Transfer-Encoding")?.includes("chunked")===!0,v=(e,t,r)=>t.status===204||e.method==="HEAD"||r==="0"&&!G(t),C=e=>e?.split(";")[0]?.trim().toLowerCase(),R=(e,t)=>C(e.headers.get("content-type"))??t,Q=(e,t,r,n)=>({_tag:"ParseError",status:e,contentType:t,error:d(n),body:r}),K=(e,t)=>({_tag:"UnexpectedContentType",status:e.status,expected:["application/json"],actual:e.headers.get("content-type")??void 0,body:t}),X=(e,t)=>{const r=e.headers.get("content-type");return C(r)!=="application/json"?i.fail(K(e,t)):t.length===0?i.void:i.try({try:()=>J(JSON.parse(t)),catch:n=>Q(e.status,"application/json",t,n)})},I=(e,t)=>t.pipe(i.map(r=>({contentType:R(e,"application/octet-stream"),body:r}))),Z=e=>I(e,i.tryPromise({try:()=>e.blob(),catch:u})),ee=e=>I(e,i.tryPromise({try:()=>e.arrayBuffer(),catch:u})),te=(e,t)=>t==="stream"?i.succeed({contentType:R(e,"stream"),body:e.body}):t==="text"?q(e).pipe(i.map(r=>({contentType:R(e,"text/plain"),body:r}))):t==="blob"?Z(e):t==="arrayBuffer"?ee(e):q(e).pipe(i.flatMap(r=>X(e,r).pipe(i.map(n=>({contentType:"application/json",body:n}))))),re=(e,t)=>({status:e.status,contentType:t.contentType,body:t.body}),z=e=>({_tag:"HttpError",...e}),ne=(e,t,r)=>{const n=t.headers.get("Content-Length");if(v(e,t,n)){const o={status:t.status,contentType:"none",body:void 0};return t.ok?i.succeed(o):i.fail(z(o))}return te(t,r).pipe(i.flatMap(o=>{const s=re(t,o);return t.ok?i.succeed(s):i.fail(z(s))}))},oe=e=>typeof e=="object"&&e!==null&&"then"in e&&typeof Reflect.get(e,"then")=="function",g=e=>e===void 0?i.sync(()=>{}):i.succeed(Y(e)),b=e=>oe(e)?i.async(t=>{e.then(r=>{t(g(r))},r=>{t(i.fail(d(r)))})}):g(e),H=e=>{const t=[];for(let r=e.length-1;r>=0;r-=1){const n=e[r];n!==void 0&&t.push(n)}return t},T=(e,t)=>({request:e,schemaPath:t.schemaPath,params:t.params,options:t.options,id:t.id}),se=(e,t)=>i.gen(function*(){let r=e;for(const n of t.middleware){if(typeof n.onRequest!="function")continue;const o=yield*b(n.onRequest(T(r,t)));if(o!==void 0){if(o instanceof Request){r=o;continue}return o instanceof Response?{request:r,response:o}:yield*i.fail(new Error("onRequest: must return new Request() or Response() when modifying the request"))}}return{request:r}}),ie=(e,t,r)=>i.gen(function*(){let n=t;for(const o of H(r.middleware)){if(typeof o.onResponse!="function")continue;const s=yield*b(o.onResponse({...T(e,r),response:n}));if(s!==void 0){if(!(s instanceof Response))return yield*i.fail(new Error("onResponse: must return new Response() when modifying the response"));n=s}}return n}),ae=e=>e===void 0||e instanceof Response||e instanceof Error?i.succeed(e):i.fail(new Error("onError: must return new Response() or instance of Error")),ce=(e,t,r)=>i.gen(function*(){let n=t;for(const o of H(r.middleware)){if(typeof o.onError!="function")continue;const s=yield*b(o.onError({...T(e,r),error:n})),a=yield*ae(s);if(a instanceof Response)return a;a instanceof Error&&(n=a)}return yield*i.fail(n)}),f=e=>typeof e=="string"||typeof e=="number"||typeof e=="boolean",p=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),le={simple:",",label:".",matrix:";",form:"&",deepObject:"&"},A={simple:{explodeFalse:",",explodeTrue:","},label:{explodeFalse:",",explodeTrue:"."},matrix:{explodeFalse:",",explodeTrue:";"},form:{explodeFalse:",",explodeTrue:"&"},spaceDelimited:{explodeFalse:"%20",explodeTrue:"&"},pipeDelimited:{explodeFalse:"|",explodeTrue:"&"}},w=(e,t)=>t?String(e):encodeURIComponent(String(e)),de=(e,t,r)=>t==="simple"?r:t==="label"?`.${r}`:t==="matrix"?`;${e}=${r}`:`${e}=${r}`,ue=(e,t,r)=>e==="label"||e==="matrix"?`${t}${r}`:r,fe=e=>{const t=[];for(const r of e)f(r)&&t.push(r);return t},pe=e=>p(e)?Object.entries(e):[],ye=(e,t,r,n,o)=>{const s=[];for(const[a,c]of Object.entries(t)){if(!f(c))continue;if(!n){s.push(a,w(c,r));continue}const l=o==="deepObject"?`${e}[${a}]`:a;s.push(y(l,c,{allowReserved:r}))}return s},me=(e,t,r,n,o)=>{const s=[];for(const a of fe(t)){if(o&&r!=="simple"&&r!=="label"){s.push(y(e,a,{allowReserved:n}));continue}s.push(w(a,n))}return s},$=e=>{const t=e.explode?e.joinerWhenExplodeTrue:e.joinerWhenExplodeFalse,r=e.values.join(t);return e.explode?ue(e.style,e.joinerWhenExplodeTrue,r):de(e.name,e.style,r)},y=(e,t,r)=>`${e}=${w(t,r?.allowReserved===!0)}`,M=(e,t,r)=>{if(!p(t))return"";const n=ye(e,t,r.allowReserved===!0,r.explode,r.style);return $({name:e,style:r.style,explode:r.explode,values:n,joinerWhenExplodeFalse:",",joinerWhenExplodeTrue:le[r.style]})},F=(e,t,r)=>{if(!Array.isArray(t))return"";const n=me(e,t,r.style,r.allowReserved===!0,r.explode);return $({name:e,style:r.style,explode:r.explode,values:n,joinerWhenExplodeFalse:A[r.style].explodeFalse,joinerWhenExplodeTrue:A[r.style].explodeTrue})},he=(e,t,r)=>{if(t!=null)return Array.isArray(t)?Ee(e,t,r):Re(e,t,r)},Ee=(e,t,r)=>{if(t.length!==0)return F(e,t,{style:"form",explode:!0,...r?.array,allowReserved:r?.allowReserved===!0})},Re=(e,t,r)=>{if(p(t))return M(e,t,{style:"deepObject",explode:!0,...r?.object,allowReserved:r?.allowReserved===!0});if(f(t))return y(e,t,r)},j=e=>t=>{const r=[];for(const[n,o]of pe(t)){const s=he(n,o,e);s!==void 0&&r.push(s)}return r.join("&")},Se=/\{[^{}]+\}/g,xe=e=>{let t=e,r=!1,n="simple";return t.endsWith("*")&&(r=!0,t=t.slice(0,Math.max(0,t.length-1))),t.startsWith(".")?(n="label",t=t.slice(1)):t.startsWith(";")&&(n="matrix",t=t.slice(1)),{name:t,explode:r,style:n}},be=(e,t,r)=>{if(Array.isArray(t))return F(e,t,{style:r.style,explode:r.explode});if(p(t))return M(e,t,{style:r.style,explode:r.explode});if(!f(t))return;if(r.style==="matrix")return`;${y(e,t)}`;const n=encodeURIComponent(String(t));return r.style==="label"?`.${n}`:n},Te=(e,t)=>{let r=e;for(const n of e.match(Se)??[]){const o=n.slice(1,-1),s=xe(o),a=t[s.name];if(a==null)continue;const c=be(s.name,a,s);c!==void 0&&(r=r.replace(n,c))}return r},we=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),qe=e=>{if(!we(e))return{};const t={};for(const[r,n]of Object.entries(e))t[r]=String(n);return t},k=e=>!(e instanceof Headers)&&!Array.isArray(e),P=(e,t)=>{if(e===void 0)return;if(e instanceof Headers)return e.get(t)??void 0;if(!k(e))return;const r=e[t];if(!(r==null||Array.isArray(r)))return String(r)},ze=e=>JSON.stringify(e),ge=(e,t)=>e===void 0?"":(P(t,"Content-Type")??P(t,"content-type"))==="application/x-www-form-urlencoded"?new URLSearchParams(qe(e)).toString():ze(e),Ae=(e,t)=>{let r=`${t.baseUrl}${e}`;t.params.path&&(r=t.pathSerializer(r,t.params.path));let n=t.querySerializer(t.params.query??{});return n.startsWith("?")&&(n=n.slice(1)),n.length>0&&(r=`${r}?${n}`),r},je=(e,t,r)=>{if(r===null){e.delete(t);return}if(Array.isArray(r)){for(const n of r)e.append(t,String(n));return}r!==void 0&&e.set(t,String(r))},Pe=(e,t)=>{if(t instanceof Headers){for(const[r,n]of t.entries())e.set(r,n);return}if(k(t))for(const[r,n]of Object.entries(t))je(e,r,n)},U=(...e)=>{const t=new Headers;for(const r of e)r===void 0||typeof r!="object"||Pe(t,r);return t},D=e=>e.endsWith("/")?e.slice(0,Math.max(0,e.length-1)):e,Ue=()=>typeof process=="object"&&Number.parseInt(process.versions.node.slice(0,2),10)>=18&&typeof process.versions.undici=="string",S=9,Be=5;let E=0;const L=e=>e.slice(0,S),V=()=>"crypto"in globalThis?globalThis.crypto:void 0,Oe=()=>{const e=V();return typeof e?.randomUUID=="function"?L(e.randomUUID().replaceAll("-","")):void 0},Ce=()=>{const e=V();if(typeof e?.getRandomValues!="function")return;const t=new Uint8Array(Be);return e.getRandomValues(t),L(Array.from(t,r=>r.toString(16).padStart(2,"0")).join(""))},Ie=()=>{const e=Date.now().toString(16),t=E.toString(16).padStart(2,"0");return E=(E+1)%256,`${e}${t}`.slice(-S).padStart(S,"0")},He=()=>Oe()??Ce()??Ie(),$e=e=>e!==void 0&&typeof e=="object",Me=(e,t)=>{let r=typeof e=="function"?e:j(e);return t&&(r=typeof t=="function"?t:j({...$e(e)?e:{},...t})),r},B=e=>typeof e=="string"||typeof e=="number"||typeof e=="boolean",Fe=e=>{if(e===void 0)return{};const t={};for(const[r,n]of Object.entries(e)){if(n==null||B(n)){t[r]=n;continue}Array.isArray(n)&&(t[r]=n.filter(o=>B(o)))}return t},ke=e=>typeof e=="string"||e instanceof Blob||e instanceof URLSearchParams||e instanceof ArrayBuffer||e instanceof FormData||e instanceof ReadableStream,De=(e,t,r)=>e===void 0?{hasBody:!1}:ke(e)?{hasBody:!0,value:e}:{hasBody:!0,value:t(e,r)},Le=(e,t)=>{for(const r in t)r in e||Reflect.set(e,r,t[r])},O=(e,t,r)=>{const n=x(e);return i.tryPromise({try:()=>n(t,r),catch:d})},Ve=e=>Object.freeze({baseUrl:e.baseUrl,parseAs:e.parseAs,querySerializer:e.querySerializer,bodySerializer:e.bodySerializer,pathSerializer:e.pathSerializer,fetch:x(e.fetch)}),We=e=>"onRequest"in e||"onResponse"in e||"onError"in e,Ne=(e,t)=>({request:(r,n,o)=>e(n,{...o,method:r.toUpperCase()}),GET:(r,n)=>e(r,{...n,method:"GET"}),PUT:(r,n)=>e(r,{...n,method:"PUT"}),POST:(r,n)=>e(r,{...n,method:"POST"}),DELETE:(r,n)=>e(r,{...n,method:"DELETE"}),OPTIONS:(r,n)=>e(r,{...n,method:"OPTIONS"}),HEAD:(r,n)=>e(r,{...n,method:"HEAD"}),PATCH:(r,n)=>e(r,{...n,method:"PATCH"}),TRACE:(r,n)=>e(r,{...n,method:"TRACE"}),use:(...r)=>{for(const n of r){if(!We(n))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");t.push(n)}},eject:(...r)=>{for(const n of r){const o=t.indexOf(n);o!==-1&&t.splice(o,1)}}}),_e=(e,t)=>t?D(t):e,Je=(e,t)=>t??e??ge,Ye=(e,t)=>t??e??Te,Ge=(e,t)=>[...e,...t],ve=(e,t)=>{const{Request:r=e.Request,baseUrl:n,body:o,bodySerializer:s,fetch:a=e.fetch,headers:c,middleware:l=[],params:m={},parseAs:h="json",pathSerializer:W,querySerializer:N,..._}=t??{};return{Request:r,fetch:a,parseAs:h,params:m,body:o,bodySerializer:Je(e.bodySerializer,s),headers:c,init:_,finalBaseUrl:_e(e.baseUrl,n),pathSerializer:Ye(e.pathSerializer,W),querySerializer:Me(e.querySerializer,N),middleware:Ge(e.globalMiddlewares,l)}},Qe=(e,t)=>{const r=Fe(t.params.header),n=De(t.body,t.bodySerializer,U(e.headers,t.headers,r)),o=U(!n.hasBody||n.value instanceof FormData?{}:{"Content-Type":"application/json"},e.headers,t.headers,r);return{serializedBody:n,finalHeaders:o}},Ke=(e,t,r,n)=>{const o={redirect:"follow",...e.baseOptions,...r.init,...n.serializedBody.hasBody?{body:n.serializedBody.value}:{},headers:n.finalHeaders},s=new r.Request(Ae(t,{baseUrl:r.finalBaseUrl,params:r.params,querySerializer:r.querySerializer,pathSerializer:r.pathSerializer}),o);return Le(s,r.init),s},Xe=(e,t)=>({schemaPath:e,params:t.params,id:He(),options:Ve({baseUrl:t.finalBaseUrl,parseAs:t.parseAs,querySerializer:t.querySerializer,bodySerializer:t.bodySerializer,pathSerializer:t.pathSerializer,fetch:t.fetch}),middleware:t.middleware}),Ze=(e,t,r)=>{const n=ve(e,r),o=Qe(e,n);return{request:Ke(e,t,n,o),fetch:n.fetch,parseAs:n.parseAs,middleware:n.middleware,requestInitExt:e.requestInitExt,context:Xe(t,n)}},et=e=>e.middleware.length===0?O(e.fetch,e.request,e.requestInitExt).pipe(i.map(t=>({request:e.request,response:t}))):i.gen(function*(){const t=yield*se(e.request,e.context),r=t.request,n=t.response??(yield*O(e.fetch,r,e.requestInitExt).pipe(i.matchEffect({onFailure:s=>ce(r,s,e.context),onSuccess:s=>i.succeed(s)}))),o=yield*ie(r,n,e.context);return{request:r,response:o}}),tt=e=>(t,r)=>i.gen(function*(){const n=Ze(e,t,r),o=yield*et(n).pipe(i.mapError(u));return yield*ne(o.request,o.response,n.parseAs)}),rt=(e,t)=>{const{Request:r=globalThis.Request,baseUrl:n="",bodySerializer:o,fetch:s=globalThis.fetch,headers:a,pathSerializer:c,querySerializer:l,requestInitExt:m,...h}={...e};return{Request:r,baseUrl:D(n),bodySerializer:o,fetch:s,headers:a,pathSerializer:c,querySerializer:l,requestInitExt:Ue()?m:void 0,baseOptions:h,globalMiddlewares:t}},nt=e=>{const t=[],r=rt(e,t),n=tt(r);return Ne(n,t)},it=e=>x(nt(e));export{st as assertNever,it as createClientEffect,Ae as createFinalURL,j as createQuerySerializer,ge as defaultBodySerializer,Te as defaultPathSerializer,U as mergeHeaders,D as removeTrailingSlash,F as serializeArrayParam,M as serializeObjectParam,y as serializePrimitiveParam}; + //# sourceMappingURL=index.js.map