From 67b2bba48cb54787934ca452f8c4a4117e80187f Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:15:31 +0100 Subject: [PATCH 1/6] try with oas 3.1 --- frameworks-elysia/.gitignore | 42 + frameworks-elysia/README.md | 54 ++ frameworks-elysia/bun.lockb | Bin 0 -> 6280 bytes frameworks-elysia/openapi.yaml | 895 ++++++++++++++++++ frameworks-elysia/package.json | 21 + .../sdk-typescript/.devcontainer/README.md | 30 + .../.devcontainer/devcontainer.json | 45 + .../sdk-typescript/.devcontainer/setup.sh | 30 + .../sdk-typescript/.eslintrc.cjs | 28 + .../sdk-typescript/.gitattributes | 2 + frameworks-elysia/sdk-typescript/.gitignore | 18 + frameworks-elysia/sdk-typescript/.npmignore | 13 + .../sdk-typescript/.speakeasy/gen.lock | 171 ++++ .../sdk-typescript/.speakeasy/gen.yaml | 49 + .../sdk-typescript/.speakeasy/workflow.yaml | 16 + .../sdk-typescript/CONTRIBUTING.md | 26 + frameworks-elysia/sdk-typescript/FUNCTIONS.md | 102 ++ frameworks-elysia/sdk-typescript/README.md | 381 ++++++++ frameworks-elysia/sdk-typescript/RUNTIMES.md | 22 + frameworks-elysia/sdk-typescript/USAGE.md | 17 + .../docs/lib/utils/retryconfig.md | 24 + .../docs/models/components/id.md | 17 + .../docs/models/components/successresponse.md | 17 + .../docs/models/components/user.md | 21 + .../docs/models/errors/errorresponse.md | 16 + .../operations/deleteusersbyidrequest.md | 17 + .../models/operations/getusersbyidrequest.md | 17 + .../operations/patchusersbyidrequest.md | 21 + .../operations/patchusersbyidrequestbody.md | 18 + .../models/operations/postusersrequestbody.md | 19 + .../sdk-typescript/docs/sdks/sdk/README.md | 10 + .../sdk-typescript/docs/sdks/users/README.md | 385 ++++++++ frameworks-elysia/sdk-typescript/jsr.json | 27 + frameworks-elysia/sdk-typescript/package.json | 29 + frameworks-elysia/sdk-typescript/src/core.ts | 13 + .../src/funcs/usersDeleteUsersById.ts | 142 +++ .../sdk-typescript/src/funcs/usersGetUsers.ts | 120 +++ .../src/funcs/usersGetUsersById.ts | 142 +++ .../src/funcs/usersPatchUsersById.ts | 143 +++ .../src/funcs/usersPostUsers.ts | 136 +++ .../sdk-typescript/src/hooks/hooks.ts | 112 +++ .../sdk-typescript/src/hooks/index.ts | 6 + .../sdk-typescript/src/hooks/registration.ts | 14 + .../sdk-typescript/src/hooks/types.ts | 102 ++ frameworks-elysia/sdk-typescript/src/index.ts | 7 + .../sdk-typescript/src/lib/base64.ts | 37 + .../sdk-typescript/src/lib/config.ts | 61 ++ .../sdk-typescript/src/lib/dlv.ts | 53 ++ .../sdk-typescript/src/lib/encodings.ts | 449 +++++++++ .../sdk-typescript/src/lib/env.ts | 37 + .../sdk-typescript/src/lib/files.ts | 40 + .../sdk-typescript/src/lib/http.ts | 323 +++++++ .../sdk-typescript/src/lib/is-plain-object.ts | 43 + .../sdk-typescript/src/lib/logger.ts | 9 + .../sdk-typescript/src/lib/matchers.ts | 322 +++++++ .../sdk-typescript/src/lib/primitives.ts | 122 +++ .../sdk-typescript/src/lib/retries.ts | 219 +++++ .../sdk-typescript/src/lib/schemas.ts | 86 ++ .../sdk-typescript/src/lib/sdks.ts | 392 ++++++++ .../sdk-typescript/src/lib/security.ts | 227 +++++ .../sdk-typescript/src/lib/url.ts | 33 + .../src/models/components/id.ts | 55 ++ .../src/models/components/index.ts | 7 + .../src/models/components/successresponse.ts | 64 ++ .../src/models/components/user.ts | 64 ++ .../src/models/errors/apierror.ts | 27 + .../src/models/errors/errorresponse.ts | 73 ++ .../src/models/errors/httpclienterrors.ts | 62 ++ .../sdk-typescript/src/models/errors/index.ts | 8 + .../src/models/errors/sdkvalidationerror.ts | 97 ++ .../src/models/operations/deleteusersbyid.ts | 66 ++ .../src/models/operations/getusersbyid.ts | 66 ++ .../src/models/operations/index.ts | 8 + .../src/models/operations/patchusersbyid.ts | 141 +++ .../src/models/operations/postusers.ts | 70 ++ .../sdk-typescript/src/sdk/index.ts | 5 + .../sdk-typescript/src/sdk/sdk.ts | 13 + .../sdk-typescript/src/sdk/users.ts | 98 ++ .../sdk-typescript/src/types/blobs.ts | 31 + .../sdk-typescript/src/types/constdatetime.ts | 15 + .../sdk-typescript/src/types/enums.ts | 16 + .../sdk-typescript/src/types/fp.ts | 50 + .../sdk-typescript/src/types/index.ts | 11 + .../sdk-typescript/src/types/operations.ts | 105 ++ .../sdk-typescript/src/types/rfcdate.ts | 54 ++ .../sdk-typescript/src/types/streams.ts | 21 + .../sdk-typescript/tsconfig.json | 41 + frameworks-elysia/src/app.ts | 115 +++ frameworks-elysia/src/controllers/bookings.ts | 338 +++++++ frameworks-elysia/src/controllers/stations.ts | 73 ++ frameworks-elysia/src/controllers/trips.ts | 89 ++ .../src/generateOpenAPIDocument.ts | 31 + frameworks-elysia/src/index.ts | 3 + frameworks-elysia/src/train/data.ts | 159 ++++ frameworks-elysia/src/train/schemas.ts | 128 +++ frameworks-elysia/tsconfig.json | 103 ++ 96 files changed, 8297 insertions(+) create mode 100644 frameworks-elysia/.gitignore create mode 100644 frameworks-elysia/README.md create mode 100755 frameworks-elysia/bun.lockb create mode 100644 frameworks-elysia/openapi.yaml create mode 100644 frameworks-elysia/package.json create mode 100644 frameworks-elysia/sdk-typescript/.devcontainer/README.md create mode 100644 frameworks-elysia/sdk-typescript/.devcontainer/devcontainer.json create mode 100644 frameworks-elysia/sdk-typescript/.devcontainer/setup.sh create mode 100644 frameworks-elysia/sdk-typescript/.eslintrc.cjs create mode 100644 frameworks-elysia/sdk-typescript/.gitattributes create mode 100644 frameworks-elysia/sdk-typescript/.gitignore create mode 100644 frameworks-elysia/sdk-typescript/.npmignore create mode 100644 frameworks-elysia/sdk-typescript/.speakeasy/gen.lock create mode 100644 frameworks-elysia/sdk-typescript/.speakeasy/gen.yaml create mode 100644 frameworks-elysia/sdk-typescript/.speakeasy/workflow.yaml create mode 100644 frameworks-elysia/sdk-typescript/CONTRIBUTING.md create mode 100644 frameworks-elysia/sdk-typescript/FUNCTIONS.md create mode 100644 frameworks-elysia/sdk-typescript/README.md create mode 100644 frameworks-elysia/sdk-typescript/RUNTIMES.md create mode 100644 frameworks-elysia/sdk-typescript/USAGE.md create mode 100644 frameworks-elysia/sdk-typescript/docs/lib/utils/retryconfig.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/id.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/user.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md create mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/users/README.md create mode 100644 frameworks-elysia/sdk-typescript/jsr.json create mode 100644 frameworks-elysia/sdk-typescript/package.json create mode 100644 frameworks-elysia/sdk-typescript/src/core.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/hooks/hooks.ts create mode 100644 frameworks-elysia/sdk-typescript/src/hooks/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/hooks/registration.ts create mode 100644 frameworks-elysia/sdk-typescript/src/hooks/types.ts create mode 100644 frameworks-elysia/sdk-typescript/src/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/base64.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/config.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/dlv.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/encodings.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/env.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/files.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/http.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/is-plain-object.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/logger.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/matchers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/primitives.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/retries.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/schemas.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/sdks.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/security.ts create mode 100644 frameworks-elysia/sdk-typescript/src/lib/url.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/components/id.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/components/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/components/user.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/httpclienterrors.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/sdk.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/users.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/blobs.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/constdatetime.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/enums.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/fp.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/index.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/operations.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/rfcdate.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/streams.ts create mode 100644 frameworks-elysia/sdk-typescript/tsconfig.json create mode 100644 frameworks-elysia/src/app.ts create mode 100644 frameworks-elysia/src/controllers/bookings.ts create mode 100644 frameworks-elysia/src/controllers/stations.ts create mode 100644 frameworks-elysia/src/controllers/trips.ts create mode 100644 frameworks-elysia/src/generateOpenAPIDocument.ts create mode 100644 frameworks-elysia/src/index.ts create mode 100644 frameworks-elysia/src/train/data.ts create mode 100644 frameworks-elysia/src/train/schemas.ts create mode 100644 frameworks-elysia/tsconfig.json diff --git a/frameworks-elysia/.gitignore b/frameworks-elysia/.gitignore new file mode 100644 index 00000000..87e56100 --- /dev/null +++ b/frameworks-elysia/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +**/*.trace +**/*.zip +**/*.tar.gz +**/*.tgz +**/*.log +package-lock.json +**/*.bun \ No newline at end of file diff --git a/frameworks-elysia/README.md b/frameworks-elysia/README.md new file mode 100644 index 00000000..5a17faac --- /dev/null +++ b/frameworks-elysia/README.md @@ -0,0 +1,54 @@ +# Elysia Train Travel OpenAPI example + +This Elysia app demonstrates Speakeasy-focused OpenAPI practices using the Train Travel domain from the Bump example API. + +The sample includes resource-style endpoints for: + +- `GET /stations` +- `GET /trips` +- `GET /bookings` +- `POST /bookings` +- `GET /bookings/{bookingId}` +- `DELETE /bookings/{bookingId}` +- `POST /bookings/{bookingId}/payment` + +The OpenAPI output is generated from route metadata using `@elysia/openapi` and exported to YAML for SDK generation. + +## Prerequisites + +- Bun +- Speakeasy CLI (optional, for SDK generation) + +## Install + +```bash +bun install +``` + +## Run the server + +```bash +bun run dev +``` + +Scalar UI is available at `http://localhost:3000/openapi`. + +## Generate OpenAPI YAML + +Keep the server running, then run: + +```bash +bun run generate:openapi +``` + +This writes `openapi.yaml` in the project root. + +## Generate SDKs with Speakeasy + +```bash +speakeasy quickstart +``` + +## License + +Apache 2.0 diff --git a/frameworks-elysia/bun.lockb b/frameworks-elysia/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..319767d16319d73c3c90a01169ceb47409cb5164 GIT binary patch literal 6280 zcmeI02~bo=8i3#6fHEGSi@J)0LzJvAZw>}TkU`XF+z6=N+XX~C{+|+q0uGC^!y|tZva6MAKq+s z*t5Z2@N8G-qak?PCb&b`F9o1%LRu8@psk?G)#^*OXulTmE zvbwtMrYJu$*?LB9bz^kpQbJv} z8+#+!x#aO5?!}zW9r2^n20{3`i3feBSZbyo>j*CXYR9Rqsikq}lwkJ1C7Cgltsp&N zTwJD%pZB*D-2MzGcmW5Ov3`H;#d;Q?-~k-0hvirdG$Ao39TaB(2iDAxFb9^eUkP)* z0mX2ZJy;p@aJe^$Ib$Frc?SpA_ok1Z<8~iIW;$^2a|b5lgddoYn6n--zQDojj@7`o z`;{=K5i;JaabX^=HwCk18dxyxjy5rWz8GsEpEorr$2BE^L6&jDP(fcpSpWWuv(%&#G(p zJZ$p#VyNw?N3Hi?yf=QvC-W?=3m*LTW9_q6=}C^lW!GOfE*jI-mbfKuS>($OY1NU+ z)wQ2Ue@28zu*<@*z)>P;%_^iFqb@(!Und`+$bKiT;@T_h>@$I9WzyB_~rsT+> zL!-6VKB`{fIl^W2tE%pD$*3@wdz02Yx%(Z>;$r_ca2M_7g%4Xg-?lkgHR`8`s|jU4 zbM$4cbzN7a%Y>>Hp<4*IPP*u5@%b@wJBy3=6Jm4Ylafzfm~hv=>p|%94i0qsxK6O;Cc5r?~3fFN>~o$wQn+39$qV&?Q+b@kh<%GrIER(T4tmuzQ@GbZYj3dM`K4!%+^&dC zDO}kdRqH>h+eI#|%dpXC&)U5@yQOr%*o7=E4^J+dhaWPJc9uF=2l%#itgcOMtXx&Q zb5_!Us>2+|A;p8o*sX6Y(o|4kmkM^+#2zi(-!SY}{^9b0Zi^d~id{hou@P-7F5Cq@ ziJNEX-*%O5N%kJHW?$WLVYpxWe!D}{gZ}uu!d6#dzlN_ZzMcH|WRu(at3$)g$MHNn z%YTmDJZqsWW4n3P>>ctv78jp)2+plJQGcgJ8R?gJEXCE|>{!9vzs;*@@td4S#md&& z6u0Xu>O7n1Olg%q)-hPvz}ZkwOV@8zN(M+bn-|K37tXseL4^F=stc|yI-I6Jp;W=Z{JG4*8UI9 z!2iWcTQl$C&Wz+uRjO&dOr;|6*F3pEM^RD-vCx55rcoM&n}ftbrc%bJH465*-_>nQ zXd%&g6~q8@d%%hAVkzkMLP4{M&LH&8g5EFCy8!y&M=W&DqB{}YU#L%XpCjyF7&d+Z zxs6K_X~NLR&RR=r;?;3d}f5MWloj z69kT4;AjHWNJt?$1>zn|`~$}$%zFC4Cwoui0_liJA<+{%!LbaW!E+MKz|j&My)fel zNp~^nE+KF{1;;lGwi$GA#05t{Uf1B5433eY8Zjv%-3c8m0jx?^>4Ypd*Hu)M4M*zh z-~l!W-yV-OszI~RM-7hE;Mj>7C&P>MAVop~M|E(N1!}}#w3zh5aUL9Zff^4|>`6-A zp)(2A1*JvI+GE+XahB;*wG>T$kfNt_YME-jUZ+&Yyj7Gsh+aF2SC6CQGR$jCL=5~H zd`k2#monHuYbjYgC8JaM#+l-4w3J$=Rr0A6S%MYSGh5ytT1P z6|GOy#ZVfE;2E3-tBzMtGQB_}quu$UX~rr6LuHC_v_P)W(bEh-0pnOG6v$-BI679Z z*V5hsfsTq%(t2Ggsn#aM(WFKfgBuC>IL9~mA*qi^>q83%_&^P3`35gFp~nn>j|V9N zhl6#6&Zf~ywOl1r>I7&UQJNHmjMnp`DY+(^;wS2qe7Pn;t5H*GJ)Tp;cnyDYol>js z!`e4Az~nc|e52Q!FuYf50M~0BUxYTU39@nT0>+pz=!i||{9>{|otZX1b0(M~7$y#{ zIjA$v0;>-vmnmiAGBS>5FkMH3;mC7fDcRoqrZcmAnce8^-J)=hijI~?^|7Ko8wfh@ z$%6%Oe0d=gn9Y!kcZC|fs1F>|9JK-<5`5!HB$6OnqB>eBR~mP09~5>oz_5#a!|~-| kYF>?tl1zhkGR-#}lkP~zaJayqJWw$^X&xPj%l~cipXY_$EdT%j literal 0 HcmV?d00001 diff --git a/frameworks-elysia/openapi.yaml b/frameworks-elysia/openapi.yaml new file mode 100644 index 00000000..28663fa0 --- /dev/null +++ b/frameworks-elysia/openapi.yaml @@ -0,0 +1,895 @@ +openapi: 3.0.3 +info: + title: Train Travel API + description: API for finding and booking train trips across Europe. + version: 2.0.0 + contact: + name: Train Support + url: https://example.com/support + email: support@example.com +servers: + - url: https://api.example.com + description: Production + - url: http://localhost:3000 + description: Development server +security: + - OAuth2: + - read +components: + securitySchemes: + OAuth2: + type: oauth2 + description: OAuth 2.0 authorization code flow. + flows: + authorizationCode: + authorizationUrl: https://example.com/oauth/authorize + tokenUrl: https://example.com/oauth/token + scopes: + read: Read access + write: Write access + schemas: {} +x-speakeasy-retries: + strategy: backoff + backoff: + initialInterval: 500 + maxInterval: 60000 + maxElapsedTime: 3600000 + exponent: 1.5 + statusCodes: + - 5XX + retryConnectionErrors: true +tags: + - name: Stations + description: >- + Find and filter train stations across Europe, including their location and + local timezone. + - name: Trips + description: >- + Timetables and routes for train trips between stations, including pricing + and availability. + - name: Bookings + description: >- + Create and manage bookings for train trips, including passenger details + and optional extras. + - name: Payments + description: >- + Pay for bookings using a card or bank account, and view payment status and + history. +paths: + /stations/: + get: + operationId: get-stations + summary: Get a list of train stations + description: Returns a paginated and searchable list of all train stations. + tags: + - Stations + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + description: A train station. + type: object + properties: + id: + format: uuid + example: efdbb9d1-02c2-4bc3-afb7-6788d8782b1e + type: string + name: + example: Berlin Hauptbahnhof + type: string + address: + example: Invalidenstrasse 10557 Berlin, Germany + type: string + country_code: + example: DE + type: string + timezone: + example: Europe/Berlin + type: string + required: + - id + - name + - address + - country_code + - timezone + links: + type: object + allOf: + - type: object + properties: + self: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - self + - type: object + properties: + next: + format: uri + example: https://api.example.com/bookings?page=2 + type: string + prev: + format: uri + example: https://api.example.com/bookings?page=1 + type: string + required: + - data + - links + '400': + description: Bad Request + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: page + in: query + required: false + schema: + minimum: 1 + default: 1 + type: number + - name: limit + in: query + required: false + schema: + minimum: 1 + maximum: 100 + default: 10 + type: number + - name: coordinates + in: query + required: false + schema: + example: 52.5200,13.4050 + type: string + - name: search + in: query + required: false + schema: + example: Milano Centrale + type: string + - name: country + in: query + required: false + schema: + minLength: 2 + maxLength: 2 + example: DE + type: string + /trips/: + get: + operationId: get-trips + summary: Get available train trips + description: >- + Returns a list of available train trips between the specified origin and + destination stations on the given date. + tags: + - Trips + responses: + '200': + description: A list of available train trips + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + description: A train trip. + type: object + properties: + id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + origin: + format: uuid + example: efdbb9d1-02c2-4bc3-afb7-6788d8782b1e + type: string + destination: + format: uuid + example: b2e783e1-c824-4d63-b37a-d8d698862f1d + type: string + departure_time: + format: date-time + example: '2024-02-01T10:00:00Z' + type: string + arrival_time: + format: date-time + example: '2024-02-01T16:00:00Z' + type: string + operator: + example: Deutsche Bahn + type: string + price: + example: 50 + type: number + bicycles_allowed: + example: true + type: boolean + dogs_allowed: + example: true + type: boolean + required: + - id + - origin + - destination + - departure_time + - arrival_time + - operator + - price + - bicycles_allowed + - dogs_allowed + links: + type: object + allOf: + - type: object + properties: + self: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - self + - type: object + properties: + next: + format: uri + example: https://api.example.com/bookings?page=2 + type: string + prev: + format: uri + example: https://api.example.com/bookings?page=1 + type: string + required: + - data + - links + '400': + description: Bad Request + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: page + in: query + required: false + schema: + minimum: 1 + default: 1 + type: number + - name: limit + in: query + required: false + schema: + minimum: 1 + maximum: 100 + default: 10 + type: number + - name: origin + in: query + required: true + schema: + format: uuid + example: efdbb9d1-02c2-4bc3-afb7-6788d8782b1e + type: string + - name: destination + in: query + required: true + schema: + format: uuid + example: b2e783e1-c824-4d63-b37a-d8d698862f1d + type: string + - name: date + in: query + required: true + schema: + format: date-time + example: '2024-02-01T09:00:00Z' + type: string + - name: bicycles + in: query + required: false + schema: + default: false + type: boolean + - name: dogs + in: query + required: false + schema: + default: false + type: boolean + /bookings/: + get: + operationId: get-bookings + summary: List existing bookings + description: Returns a list of all trip bookings by the authenticated user. + tags: + - Bookings + responses: + '200': + description: A list of bookings + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + description: A booking for a train trip. + type: object + properties: + id: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog + links: + type: object + allOf: + - type: object + properties: + self: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - self + - type: object + properties: + next: + format: uri + example: https://api.example.com/bookings?page=2 + type: string + prev: + format: uri + example: https://api.example.com/bookings?page=1 + type: string + required: + - data + - links + '401': + description: Unauthorized + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + '500': + description: Internal Server Error + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: page + in: query + required: false + schema: + minimum: 1 + default: 1 + type: number + - name: limit + in: query + required: false + schema: + minimum: 1 + maximum: 100 + default: 10 + type: number + post: + operationId: create-booking + summary: Create a booking + description: >- + A booking is a temporary hold on a trip. It is not confirmed until + payment is processed. + tags: + - Bookings + security: + - OAuth2: + - write + x-speakeasy-retries: + strategy: backoff + backoff: + initialInterval: 300 + maxInterval: 40000 + maxElapsedTime: 3000000 + exponent: 1.2 + statusCodes: + - 5XX + retryConnectionErrors: true + responses: + '201': + description: Booking successful + content: + application/json: + schema: + type: object + allOf: + - description: A booking for a train trip. + type: object + properties: + id: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog + - type: object + properties: + links: + type: object + properties: + self: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - self + required: + - links + '404': + description: Not Found + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + '409': + description: Conflict + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + requestBody: + description: Booking details. + content: {} + required: true + /bookings/{bookingId}: + get: + operationId: get-booking + summary: Get a booking + description: Returns the details of a specific booking. + tags: + - Bookings + responses: + '200': + description: The booking details + content: + application/json: + schema: + type: object + allOf: + - description: A booking for a train trip. + type: object + properties: + id: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog + - type: object + properties: + links: + type: object + properties: + self: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - self + required: + - links + '404': + description: Not Found + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: bookingId + in: path + required: true + schema: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + delete: + operationId: delete-booking + summary: Delete a booking + description: Deletes a booking, cancelling the hold on the trip. + tags: + - Bookings + security: + - OAuth2: + - write + responses: + '204': + description: Booking deleted + '404': + description: Not Found + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: bookingId + in: path + required: true + schema: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + /bookings/{bookingId}/payment: + post: + operationId: create-booking-payment + summary: Pay for a booking + description: A payment attempt confirms the booking and enables ticket retrieval. + tags: + - Payments + responses: + '200': + description: Payment successful + content: + application/json: + schema: + type: object + allOf: + - type: object + properties: + id: + format: uuid + example: 2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a + type: string + amount: + example: 49.99 + type: number + currency: + example: gbp + type: string + source: + anyOf: + - type: object + properties: + object: + const: card + type: string + name: + example: J. Doe + type: string + number: + example: '4242424242424242' + type: string + cvc: + minLength: 3 + maxLength: 4 + example: '123' + type: string + exp_month: + example: 12 + type: number + exp_year: + example: 2025 + type: number + address_country: + example: gb + type: string + address_post_code: + example: N12 9XX + type: string + required: + - object + - name + - number + - cvc + - exp_month + - exp_year + - address_country + - type: object + properties: + object: + const: bank_account + type: string + name: + example: J. Doe + type: string + number: + example: '00012345' + type: string + sort_code: + example: '000123' + type: string + account_type: + anyOf: + - const: individual + type: string + - const: company + type: string + bank_name: + example: Starling Bank + type: string + country: + example: gb + type: string + required: + - object + - name + - number + - account_type + - bank_name + - country + status: + anyOf: + - const: pending + type: string + - const: succeeded + type: string + - const: failed + type: string + required: + - id + - amount + - currency + - source + - status + - type: object + properties: + links: + type: object + properties: + booking: + format: uri + example: >- + https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + required: + - booking + required: + - links + '404': + description: Not Found + content: + application/problem+json: + schema: + type: object + properties: + type: + example: https://example.com/errors/not-found + type: string + title: + example: Not Found + type: string + status: + example: 404 + type: number + detail: + example: The requested resource was not found. + type: string + required: + - type + - title + - status + - detail + parameters: + - name: bookingId + in: path + required: true + schema: + format: uuid + example: 1725ff48-ab45-4bb5-9d02-88745177dedb + type: string + requestBody: + content: {} + required: true diff --git a/frameworks-elysia/package.json b/frameworks-elysia/package.json new file mode 100644 index 00000000..6ebb2244 --- /dev/null +++ b/frameworks-elysia/package.json @@ -0,0 +1,21 @@ +{ + "name": "speakeasy-elysia-openapi-example", + "version": "2.0.0", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "bun run --watch src/index.ts", + "generate:openapi": "bun run src/generateOpenAPIDocument.ts", + "postinstall": "cd node_modules/@elysia/openapi && bun install && bun run build" + }, + "dependencies": { + "@elysiajs/cors": "^1.4.2", + "@elysia/openapi": "github:philsturgeon/elysia-openapi#feat/oas3-1", + "@types/js-yaml": "^4.0.9", + "elysia": "latest", + "js-yaml": "^4.2.0" + }, + "devDependencies": { + "bun-types": "latest" + }, + "module": "src/index.js" +} diff --git a/frameworks-elysia/sdk-typescript/.devcontainer/README.md b/frameworks-elysia/sdk-typescript/.devcontainer/README.md new file mode 100644 index 00000000..ce22244d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.devcontainer/README.md @@ -0,0 +1,30 @@ + +> **Remember to shutdown a GitHub Codespace when it is not in use!** + +# Dev Containers Quick Start + +The default location for usage snippets is the `samples` directory. + +## Running a Usage Sample + +A sample usage example has been provided in a `root.ts` file. As you work with the SDK, it's expected that you will modify these samples to fit your needs. To execute this particular snippet, use the command below. + +``` +ts-node root.ts +``` + +## Generating Additional Usage Samples + +The speakeasy CLI allows you to generate more usage snippets. Here's how: + +- To generate a sample for a specific operation by providing an operation ID, use: + +``` +speakeasy generate usage -s ./openapi.yaml -l typescript -i {INPUT_OPERATION_ID} -o ./samples +``` + +- To generate samples for an entire namespace (like a tag or group name), use: + +``` +speakeasy generate usage -s ./openapi.yaml -l typescript -n {INPUT_TAG_NAME} -o ./samples +``` diff --git a/frameworks-elysia/sdk-typescript/.devcontainer/devcontainer.json b/frameworks-elysia/sdk-typescript/.devcontainer/devcontainer.json new file mode 100644 index 00000000..4d560dd5 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.devcontainer/devcontainer.json @@ -0,0 +1,45 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/images/tree/main/src/typescript-node +{ + "name": "TypeScript", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye", + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "sudo chmod +x ./.devcontainer/setup.sh && ./.devcontainer/setup.sh", + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.vscode-typescript-tslint-plugin", + "esbenp.prettier-vscode", + "github.vscode-pull-request-github" + ], + "settings": { + "files.eol": "\n", + "editor.formatOnSave": true, + "typescript.tsc.autoDetect": "on", + "typescript.updateImportsOnFileMove.enabled": "always", + "typescript.preferences.importModuleSpecifier": "relative", + "[typescript]": { + "editor.codeActionsOnSave": { + "source.organizeImports": true + } + }, + "[typescriptreact]": { + "editor.codeActionsOnSave": { + "source.organizeImports": true + } + } + } + }, + "codespaces": { + "openFiles": [ + ".devcontainer/README.md" + ] + } + } + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh b/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh new file mode 100644 index 00000000..57f84b5b --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Install the speakeasy CLI +curl -fsSL https://raw.githubusercontent.com/speakeasy-api/speakeasy/main/install.sh | sh + +# Setup samples directory +rmdir samples || true +mkdir samples + +npm install +npm install -g ts-node +npm link +npm link sdk +TS_CONFIG_CONTENT=$(cat < samples/tsconfig.json + +# Generate starter usage sample with speakeasy +speakeasy generate usage -s ./openapi.yaml -l typescript -o samples/root.ts \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/.eslintrc.cjs b/frameworks-elysia/sdk-typescript/.eslintrc.cjs new file mode 100644 index 00000000..4d160bd2 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.eslintrc.cjs @@ -0,0 +1,28 @@ +/* eslint-env node */ +module.exports = { + root: true, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/recommended", + "plugin:import/typescript", + ], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + settings: { + "import/resolver": { + typescript: true, + node: true, + }, + }, + rules: { + // Handled by typescript compiler + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-explicit-any": "off", + "import/no-named-as-default-member": "off", + + "import/no-default-export": "error", + }, +}; diff --git a/frameworks-elysia/sdk-typescript/.gitattributes b/frameworks-elysia/sdk-typescript/.gitattributes new file mode 100644 index 00000000..113eead5 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.gitattributes @@ -0,0 +1,2 @@ +# This allows generated code to be indexed correctly +*.ts linguist-generated=false \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/.gitignore b/frameworks-elysia/sdk-typescript/.gitignore new file mode 100644 index 00000000..a15875a3 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.gitignore @@ -0,0 +1,18 @@ +/models +/models/errors +/types +/node_modules +/lib +/sdk +/funcs +/react-query +/hooks +/index.* +/core.* +/cjs +/esm +/dist +/.tsbuildinfo +/.tshy +/.tshy-* +/__tests__ diff --git a/frameworks-elysia/sdk-typescript/.npmignore b/frameworks-elysia/sdk-typescript/.npmignore new file mode 100644 index 00000000..9ad259ee --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.npmignore @@ -0,0 +1,13 @@ +**/* +!/FUNCTIONS.md +!/RUNTIMES.md +!/REACT_QUERY.md +!/**/*.ts +!/**/*.js +!/**/*.map + +/.eslintrc.js +/cjs +/.tshy +/.tshy-* +/__tests__ diff --git a/frameworks-elysia/sdk-typescript/.speakeasy/gen.lock b/frameworks-elysia/sdk-typescript/.speakeasy/gen.lock new file mode 100644 index 00000000..cce55239 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.speakeasy/gen.lock @@ -0,0 +1,171 @@ +lockVersion: 2.0.0 +id: 710ea1be-a838-453b-adf7-b1cdc6925887 +management: + docChecksum: 773a73990a00ef4f9a491ed0dd795a89 + docVersion: 1.0.50 + speakeasyVersion: 1.453.0 + generationVersion: 2.472.1 + releaseVersion: 0.0.1 + configChecksum: a476bb6ada5f4ed3b065316a0dfdd346 +features: + typescript: + additionalDependencies: 0.1.0 + core: 3.18.8 + defaultEnabledRetries: 0.1.0 + devContainers: 2.90.0 + envVarSecurityUsage: 0.1.2 + globalSecurityCallbacks: 0.1.0 + globalServerURLs: 2.82.4 + responseFormat: 0.2.3 + retries: 2.83.0 + sdkHooks: 0.2.0 +generatedFiles: + - .devcontainer/README.md + - .devcontainer/devcontainer.json + - .devcontainer/setup.sh + - .eslintrc.cjs + - .gitattributes + - .npmignore + - CONTRIBUTING.md + - FUNCTIONS.md + - RUNTIMES.md + - USAGE.md + - docs/lib/utils/retryconfig.md + - docs/models/components/id.md + - docs/models/components/successresponse.md + - docs/models/components/user.md + - docs/models/errors/errorresponse.md + - docs/models/operations/deleteusersbyidrequest.md + - docs/models/operations/getusersbyidrequest.md + - docs/models/operations/patchusersbyidrequest.md + - docs/models/operations/patchusersbyidrequestbody.md + - docs/models/operations/postusersrequestbody.md + - docs/sdks/sdk/README.md + - docs/sdks/users/README.md + - jsr.json + - package.json + - src/core.ts + - src/funcs/usersDeleteUsersById.ts + - src/funcs/usersGetUsers.ts + - src/funcs/usersGetUsersById.ts + - src/funcs/usersPatchUsersById.ts + - src/funcs/usersPostUsers.ts + - src/hooks/hooks.ts + - src/hooks/index.ts + - src/hooks/types.ts + - src/index.ts + - src/lib/base64.ts + - src/lib/config.ts + - src/lib/dlv.ts + - src/lib/encodings.ts + - src/lib/env.ts + - src/lib/files.ts + - src/lib/http.ts + - src/lib/is-plain-object.ts + - src/lib/logger.ts + - src/lib/matchers.ts + - src/lib/primitives.ts + - src/lib/retries.ts + - src/lib/schemas.ts + - src/lib/sdks.ts + - src/lib/security.ts + - src/lib/url.ts + - src/models/components/id.ts + - src/models/components/index.ts + - src/models/components/successresponse.ts + - src/models/components/user.ts + - src/models/errors/apierror.ts + - src/models/errors/errorresponse.ts + - src/models/errors/httpclienterrors.ts + - src/models/errors/index.ts + - src/models/errors/sdkvalidationerror.ts + - src/models/operations/deleteusersbyid.ts + - src/models/operations/getusersbyid.ts + - src/models/operations/index.ts + - src/models/operations/patchusersbyid.ts + - src/models/operations/postusers.ts + - src/sdk/index.ts + - src/sdk/sdk.ts + - src/sdk/users.ts + - src/types/blobs.ts + - src/types/constdatetime.ts + - src/types/enums.ts + - src/types/fp.ts + - src/types/index.ts + - src/types/operations.ts + - src/types/rfcdate.ts + - src/types/streams.ts + - tsconfig.json +examples: + getUsers: + basic: + responses: + "200": + application/json: [{"id": "1", "name": "Alice", "age": 20}, {"id": "2", "name": "Bob", "age": 25}] + Server error: + responses: + "500": + application/json: {"status": 500, "message": "There was an error"} + postUsers: + Created user: + requestBody: + application/json: {"name": "Alice", "age": 20} + responses: + "200": + application/json: {"id": "1"} + Server error: + requestBody: + application/json: {"name": "Alice", "age": 20} + responses: + "500": + application/json: {"status": 500, "message": "There was an error"} + getUsersById: + basic: + parameters: + path: + id: "1" + responses: + "200": + application/json: {"id": "1", "name": "Alice", "age": 20} + User not found: + parameters: + path: + id: "1" + responses: + "404": + application/json: {"status": 404, "message": "User not found :("} + deleteUsersById: + success: + parameters: + path: + id: "1" + responses: + "200": + application/json: {"success": true} + Invalid user: + parameters: + path: + id: "1" + responses: + "422": + application/json: {"status": 422, "message": "Invalid user"} + patchUsersById: + Success: + parameters: + path: + id: "1" + requestBody: + application/json: {"age": 21} + responses: + "200": + application/json: {"success": true} + Invalid user: + parameters: + path: + id: "1" + requestBody: + application/json: {"age": 21} + responses: + "422": + application/json: {"status": 422, "message": "Invalid user"} +generatedTests: {} diff --git a/frameworks-elysia/sdk-typescript/.speakeasy/gen.yaml b/frameworks-elysia/sdk-typescript/.speakeasy/gen.yaml new file mode 100644 index 00000000..20a9f139 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.speakeasy/gen.yaml @@ -0,0 +1,49 @@ +configVersion: 2.0.0 +generation: + devContainers: + enabled: true + schemaPath: ./openapi.yaml + sdkClassName: Sdk + maintainOpenAPIOrder: true + usageSnippets: + optionalPropertyRendering: withExample + useClassNamesForArrayFields: true + fixes: + nameResolutionDec2023: true + parameterOrderingFeb2024: true + requestResponseComponentNamesFeb2024: true + auth: + oAuth2ClientCredentialsEnabled: true + oAuth2PasswordEnabled: true +typescript: + version: 0.0.1 + additionalDependencies: + dependencies: {} + devDependencies: {} + peerDependencies: {} + additionalPackageJSON: {} + author: Speakeasy + clientServerStatusCodesAsErrors: true + defaultErrorName: APIError + enableReactQuery: false + enumFormat: union + envVarPrefix: SDK + flattenGlobalSecurity: true + flatteningOrder: parameters-first + imports: + option: openapi + paths: + callbacks: models/callbacks + errors: models/errors + operations: models/operations + shared: models/components + webhooks: models/webhooks + inputModelSuffix: input + maxMethodParams: 0 + methodArguments: require-security-and-request + moduleFormat: commonjs + outputModelSuffix: output + packageName: sdk + responseFormat: flat + templateVersion: v2 + useIndexModules: true diff --git a/frameworks-elysia/sdk-typescript/.speakeasy/workflow.yaml b/frameworks-elysia/sdk-typescript/.speakeasy/workflow.yaml new file mode 100644 index 00000000..a6fbed38 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/.speakeasy/workflow.yaml @@ -0,0 +1,16 @@ +workflowVersion: 1.0.0 +speakeasyVersion: latest +sources: + Users app documentation: + inputs: + - location: ../openapi.yaml + registry: + location: registry.speakeasyapi.dev/ritza-rzx/ritza/users-app-documentation +targets: + sdk: + target: typescript + source: Users app documentation + codeSamples: + registry: + location: registry.speakeasyapi.dev/ritza-rzx/ritza/users-app-documentation-typescript-code-samples + blocking: false diff --git a/frameworks-elysia/sdk-typescript/CONTRIBUTING.md b/frameworks-elysia/sdk-typescript/CONTRIBUTING.md new file mode 100644 index 00000000..d585717f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to This Repository + +Thank you for your interest in contributing to this repository. Please note that this repository contains generated code. As such, we do not accept direct changes or pull requests. Instead, we encourage you to follow the guidelines below to report issues and suggest improvements. + +## How to Report Issues + +If you encounter any bugs or have suggestions for improvements, please open an issue on GitHub. When reporting an issue, please provide as much detail as possible to help us reproduce the problem. This includes: + +- A clear and descriptive title +- Steps to reproduce the issue +- Expected and actual behavior +- Any relevant logs, screenshots, or error messages +- Information about your environment (e.g., operating system, software versions) + - For example can be collected using the `npx envinfo` command from your terminal if you have Node.js installed + +## Issue Triage and Upstream Fixes + +We will review and triage issues as quickly as possible. Our goal is to address bugs and incorporate improvements in the upstream source code. Fixes will be included in the next generation of the generated code. + +## Contact + +If you have any questions or need further assistance, please feel free to reach out by opening an issue. + +Thank you for your understanding and cooperation! + +The Maintainers diff --git a/frameworks-elysia/sdk-typescript/FUNCTIONS.md b/frameworks-elysia/sdk-typescript/FUNCTIONS.md new file mode 100644 index 00000000..1ba29420 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/FUNCTIONS.md @@ -0,0 +1,102 @@ +# Standalone Functions + +> [!NOTE] +> This section is useful if you are using a bundler and targetting browsers and +> runtimes where the size of an application affects performance and load times. + +Every method in this SDK is also available as a standalone function. This +alternative API is suitable when targetting the browser or serverless runtimes +and using a bundler to build your application since all unused functionality +will be tree-shaken away. This includes code for unused methods, Zod schemas, +encoding helpers and response handlers. The result is dramatically smaller +impact on the application's final bundle size which grows very slowly as you use +more and more functionality from this SDK. + +Calling methods through the main SDK class remains a valid and generally more +more ergonomic option. Standalone functions represent an optimisation for a +specific category of applications. + +## Example + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersGetUsers } from "sdk/funcs/usersGetUsers.js"; +import { SDKValidationError } from "sdk/models/errors/sdkvalidationerror.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersGetUsers(sdk); + + switch (true) { + case res.ok: + // The success case will be handled outside of the switch block + break; + case res.error instanceof SDKValidationError: + // Pretty-print validation errors. + return console.log(res.error.pretty()); + case res.error instanceof Error: + return console.log(res.error); + default: + // TypeScript's type checking will fail on the following line if the above + // cases were not exhaustive. + res.error satisfies never; + throw new Error("Assertion failed: expected error checks to be exhaustive: " + res.error); + } + + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +## Result types + +Standalone functions differ from SDK methods in that they return a +`Result` type to capture _known errors_ and document them using +the type system. By avoiding throwing errors, application code maintains clear +control flow and error-handling become part of the regular flow of application +code. + +> We use the term "known errors" because standalone functions, and JavaScript +> code in general, can still throw unexpected errors such as `TypeError`s, +> `RangeError`s and `DOMException`s. Exhaustively catching all errors may be +> something this SDK addresses in the future. Nevertheless, there is still a lot +> of benefit from capturing most errors and turning them into values. + +The second reason for this style of programming is because these functions will +typically be used in front-end applications where exception throwing is +sometimes discouraged or considered unidiomatic. React and similar ecosystems +and libraries tend to promote this style of programming so that components +render useful content under all states (loading, success, error and so on). + +The general pattern when calling standalone functions looks like this: + +```typescript +import { Core } from ""; +import { fetchSomething } from "/funcs/fetchSomething.js"; + +const client = new Core(); + +async function run() { + const result = await fetchSomething(client, { id: "123" }); + if (!result.ok) { + // You can throw the error or handle it. It's your choice now. + throw result.error; + } + + console.log(result.value); +} + +run(); +``` + +Notably, `result.error` above will have an explicit type compared to a try-catch +variation where the error in the catch block can only be of type `unknown` (or +`any` depending on your TypeScript settings). \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/README.md b/frameworks-elysia/sdk-typescript/README.md new file mode 100644 index 00000000..9cc0e975 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/README.md @@ -0,0 +1,381 @@ +# sdk + +Developer-friendly & type-safe Typescript SDK specifically catered to leverage *sdk* API. + +
+ + + + +
+ + +

+> [!IMPORTANT] +> This SDK is not yet ready for production use. To complete setup please follow the steps outlined in your [workspace](https://app.speakeasy.com/org/ritza-rzx/ritza). Delete this section before > publishing to a package manager. + + +## Summary + +Users app documentation: Development documentation + +For more information about the API: [Find out more about the Users API](www.example.com) + + + +## Table of Contents + +* [sdk](#sdk) + * [SDK Installation](#sdk-installation) + * [Requirements](#requirements) + * [SDK Example Usage](#sdk-example-usage) + * [Available Resources and Operations](#available-resources-and-operations) + * [Standalone functions](#standalone-functions) + * [Retries](#retries) + * [Error Handling](#error-handling) + * [Server Selection](#server-selection) + * [Custom HTTP Client](#custom-http-client) + * [Debugging](#debugging) +* [Development](#development) + * [Maturity](#maturity) + * [Contributions](#contributions) + + + + +## SDK Installation + +The SDK can be installed with either [npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/), [bun](https://bun.sh/) or [yarn](https://classic.yarnpkg.com/en/) package managers. + +### NPM + +```bash +npm add +``` + +### PNPM + +```bash +pnpm add +``` + +### Bun + +```bash +bun add +``` + +### Yarn + +```bash +yarn add zod + +# Note that Yarn does not install peer dependencies automatically. You will need +# to install zod as shown above. +``` + + + +## Requirements + +For supported JavaScript runtimes, please consult [RUNTIMES.md](RUNTIMES.md). + + + +## SDK Example Usage + +### Example + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); +} + +run(); + +``` + + + +## Available Resources and Operations + +
+Available methods + + +### [users](docs/sdks/users/README.md) + +* [getUsers](docs/sdks/users/README.md#getusers) - Get all users +* [postUsers](docs/sdks/users/README.md#postusers) - Create user +* [getUsersById](docs/sdks/users/README.md#getusersbyid) - Get user +* [deleteUsersById](docs/sdks/users/README.md#deleteusersbyid) - Delete user +* [patchUsersById](docs/sdks/users/README.md#patchusersbyid) - Update user + +
+ + + +## Standalone functions + +All the methods listed above are available as standalone functions. These +functions are ideal for use in applications running in the browser, serverless +runtimes or other environments where application bundle size is a primary +concern. When using a bundler to build your application, all unused +functionality will be either excluded from the final bundle or tree-shaken away. + +To read more about standalone functions, check [FUNCTIONS.md](./FUNCTIONS.md). + +
+ +Available standalone functions + +- [`usersDeleteUsersById`](docs/sdks/users/README.md#deleteusersbyid) - Delete user +- [`usersGetUsers`](docs/sdks/users/README.md#getusers) - Get all users +- [`usersGetUsersById`](docs/sdks/users/README.md#getusersbyid) - Get user +- [`usersPatchUsersById`](docs/sdks/users/README.md#patchusersbyid) - Update user +- [`usersPostUsers`](docs/sdks/users/README.md#postusers) - Create user + +
+ + + +## Retries + +Some of the endpoints in this SDK support retries. If you use the SDK without any configuration, it will fall back to the default retry strategy provided by the API. However, the default retry strategy can be overridden on a per-operation basis, or across the entire SDK. + +To change the default retry strategy for a single API call, simply provide a retryConfig object to the call: +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.getUsers({ + retries: { + strategy: "backoff", + backoff: { + initialInterval: 1, + maxInterval: 50, + exponent: 1.1, + maxElapsedTime: 100, + }, + retryConnectionErrors: false, + }, + }); + + // Handle the result + console.log(result); +} + +run(); + +``` + +If you'd like to override the default retry strategy for all operations that support retries, you can provide a retryConfig at SDK initialization: +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + retryConfig: { + strategy: "backoff", + backoff: { + initialInterval: 1, + maxInterval: 50, + exponent: 1.1, + maxElapsedTime: 100, + }, + retryConnectionErrors: false, + }, +}); + +async function run() { + const result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); +} + +run(); + +``` + + + +## Error Handling + +All SDK methods return a response object or throw an error. By default, an API error will throw a `errors.APIError`. + +If a HTTP request fails, an operation my also throw an error from the `models/errors/httpclienterrors.ts` module: + +| HTTP Client Error | Description | +| ---------------------------------------------------- | ---------------------------------------------------- | +| RequestAbortedError | HTTP request was aborted by the client | +| RequestTimeoutError | HTTP request timed out due to an AbortSignal signal | +| ConnectionError | HTTP client was unable to make a request to a server | +| InvalidRequestError | Any input used to create a request is invalid | +| UnexpectedClientError | Unrecognised or unexpected error | + +In addition, when custom error responses are specified for an operation, the SDK may throw their associated Error type. You can refer to respective *Errors* tables in SDK docs for more details on possible error types for each operation. For example, the `getUsers` method may throw the following errors: + +| Error Type | Status Code | Content Type | +| -------------------- | ----------- | ---------------- | +| errors.ErrorResponse | 500 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | + +```typescript +import { SDK } from "sdk"; +import { ErrorResponse, SDKValidationError } from "sdk/models/errors"; + +const sdk = new SDK(); + +async function run() { + let result; + try { + result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); + } catch (err) { + switch (true) { + case (err instanceof SDKValidationError): { + // Validation errors can be pretty-printed + console.error(err.pretty()); + // Raw value may also be inspected + console.error(err.rawValue); + return; + } + case (err instanceof ErrorResponse): { + // Handle err.data$: ErrorResponseData + console.error(err); + return; + } + default: { + throw err; + } + } + } +} + +run(); + +``` + +Validation errors can also occur when either method arguments or data returned from the server do not match the expected format. The `SDKValidationError` that is thrown as a result will capture the raw value that failed validation in an attribute called `rawValue`. Additionally, a `pretty()` method is available on this error that can be used to log a nicely formatted string since validation errors can list many issues and the plain error string may be difficult read when debugging. + + + +## Server Selection + +### Override Server URL Per-Client + +The default server can also be overridden globally by passing a URL to the `serverURL: string` optional parameter when initializing the SDK client instance. For example: +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + serverURL: "http://localhost:3000/", +}); + +async function run() { + const result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); +} + +run(); + +``` + + + +## Custom HTTP Client + +The TypeScript SDK makes API calls using an `HTTPClient` that wraps the native +[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). This +client is a thin wrapper around `fetch` and provides the ability to attach hooks +around the request lifecycle that can be used to modify the request or handle +errors and response. + +The `HTTPClient` constructor takes an optional `fetcher` argument that can be +used to integrate a third-party HTTP client or when writing tests to mock out +the HTTP client and feed in fixtures. + +The following example shows how to use the `"beforeRequest"` hook to to add a +custom header and a timeout to requests and how to use the `"requestError"` hook +to log errors: + +```typescript +import { SDK } from "sdk"; +import { HTTPClient } from "sdk/lib/http"; + +const httpClient = new HTTPClient({ + // fetcher takes a function that has the same signature as native `fetch`. + fetcher: (request) => { + return fetch(request); + } +}); + +httpClient.addHook("beforeRequest", (request) => { + const nextRequest = new Request(request, { + signal: request.signal || AbortSignal.timeout(5000) + }); + + nextRequest.headers.set("x-custom-header", "custom value"); + + return nextRequest; +}); + +httpClient.addHook("requestError", (error, request) => { + console.group("Request Error"); + console.log("Reason:", `${error}`); + console.log("Endpoint:", `${request.method} ${request.url}`); + console.groupEnd(); +}); + +const sdk = new SDK({ httpClient }); +``` + + + +## Debugging + +You can setup your SDK to emit debug logs for SDK requests and responses. + +You can pass a logger that matches `console`'s interface as an SDK option. + +> [!WARNING] +> Beware that debug logging will reveal secrets, like API tokens in headers, in log messages printed to a console or files. It's recommended to use this feature only during local development and not in production. + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ debugLogger: console }); +``` + +You can also enable a default debug logger by setting an environment variable `SDK_DEBUG` to true. + + + + +# Development + +## Maturity + +This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage +to a specific package version. This way, you can install the same version each time without breaking changes unless you are intentionally +looking for the latest version. + +## Contributions + +While we value open-source contributions to this SDK, this library is generated programmatically. Any manual changes added to internal files will be overwritten on the next generation. +We look forward to hearing your feedback. Feel free to open a PR or an issue with a proof of concept and we'll do our best to include it in a future release. + +### SDK Created by [Speakeasy](https://www.speakeasy.com/?utm_source=sdk&utm_campaign=typescript) diff --git a/frameworks-elysia/sdk-typescript/RUNTIMES.md b/frameworks-elysia/sdk-typescript/RUNTIMES.md new file mode 100644 index 00000000..d08a0c07 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/RUNTIMES.md @@ -0,0 +1,22 @@ +# Supported JavaScript runtimes + +This SDK is intended to be used in JavaScript runtimes that support the following features: + +* [Web Fetch API][web-fetch] +* [Web Streams API][web-streams] and in particular `ReadableStream` +* [Async iterables][async-iter] using `Symbol.asyncIterator` + +[web-fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API +[web-streams]: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API +[async-iter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols + +Runtime environments that are explicitly supported are: + +- Evergreen browsers which include: Chrome, Safari, Edge, Firefox +- Node.js active and maintenance LTS releases + - Currently, this is v18 and v20 +- Bun v1 and above +- Deno v1.39 + - Note that Deno does not currently have native support for streaming file uploads backed by the filesystem ([issue link][deno-file-streaming]) + +[deno-file-streaming]: https://github.com/denoland/deno/issues/11018 diff --git a/frameworks-elysia/sdk-typescript/USAGE.md b/frameworks-elysia/sdk-typescript/USAGE.md new file mode 100644 index 00000000..d24de951 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/USAGE.md @@ -0,0 +1,17 @@ + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); +} + +run(); + +``` + \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/lib/utils/retryconfig.md b/frameworks-elysia/sdk-typescript/docs/lib/utils/retryconfig.md new file mode 100644 index 00000000..08f95f45 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/lib/utils/retryconfig.md @@ -0,0 +1,24 @@ +# RetryConfig + +Allows customizing the default retry configuration. It is only permitted in methods that accept retry policies. + +## Fields + +| Name | Type | Description | Example | +| ------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------ | ----------- | +| `strategy` | `"backoff" | "none"` | The retry strategy to use. | `"backoff"` | +| `backoff` | [BackoffStrategy](#backoffstrategy) | When strategy is "backoff", this configurates for the backoff parameters. | | +| `retryConnectionErrors` | `*boolean*` | When strategy is "backoff", this determines whether or not to retry on connection errors. | `true` | + +## BackoffStrategy + +The backoff strategy allows retrying a request with an exponential backoff between each retry. + +### Fields + +| Name | Type | Description | Example | +| ------------------ | ------------ | ----------------------------------------- | -------- | +| `initialInterval` | `*number*` | The initial interval in milliseconds. | `500` | +| `maxInterval` | `*number*` | The maximum interval in milliseconds. | `60000` | +| `exponent` | `*number*` | The exponent to use for the backoff. | `1.5` | +| `maxElapsedTime` | `*number*` | The maximum elapsed time in milliseconds. | `300000` | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/id.md b/frameworks-elysia/sdk-typescript/docs/models/components/id.md new file mode 100644 index 00000000..00405d3f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/components/id.md @@ -0,0 +1,17 @@ +# Id + +## Example Usage + +```typescript +import { Id } from "sdk/models/components"; + +let value: Id = { + id: "1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md b/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md new file mode 100644 index 00000000..39b5825f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md @@ -0,0 +1,17 @@ +# SuccessResponse + +## Example Usage + +```typescript +import { SuccessResponse } from "sdk/models/components"; + +let value: SuccessResponse = { + success: true, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `success` | *boolean* | :heavy_check_mark: | N/A | true | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/user.md b/frameworks-elysia/sdk-typescript/docs/models/components/user.md new file mode 100644 index 00000000..3f29da87 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/components/user.md @@ -0,0 +1,21 @@ +# User + +## Example Usage + +```typescript +import { User } from "sdk/models/components"; + +let value: User = { + id: "1", + name: "Alice", + age: 20, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1 | +| `name` | *string* | :heavy_check_mark: | N/A | Alice | +| `age` | *number* | :heavy_check_mark: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md b/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md new file mode 100644 index 00000000..11a01f62 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md @@ -0,0 +1,16 @@ +# ErrorResponse + +## Example Usage + +```typescript +import { ErrorResponse } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `message` | *string* | :heavy_check_mark: | N/A | User not found :( | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md new file mode 100644 index 00000000..63293192 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md @@ -0,0 +1,17 @@ +# DeleteUsersByIdRequest + +## Example Usage + +```typescript +import { DeleteUsersByIdRequest } from "sdk/models/operations"; + +let value: DeleteUsersByIdRequest = { + id: "1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md new file mode 100644 index 00000000..3291d6b4 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md @@ -0,0 +1,17 @@ +# GetUsersByIdRequest + +## Example Usage + +```typescript +import { GetUsersByIdRequest } from "sdk/models/operations"; + +let value: GetUsersByIdRequest = { + id: "1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md new file mode 100644 index 00000000..acbcd606 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md @@ -0,0 +1,21 @@ +# PatchUsersByIdRequest + +## Example Usage + +```typescript +import { PatchUsersByIdRequest } from "sdk/models/operations"; + +let value: PatchUsersByIdRequest = { + id: "1", + requestBody: { + age: 21, + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `id` | *string* | :heavy_check_mark: | N/A | 1 | +| `requestBody` | [operations.PatchUsersByIdRequestBody](../../models/operations/patchusersbyidrequestbody.md) | :heavy_check_mark: | N/A | {
"age": 21
} | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md new file mode 100644 index 00000000..d4ccc987 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md @@ -0,0 +1,18 @@ +# PatchUsersByIdRequestBody + +## Example Usage + +```typescript +import { PatchUsersByIdRequestBody } from "sdk/models/operations"; + +let value: PatchUsersByIdRequestBody = { + age: 21, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `name` | *string* | :heavy_minus_sign: | N/A | Alice | +| `age` | *number* | :heavy_minus_sign: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md new file mode 100644 index 00000000..111238b1 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md @@ -0,0 +1,19 @@ +# PostUsersRequestBody + +## Example Usage + +```typescript +import { PostUsersRequestBody } from "sdk/models/operations"; + +let value: PostUsersRequestBody = { + name: "Alice", + age: 20, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `name` | *string* | :heavy_check_mark: | N/A | Alice | +| `age` | *number* | :heavy_check_mark: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md new file mode 100644 index 00000000..7480e820 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md @@ -0,0 +1,10 @@ +# SDK + +## Overview + +Users app documentation: Development documentation + +Find out more about the Users API + + +### Available Operations diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/users/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/users/README.md new file mode 100644 index 00000000..6c8e00bc --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/sdks/users/README.md @@ -0,0 +1,385 @@ +# Users +(*users*) + +## Overview + +Users operations + +Find more info here + + +### Available Operations + +* [getUsers](#getusers) - Get all users +* [postUsers](#postusers) - Create user +* [getUsersById](#getusersbyid) - Get user +* [deleteUsersById](#deleteusersbyid) - Delete user +* [patchUsersById](#patchusersbyid) - Update user + +## getUsers + +Get all users from the database + +### Example Usage + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.getUsers(); + + // Handle the result + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersGetUsers } from "sdk/funcs/usersGetUsers.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersGetUsers(sdk); + + if (!res.ok) { + throw res.error; + } + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[components.User[]](../../models/.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| -------------------- | -------------------- | -------------------- | +| errors.ErrorResponse | 500 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | + +## postUsers + +Add user to the database + +### Example Usage + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.postUsers({ + name: "Alice", + age: 20, + }); + + // Handle the result + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersPostUsers } from "sdk/funcs/usersPostUsers.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersPostUsers(sdk, { + name: "Alice", + age: 20, + }); + + if (!res.ok) { + throw res.error; + } + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.PostUsersRequestBody](../../models/operations/postusersrequestbody.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[components.Id](../../models/components/id.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| -------------------- | -------------------- | -------------------- | +| errors.ErrorResponse | 500 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | + +## getUsersById + +Get user by id from the database + +### Example Usage + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.getUsersById({ + id: "1", + }); + + // Handle the result + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersGetUsersById } from "sdk/funcs/usersGetUsersById.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersGetUsersById(sdk, { + id: "1", + }); + + if (!res.ok) { + throw res.error; + } + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.GetUsersByIdRequest](../../models/operations/getusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[components.User](../../models/components/user.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| -------------------- | -------------------- | -------------------- | +| errors.ErrorResponse | 404 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | + +## deleteUsersById + +Delete user by id from the database + +### Example Usage + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.deleteUsersById({ + id: "1", + }); + + // Handle the result + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersDeleteUsersById } from "sdk/funcs/usersDeleteUsersById.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersDeleteUsersById(sdk, { + id: "1", + }); + + if (!res.ok) { + throw res.error; + } + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.DeleteUsersByIdRequest](../../models/operations/deleteusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[components.SuccessResponse](../../models/components/successresponse.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| -------------------- | -------------------- | -------------------- | +| errors.ErrorResponse | 422 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | + +## patchUsersById + +Update user by id from the database + +### Example Usage + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK(); + +async function run() { + const result = await sdk.users.patchUsersById({ + id: "1", + requestBody: { + age: 21, + }, + }); + + // Handle the result + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { usersPatchUsersById } from "sdk/funcs/usersPatchUsersById.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore(); + +async function run() { + const res = await usersPatchUsersById(sdk, { + id: "1", + requestBody: { + age: 21, + }, + }); + + if (!res.ok) { + throw res.error; + } + + const { value: result } = res; + + // Handle the result + console.log(result); +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.PatchUsersByIdRequest](../../models/operations/patchusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[components.SuccessResponse](../../models/components/successresponse.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| -------------------- | -------------------- | -------------------- | +| errors.ErrorResponse | 422 | application/json | +| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/jsr.json b/frameworks-elysia/sdk-typescript/jsr.json new file mode 100644 index 00000000..f347e0ff --- /dev/null +++ b/frameworks-elysia/sdk-typescript/jsr.json @@ -0,0 +1,27 @@ + + +{ + "name": "sdk", + "version": "0.0.1", + "exports": { + ".": "./src/index.ts", + "./models/errors": "./src/models/errors/index.ts", + "./models/components": "./src/models/components/index.ts", + "./models/operations": "./src/models/operations/index.ts", + "./lib/config": "./src/lib/config.ts", + "./lib/http": "./src/lib/http.ts", + "./lib/retries": "./src/lib/retries.ts", + "./lib/sdks": "./src/lib/sdks.ts", + "./types": "./src/types/index.ts" + }, + "publish": { + "include": [ + "LICENSE", + "README.md", + "RUNTIMES.md", + "USAGE.md", + "jsr.json", + "src/**/*.ts" + ] + } +} diff --git a/frameworks-elysia/sdk-typescript/package.json b/frameworks-elysia/sdk-typescript/package.json new file mode 100644 index 00000000..adda5bda --- /dev/null +++ b/frameworks-elysia/sdk-typescript/package.json @@ -0,0 +1,29 @@ +{ + "name": "sdk", + "version": "0.0.1", + "author": "Speakeasy", + "main": "./index.js", + "sideEffects": false, + "scripts": { + "lint": "eslint --max-warnings=0 src", + "build": "tsc", + "prepublishOnly": "npm run build" + }, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19", + "zod": ">= 3" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^7.7.1", + "@typescript-eslint/parser": "^7.7.1", + "eslint": "^8.57.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "typescript": "^5.4.5", + "zod": "^3.23.4" + }, + "dependencies": { + + } +} diff --git a/frameworks-elysia/sdk-typescript/src/core.ts b/frameworks-elysia/sdk-typescript/src/core.ts new file mode 100644 index 00000000..c4486e4a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/core.ts @@ -0,0 +1,13 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { ClientSDK } from "./lib/sdks.js"; + +/** + * A minimal client to use when calling standalone SDK functions. Typically, an + * instance of this class would be instantiated once at the start of an + * application and passed around through some dependency injection mechanism to + * parts of an application that need to make SDK calls. + */ +export class SDKCore extends ClientSDK {} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts new file mode 100644 index 00000000..031eee76 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts @@ -0,0 +1,142 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeSimple } from "../lib/encodings.js"; +import * as M from "../lib/matchers.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../models/components/index.js"; +import { APIError } from "../models/errors/apierror.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Delete user + * + * @remarks + * Delete user by id from the database + */ +export async function usersDeleteUsersById( + client: SDKCore, + request: operations.DeleteUsersByIdRequest, + options?: RequestOptions, +): Promise< + Result< + components.SuccessResponse, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const parsed = safeParse( + request, + (value) => operations.DeleteUsersByIdRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return parsed; + } + const payload = parsed.value; + const body = null; + + const pathParams = { + id: encodeSimple("id", payload.id, { + explode: false, + charEncoding: "percent", + }), + }; + + const path = pathToFunc("/users/{id}")(pathParams); + + const headers = new Headers({ + Accept: "application/json", + }); + + const context = { + operationID: "deleteUsersById", + oAuth2Scopes: [], + + resolvedSecurity: null, + + securitySource: null, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + method: "DELETE", + path: path, + headers: headers, + body: body, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: ["422", "4XX", "5XX"], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + components.SuccessResponse, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json(200, components.SuccessResponse$inboundSchema), + M.jsonErr(422, errors.ErrorResponse$inboundSchema), + M.fail(["4XX", "5XX"]), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts new file mode 100644 index 00000000..e08f2964 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts @@ -0,0 +1,120 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { SDKCore } from "../core.js"; +import * as M from "../lib/matchers.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../models/components/index.js"; +import { APIError } from "../models/errors/apierror.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import { Result } from "../types/fp.js"; + +/** + * Get all users + * + * @remarks + * Get all users from the database + */ +export async function usersGetUsers( + client: SDKCore, + options?: RequestOptions, +): Promise< + Result< + Array, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const path = pathToFunc("/users/")(); + + const headers = new Headers({ + Accept: "application/json", + }); + + const context = { + operationID: "getUsers", + oAuth2Scopes: [], + + resolvedSecurity: null, + + securitySource: null, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + method: "GET", + path: path, + headers: headers, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: ["4XX", "500", "5XX"], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + Array, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json(200, z.array(components.User$inboundSchema)), + M.jsonErr(500, errors.ErrorResponse$inboundSchema), + M.fail(["4XX", "5XX"]), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts new file mode 100644 index 00000000..500e7997 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts @@ -0,0 +1,142 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeSimple } from "../lib/encodings.js"; +import * as M from "../lib/matchers.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../models/components/index.js"; +import { APIError } from "../models/errors/apierror.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Get user + * + * @remarks + * Get user by id from the database + */ +export async function usersGetUsersById( + client: SDKCore, + request: operations.GetUsersByIdRequest, + options?: RequestOptions, +): Promise< + Result< + components.User, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const parsed = safeParse( + request, + (value) => operations.GetUsersByIdRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return parsed; + } + const payload = parsed.value; + const body = null; + + const pathParams = { + id: encodeSimple("id", payload.id, { + explode: false, + charEncoding: "percent", + }), + }; + + const path = pathToFunc("/users/{id}")(pathParams); + + const headers = new Headers({ + Accept: "application/json", + }); + + const context = { + operationID: "getUsersById", + oAuth2Scopes: [], + + resolvedSecurity: null, + + securitySource: null, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + method: "GET", + path: path, + headers: headers, + body: body, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: ["404", "4XX", "5XX"], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + components.User, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json(200, components.User$inboundSchema), + M.jsonErr(404, errors.ErrorResponse$inboundSchema), + M.fail(["4XX", "5XX"]), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts new file mode 100644 index 00000000..9e83f667 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts @@ -0,0 +1,143 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeJSON, encodeSimple } from "../lib/encodings.js"; +import * as M from "../lib/matchers.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../models/components/index.js"; +import { APIError } from "../models/errors/apierror.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Update user + * + * @remarks + * Update user by id from the database + */ +export async function usersPatchUsersById( + client: SDKCore, + request: operations.PatchUsersByIdRequest, + options?: RequestOptions, +): Promise< + Result< + components.SuccessResponse, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const parsed = safeParse( + request, + (value) => operations.PatchUsersByIdRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return parsed; + } + const payload = parsed.value; + const body = encodeJSON("body", payload.RequestBody, { explode: true }); + + const pathParams = { + id: encodeSimple("id", payload.id, { + explode: false, + charEncoding: "percent", + }), + }; + + const path = pathToFunc("/users/{id}")(pathParams); + + const headers = new Headers({ + "Content-Type": "application/json", + Accept: "application/json", + }); + + const context = { + operationID: "patchUsersById", + oAuth2Scopes: [], + + resolvedSecurity: null, + + securitySource: null, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + method: "PATCH", + path: path, + headers: headers, + body: body, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: ["422", "4XX", "5XX"], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + components.SuccessResponse, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json(200, components.SuccessResponse$inboundSchema), + M.jsonErr(422, errors.ErrorResponse$inboundSchema), + M.fail(["4XX", "5XX"]), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts new file mode 100644 index 00000000..c04ae84f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts @@ -0,0 +1,136 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeJSON } from "../lib/encodings.js"; +import * as M from "../lib/matchers.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../models/components/index.js"; +import { APIError } from "../models/errors/apierror.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Create user + * + * @remarks + * Add user to the database + */ +export async function usersPostUsers( + client: SDKCore, + request: operations.PostUsersRequestBody, + options?: RequestOptions, +): Promise< + Result< + components.Id, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const parsed = safeParse( + request, + (value) => operations.PostUsersRequestBody$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return parsed; + } + const payload = parsed.value; + const body = encodeJSON("body", payload, { explode: true }); + + const path = pathToFunc("/users/")(); + + const headers = new Headers({ + "Content-Type": "application/json", + Accept: "application/json", + }); + + const context = { + operationID: "postUsers", + oAuth2Scopes: [], + + resolvedSecurity: null, + + securitySource: null, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 300, + maxInterval: 40000, + exponent: 1.2, + maxElapsedTime: 3000000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + method: "POST", + path: path, + headers: headers, + body: body, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: ["4XX", "500", "5XX"], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + components.Id, + | errors.ErrorResponse + | APIError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json(200, components.Id$inboundSchema), + M.jsonErr(500, errors.ErrorResponse$inboundSchema), + M.fail(["4XX", "5XX"]), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts b/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts new file mode 100644 index 00000000..d1b3396f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts @@ -0,0 +1,112 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { RequestInput } from "../lib/http.js"; +import { + AfterErrorContext, + AfterErrorHook, + AfterSuccessContext, + AfterSuccessHook, + BeforeCreateRequestContext, + BeforeCreateRequestHook, + BeforeRequestContext, + BeforeRequestHook, + Hooks, + SDKInitHook, + SDKInitOptions, +} from "./types.js"; + +import { initHooks } from "./registration.js"; + +export class SDKHooks implements Hooks { + sdkInitHooks: SDKInitHook[] = []; + beforeCreateRequestHooks: BeforeCreateRequestHook[] = []; + beforeRequestHooks: BeforeRequestHook[] = []; + afterSuccessHooks: AfterSuccessHook[] = []; + afterErrorHooks: AfterErrorHook[] = []; + + constructor() { + initHooks(this); + } + + registerSDKInitHook(hook: SDKInitHook) { + this.sdkInitHooks.push(hook); + } + + registerBeforeCreateRequestHook(hook: BeforeCreateRequestHook) { + this.beforeCreateRequestHooks.push(hook); + } + + registerBeforeRequestHook(hook: BeforeRequestHook) { + this.beforeRequestHooks.push(hook); + } + + registerAfterSuccessHook(hook: AfterSuccessHook) { + this.afterSuccessHooks.push(hook); + } + + registerAfterErrorHook(hook: AfterErrorHook) { + this.afterErrorHooks.push(hook); + } + + sdkInit(opts: SDKInitOptions): SDKInitOptions { + return this.sdkInitHooks.reduce((opts, hook) => hook.sdkInit(opts), opts); + } + + beforeCreateRequest( + hookCtx: BeforeCreateRequestContext, + input: RequestInput, + ): RequestInput { + let inp = input; + + for (const hook of this.beforeCreateRequestHooks) { + inp = hook.beforeCreateRequest(hookCtx, inp); + } + + return inp; + } + + async beforeRequest( + hookCtx: BeforeRequestContext, + request: Request, + ): Promise { + let req = request; + + for (const hook of this.beforeRequestHooks) { + req = await hook.beforeRequest(hookCtx, req); + } + + return req; + } + + async afterSuccess( + hookCtx: AfterSuccessContext, + response: Response, + ): Promise { + let res = response; + + for (const hook of this.afterSuccessHooks) { + res = await hook.afterSuccess(hookCtx, res); + } + + return res; + } + + async afterError( + hookCtx: AfterErrorContext, + response: Response | null, + error: unknown, + ): Promise<{ response: Response | null; error: unknown }> { + let res = response; + let err = error; + + for (const hook of this.afterErrorHooks) { + const result = await hook.afterError(hookCtx, res, err); + res = result.response; + err = result.error; + } + + return { response: res, error: err }; + } +} diff --git a/frameworks-elysia/sdk-typescript/src/hooks/index.ts b/frameworks-elysia/sdk-typescript/src/hooks/index.ts new file mode 100644 index 00000000..f60ec7ac --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/hooks/index.ts @@ -0,0 +1,6 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./hooks.js"; +export * from "./types.js"; diff --git a/frameworks-elysia/sdk-typescript/src/hooks/registration.ts b/frameworks-elysia/sdk-typescript/src/hooks/registration.ts new file mode 100644 index 00000000..70649734 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/hooks/registration.ts @@ -0,0 +1,14 @@ +import { Hooks } from "./types.js"; + +/* + * This file is only ever generated once on the first generation and then is free to be modified. + * Any hooks you wish to add should be registered in the initHooks function. Feel free to define them + * in this file or in separate files in the hooks folder. + */ + +// @ts-expect-error remove this line when you add your first hook and hooks is used +export function initHooks(hooks: Hooks) { + // Add hooks by calling hooks.register{ClientInit/BeforeCreateRequest/BeforeRequest/AfterSuccess/AfterError}Hook + // with an instance of a hook that implements that specific Hook interface + // Hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance +} diff --git a/frameworks-elysia/sdk-typescript/src/hooks/types.ts b/frameworks-elysia/sdk-typescript/src/hooks/types.ts new file mode 100644 index 00000000..df5237dc --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/hooks/types.ts @@ -0,0 +1,102 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { HTTPClient, RequestInput } from "../lib/http.js"; +import { RetryConfig } from "../lib/retries.js"; +import { SecurityState } from "../lib/security.js"; + +export type HookContext = { + operationID: string; + oAuth2Scopes?: string[]; + securitySource?: any | (() => Promise); + retryConfig: RetryConfig; + resolvedSecurity: SecurityState | null; +}; + +export type Awaitable = T | Promise; + +export type SDKInitOptions = { + baseURL: URL | null; + client: HTTPClient; +}; + +export type BeforeCreateRequestContext = HookContext & {}; +export type BeforeRequestContext = HookContext & {}; +export type AfterSuccessContext = HookContext & {}; +export type AfterErrorContext = HookContext & {}; + +/** + * SDKInitHook is called when the SDK is initializing. The + * hook can return a new baseURL and HTTP client to be used by the SDK. + */ +export interface SDKInitHook { + sdkInit: (opts: SDKInitOptions) => SDKInitOptions; +} + +export interface BeforeCreateRequestHook { + /** + * A hook that is called before the SDK creates a `Request` object. The hook + * can modify how a request is constructed since certain modifications, like + * changing the request URL, cannot be done on a request object directly. + */ + beforeCreateRequest: ( + hookCtx: BeforeCreateRequestContext, + input: RequestInput, + ) => RequestInput; +} + +export interface BeforeRequestHook { + /** + * A hook that is called before the SDK sends a request. The hook can + * introduce instrumentation code such as logging, tracing and metrics or + * replace the request before it is sent or throw an error to stop the + * request from being sent. + */ + beforeRequest: ( + hookCtx: BeforeRequestContext, + request: Request, + ) => Awaitable; +} + +export interface AfterSuccessHook { + /** + * A hook that is called after the SDK receives a response. The hook can + * introduce instrumentation code such as logging, tracing and metrics or + * modify the response before it is handled or throw an error to stop the + * response from being handled. + */ + afterSuccess: ( + hookCtx: AfterSuccessContext, + response: Response, + ) => Awaitable; +} + +export interface AfterErrorHook { + /** + * A hook that is called after the SDK encounters an error, or a + * non-successful response. The hook can introduce instrumentation code such + * as logging, tracing and metrics or modify the response or error values. + */ + afterError: ( + hookCtx: AfterErrorContext, + response: Response | null, + error: unknown, + ) => Awaitable<{ + response: Response | null; + error: unknown; + }>; +} + +export interface Hooks { + /** Registers a hook to be used by the SDK for initialization event. */ + registerSDKInitHook(hook: SDKInitHook): void; + /** Registers a hook to be used by the SDK for to modify `Request` construction. */ + registerBeforeCreateRequestHook(hook: BeforeCreateRequestHook): void; + /** Registers a hook to be used by the SDK for the before request event. */ + registerBeforeRequestHook(hook: BeforeRequestHook): void; + /** Registers a hook to be used by the SDK for the after success event. */ + registerAfterSuccessHook(hook: AfterSuccessHook): void; + /** Registers a hook to be used by the SDK for the after error event. */ + registerAfterErrorHook(hook: AfterErrorHook): void; +} diff --git a/frameworks-elysia/sdk-typescript/src/index.ts b/frameworks-elysia/sdk-typescript/src/index.ts new file mode 100644 index 00000000..5ddc765e --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/index.ts @@ -0,0 +1,7 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./lib/config.js"; +export * as files from "./lib/files.js"; +export * from "./sdk/sdk.js"; diff --git a/frameworks-elysia/sdk-typescript/src/lib/base64.ts b/frameworks-elysia/sdk-typescript/src/lib/base64.ts new file mode 100644 index 00000000..c2d5b389 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/base64.ts @@ -0,0 +1,37 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export function bytesToBase64(u8arr: Uint8Array): string { + return btoa(String.fromCodePoint(...u8arr)); +} + +export function bytesFromBase64(encoded: string): Uint8Array { + return Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0)); +} + +export function stringToBytes(str: string): Uint8Array { + return new TextEncoder().encode(str); +} + +export function stringFromBytes(u8arr: Uint8Array): string { + return new TextDecoder().decode(u8arr); +} + +export function stringToBase64(str: string): string { + return bytesToBase64(stringToBytes(str)); +} + +export function stringFromBase64(b64str: string): string { + return stringFromBytes(bytesFromBase64(b64str)); +} + +export const zodOutbound = z + .instanceof(Uint8Array) + .or(z.string().transform(stringToBytes)); + +export const zodInbound = z + .instanceof(Uint8Array) + .or(z.string().transform(bytesFromBase64)); diff --git a/frameworks-elysia/sdk-typescript/src/lib/config.ts b/frameworks-elysia/sdk-typescript/src/lib/config.ts new file mode 100644 index 00000000..8c65a191 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/config.ts @@ -0,0 +1,61 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { HTTPClient } from "./http.js"; +import { Logger } from "./logger.js"; +import { RetryConfig } from "./retries.js"; +import { Params, pathToFunc } from "./url.js"; + +/** + * Contains the list of servers available to the SDK + */ +export const ServerList = [ + /** + * Development server + */ + "http://localhost:3000/", +] as const; + +export type SDKOptions = { + httpClient?: HTTPClient; + /** + * Allows overriding the default server used by the SDK + */ + serverIdx?: number; + /** + * Allows overriding the default server URL used by the SDK + */ + serverURL?: string; + /** + * Allows overriding the default retry config used by the SDK + */ + retryConfig?: RetryConfig; + timeoutMs?: number; + debugLogger?: Logger; +}; + +export function serverURLFromOptions(options: SDKOptions): URL | null { + let serverURL = options.serverURL; + + const params: Params = {}; + + if (!serverURL) { + const serverIdx = options.serverIdx ?? 0; + if (serverIdx < 0 || serverIdx >= ServerList.length) { + throw new Error(`Invalid server index ${serverIdx}`); + } + serverURL = ServerList[serverIdx] || ""; + } + + const u = pathToFunc(serverURL)(params); + return new URL(u); +} + +export const SDK_METADATA = { + language: "typescript", + openapiDocVersion: "1.0.50", + sdkVersion: "0.0.1", + genVersion: "2.472.1", + userAgent: "speakeasy-sdk/typescript 0.0.1 2.472.1 1.0.50 sdk", +} as const; diff --git a/frameworks-elysia/sdk-typescript/src/lib/dlv.ts b/frameworks-elysia/sdk-typescript/src/lib/dlv.ts new file mode 100644 index 00000000..e81091f5 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/dlv.ts @@ -0,0 +1,53 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/* +MIT License + +Copyright (c) 2024 Jason Miller (http://jasonformat.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @param obj The object to walk + * @param key The key path to walk the object with + * @param def A default value to return if the result is undefined + * + * @example + * dlv(obj, "a.b.c.d") + * @example + * dlv(object, ["a", "b", "c", "d"]) + * @example + * dlv(object, "foo.bar.baz", "Hello, default value!") + */ +export function dlv( + obj: any, + key: string | string[], + def?: T, + p?: number, + undef?: never, +): T | undefined { + key = Array.isArray(key) ? key : key.split("."); + for (p = 0; p < key.length; p++) { + const k = key[p]; + obj = k != null && obj ? obj[k] : undef; + } + return obj === undef ? def : obj; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/encodings.ts b/frameworks-elysia/sdk-typescript/src/lib/encodings.ts new file mode 100644 index 00000000..44fa7284 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/encodings.ts @@ -0,0 +1,449 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { bytesToBase64 } from "./base64.js"; +import { isPlainObject } from "./is-plain-object.js"; + +export class EncodingError extends Error { + constructor(message: string) { + super(message); + this.name = "EncodingError"; + } +} + +export function encodeMatrix( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +): string { + let out = ""; + const pairs: [string, unknown][] = options?.explode + ? explode(key, value) + : [[key, value]]; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + const encodeValue = (v: unknown) => encodeString(serializeValue(v)); + + pairs.forEach(([pk, pv]) => { + let tmp = ""; + let encValue = ""; + + if (pv === undefined) { + return; + } else if (Array.isArray(pv)) { + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join(","); + } else if (isPlainObject(pv)) { + encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + return `,${encodeString(k)},${encodeValue(v)}`; + }).join(""); + encValue = encValue.slice(1); + } else { + encValue = `${encodeValue(pv)}`; + } + + const keyPrefix = encodeString(pk); + tmp = `${keyPrefix}=${encValue}`; + // trim trailing '=' if value was empty + if (tmp === `${keyPrefix}=`) { + tmp = tmp.slice(0, -1); + } + + // If we end up with the nothing then skip forward + if (!tmp) { + return; + } + + out += `;${tmp}`; + }); + + return out; +} + +export function encodeLabel( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +): string { + let out = ""; + const pairs: [string, unknown][] = options?.explode + ? explode(key, value) + : [[key, value]]; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + const encodeValue = (v: unknown) => encodeString(serializeValue(v)); + + pairs.forEach(([pk, pv]) => { + let encValue = ""; + + if (pv === undefined) { + return; + } else if (Array.isArray(pv)) { + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join("."); + } else if (isPlainObject(pv)) { + encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + return `.${encodeString(k)}.${encodeValue(v)}`; + }).join(""); + encValue = encValue.slice(1); + } else { + const k = + options?.explode && isPlainObject(value) ? `${encodeString(pk)}=` : ""; + encValue = `${k}${encodeValue(pv)}`; + } + + out += `.${encValue}`; + }); + + return out; +} + +type FormEncoder = ( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +) => string; + +function formEncoder(sep: string): FormEncoder { + return ( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, + ) => { + let out = ""; + const pairs: [string, unknown][] = options?.explode + ? explode(key, value) + : [[key, value]]; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + + const encodeValue = (v: unknown) => encodeString(serializeValue(v)); + + const encodedSep = encodeString(sep); + + pairs.forEach(([pk, pv]) => { + let tmp = ""; + let encValue = ""; + + if (pv === undefined) { + return; + } else if (Array.isArray(pv)) { + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join(encodedSep); + } else if (isPlainObject(pv)) { + encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + return `${encodeString(k)}${encodedSep}${encodeValue(v)}`; + }).join(encodedSep); + } else { + encValue = `${encodeValue(pv)}`; + } + + tmp = `${encodeString(pk)}=${encValue}`; + + // If we end up with the nothing then skip forward + if (!tmp || tmp === "=") { + return; + } + + out += `&${tmp}`; + }); + + return out.slice(1); + }; +} + +export const encodeForm = formEncoder(","); +export const encodeSpaceDelimited = formEncoder(" "); +export const encodePipeDelimited = formEncoder("|"); + +export function encodeBodyForm( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +): string { + let out = ""; + const pairs: [string, unknown][] = options?.explode + ? explode(key, value) + : [[key, value]]; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + + const encodeValue = (v: unknown) => encodeString(serializeValue(v)); + + pairs.forEach(([pk, pv]) => { + let tmp = ""; + let encValue = ""; + + if (pv === undefined) { + return; + } else if (Array.isArray(pv)) { + encValue = JSON.stringify(pv, jsonReplacer); + } else if (isPlainObject(pv)) { + encValue = JSON.stringify(pv, jsonReplacer); + } else { + encValue = `${encodeValue(pv)}`; + } + + tmp = `${encodeString(pk)}=${encValue}`; + + // If we end up with the nothing then skip forward + if (!tmp || tmp === "=") { + return; + } + + out += `&${tmp}`; + }); + + return out.slice(1); +} + +export function encodeDeepObject( + key: string, + value: unknown, + options?: { charEncoding?: "percent" | "none" }, +): string { + if (value == null) { + return ""; + } + + if (!isPlainObject(value)) { + throw new EncodingError( + `Value of parameter '${key}' which uses deepObject encoding must be an object`, + ); + } + + return encodeDeepObjectObject(key, value, options); +} + +export function encodeDeepObjectObject( + key: string, + value: unknown, + options?: { charEncoding?: "percent" | "none" }, +): string { + if (value == null) { + return ""; + } + + let out = ""; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + + if (!isPlainObject(value)) { + throw new EncodingError(`Expected parameter '${key}' to be an object.`); + } + + Object.entries(value).forEach(([ck, cv]) => { + if (cv === undefined) { + return; + } + + const pk = `${key}[${ck}]`; + + if (isPlainObject(cv)) { + const objOut = encodeDeepObjectObject(pk, cv, options); + + out += `&${objOut}`; + + return; + } + + const pairs: unknown[] = Array.isArray(cv) ? cv : [cv]; + let encoded = ""; + + encoded = mapDefined(pairs, (v) => { + return `${encodeString(pk)}=${encodeString(serializeValue(v))}`; + }).join("&"); + + out += `&${encoded}`; + }); + + return out.slice(1); +} + +export function encodeJSON( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +): string { + if (typeof value === "undefined") { + return ""; + } + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + + const encVal = encodeString(JSON.stringify(value, jsonReplacer)); + + return options?.explode ? encVal : `${encodeString(key)}=${encVal}`; +} + +export const encodeSimple = ( + key: string, + value: unknown, + options?: { explode?: boolean; charEncoding?: "percent" | "none" }, +): string => { + let out = ""; + const pairs: [string, unknown][] = options?.explode + ? explode(key, value) + : [[key, value]]; + + const encodeString = (v: string) => { + return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; + }; + const encodeValue = (v: unknown) => encodeString(serializeValue(v)); + + pairs.forEach(([pk, pv]) => { + let tmp = ""; + + if (pv === undefined) { + return; + } else if (Array.isArray(pv)) { + tmp = mapDefined(pv, (v) => `${encodeValue(v)}`).join(","); + } else if (isPlainObject(pv)) { + tmp = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + return `,${encodeString(k)},${encodeValue(v)}`; + }).join(""); + tmp = tmp.slice(1); + } else { + const k = options?.explode && isPlainObject(value) ? `${pk}=` : ""; + tmp = `${k}${encodeValue(pv)}`; + } + + // If we end up with the nothing then skip forward + if (!tmp) { + return; + } + + out += `,${tmp}`; + }); + + return out.slice(1); +}; + +function explode(key: string, value: unknown): [string, unknown][] { + if (Array.isArray(value)) { + return value.map((v) => [key, v]); + } else if (isPlainObject(value)) { + const o = value ?? {}; + return Object.entries(o).map(([k, v]) => [k, v]); + } else { + return [[key, value]]; + } +} + +function serializeValue(value: unknown): string { + if (value === null) { + return "null"; + } else if (typeof value === "undefined") { + return ""; + } else if (value instanceof Date) { + return value.toISOString(); + } else if (value instanceof Uint8Array) { + return bytesToBase64(value); + } else if (typeof value === "object") { + return JSON.stringify(value, jsonReplacer); + } + + return `${value}`; +} + +function jsonReplacer(_: string, value: unknown): unknown { + if (value instanceof Uint8Array) { + return bytesToBase64(value); + } else { + return value; + } +} + +function mapDefined(inp: T[], mapper: (v: T) => R): R[] { + return inp.reduce((acc, v) => { + if (v === undefined) { + return acc; + } + + const m = mapper(v); + if (m === undefined) { + return acc; + } + + acc.push(m); + + return acc; + }, []); +} + +function mapDefinedEntries( + inp: Iterable<[K, V]>, + mapper: (v: [K, V]) => R, +): R[] { + const acc: R[] = []; + for (const [k, v] of inp) { + if (v === undefined) { + continue; + } + + const m = mapper([k, v]); + if (m === undefined) { + continue; + } + + acc.push(m); + } + + return acc; +} + +export function queryJoin(...args: string[]): string { + return args.filter(Boolean).join("&"); +} + +type QueryEncoderOptions = { + explode?: boolean; + charEncoding?: "percent" | "none"; +}; + +type QueryEncoder = ( + key: string, + value: unknown, + options?: QueryEncoderOptions, +) => string; + +type BulkQueryEncoder = ( + values: Record, + options?: QueryEncoderOptions, +) => string; + +export function queryEncoder(f: QueryEncoder): BulkQueryEncoder { + const bulkEncode = function ( + values: Record, + options?: QueryEncoderOptions, + ): string { + const opts: QueryEncoderOptions = { + ...options, + explode: options?.explode ?? true, + charEncoding: options?.charEncoding ?? "percent", + }; + + const encoded = Object.entries(values).map(([key, value]) => { + return f(key, value, opts); + }); + return queryJoin(...encoded); + }; + + return bulkEncode; +} + +export const encodeJSONQuery = queryEncoder(encodeJSON); +export const encodeFormQuery = queryEncoder(encodeForm); +export const encodeSpaceDelimitedQuery = queryEncoder(encodeSpaceDelimited); +export const encodePipeDelimitedQuery = queryEncoder(encodePipeDelimited); +export const encodeDeepObjectQuery = queryEncoder(encodeDeepObject); diff --git a/frameworks-elysia/sdk-typescript/src/lib/env.ts b/frameworks-elysia/sdk-typescript/src/lib/env.ts new file mode 100644 index 00000000..c94701ff --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/env.ts @@ -0,0 +1,37 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { dlv } from "./dlv.js"; + +import * as z from "zod"; + +export interface Env { + SDK_DEBUG?: boolean | undefined; +} + +export const envSchema: z.ZodType = z.object({ + SDK_DEBUG: z.coerce.boolean().optional(), +}); + +let envMemo: Env | undefined = undefined; +/** + * Reads and validates environment variables. + */ +export function env(): Env { + if (envMemo) { + return envMemo; + } + + envMemo = envSchema.parse( + dlv(globalThis, "process.env") ?? dlv(globalThis, "Deno.env") ?? {}, + ); + return envMemo; +} + +/** + * Clears the cached env object. Useful for testing with a fresh environment. + */ +export function resetEnv() { + envMemo = undefined; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/files.ts b/frameworks-elysia/sdk-typescript/src/lib/files.ts new file mode 100644 index 00000000..19e08041 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/files.ts @@ -0,0 +1,40 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/** + * Consumes a stream and returns a concatenated array buffer. Useful in + * situations where we need to read the whole file because it forms part of a + * larger payload containing other fields, and we can't modify the underlying + * request structure. + */ +export async function readableStreamToArrayBuffer( + readable: ReadableStream, +): Promise { + const reader = readable.getReader(); + const chunks: Uint8Array[] = []; + + let totalLength = 0; + let done = false; + + while (!done) { + const { value, done: doneReading } = await reader.read(); + + if (doneReading) { + done = true; + } else { + chunks.push(value); + totalLength += value.length; + } + } + + const concatenatedChunks = new Uint8Array(totalLength); + let offset = 0; + + for (const chunk of chunks) { + concatenatedChunks.set(chunk, offset); + offset += chunk.length; + } + + return concatenatedChunks.buffer; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/http.ts b/frameworks-elysia/sdk-typescript/src/lib/http.ts new file mode 100644 index 00000000..13cf1fd7 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/http.ts @@ -0,0 +1,323 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export type Fetcher = ( + input: RequestInfo | URL, + init?: RequestInit, +) => Promise; + +export type Awaitable = T | Promise; + +const DEFAULT_FETCHER: Fetcher = (input, init) => { + // If input is a Request and init is undefined, Bun will discard the method, + // headers, body and other options that were set on the request object. + // Node.js and browers would ignore an undefined init value. This check is + // therefore needed for interop with Bun. + if (init == null) { + return fetch(input); + } else { + return fetch(input, init); + } +}; + +export type RequestInput = { + /** + * The URL the request will use. + */ + url: URL; + /** + * Options used to create a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request). + */ + options?: RequestInit | undefined; +}; + +export interface HTTPClientOptions { + fetcher?: Fetcher; +} + +export type BeforeRequestHook = (req: Request) => Awaitable; +export type RequestErrorHook = (err: unknown, req: Request) => Awaitable; +export type ResponseHook = (res: Response, req: Request) => Awaitable; + +export class HTTPClient { + private fetcher: Fetcher; + private requestHooks: BeforeRequestHook[] = []; + private requestErrorHooks: RequestErrorHook[] = []; + private responseHooks: ResponseHook[] = []; + + constructor(private options: HTTPClientOptions = {}) { + this.fetcher = options.fetcher || DEFAULT_FETCHER; + } + + async request(request: Request): Promise { + let req = request; + for (const hook of this.requestHooks) { + const nextRequest = await hook(req); + if (nextRequest) { + req = nextRequest; + } + } + + try { + const res = await this.fetcher(req); + + for (const hook of this.responseHooks) { + await hook(res, req); + } + + return res; + } catch (err) { + for (const hook of this.requestErrorHooks) { + await hook(err, req); + } + + throw err; + } + } + + /** + * Registers a hook that is called before a request is made. The hook function + * can mutate the request or return a new request. This may be useful to add + * additional information to request such as request IDs and tracing headers. + */ + addHook(hook: "beforeRequest", fn: BeforeRequestHook): this; + /** + * Registers a hook that is called when a request cannot be made due to a + * network error. + */ + addHook(hook: "requestError", fn: RequestErrorHook): this; + /** + * Registers a hook that is called when a response has been received from the + * server. + */ + addHook(hook: "response", fn: ResponseHook): this; + addHook( + ...args: + | [hook: "beforeRequest", fn: BeforeRequestHook] + | [hook: "requestError", fn: RequestErrorHook] + | [hook: "response", fn: ResponseHook] + ) { + if (args[0] === "beforeRequest") { + this.requestHooks.push(args[1]); + } else if (args[0] === "requestError") { + this.requestErrorHooks.push(args[1]); + } else if (args[0] === "response") { + this.responseHooks.push(args[1]); + } else { + throw new Error(`Invalid hook type: ${args[0]}`); + } + return this; + } + + /** Removes a hook that was previously registered with `addHook`. */ + removeHook(hook: "beforeRequest", fn: BeforeRequestHook): this; + /** Removes a hook that was previously registered with `addHook`. */ + removeHook(hook: "requestError", fn: RequestErrorHook): this; + /** Removes a hook that was previously registered with `addHook`. */ + removeHook(hook: "response", fn: ResponseHook): this; + removeHook( + ...args: + | [hook: "beforeRequest", fn: BeforeRequestHook] + | [hook: "requestError", fn: RequestErrorHook] + | [hook: "response", fn: ResponseHook] + ): this { + let target: unknown[]; + if (args[0] === "beforeRequest") { + target = this.requestHooks; + } else if (args[0] === "requestError") { + target = this.requestErrorHooks; + } else if (args[0] === "response") { + target = this.responseHooks; + } else { + throw new Error(`Invalid hook type: ${args[0]}`); + } + + const index = target.findIndex((v) => v === args[1]); + if (index >= 0) { + target.splice(index, 1); + } + + return this; + } + + clone(): HTTPClient { + const child = new HTTPClient(this.options); + child.requestHooks = this.requestHooks.slice(); + child.requestErrorHooks = this.requestErrorHooks.slice(); + child.responseHooks = this.responseHooks.slice(); + + return child; + } +} + +export type StatusCodePredicate = number | string | (number | string)[]; + +// A semicolon surrounded by optional whitespace characters is used to separate +// segments in a media type string. +const mediaParamSeparator = /\s*;\s*/g; + +export function matchContentType(response: Response, pattern: string): boolean { + // `*` is a special case which means anything is acceptable. + if (pattern === "*") { + return true; + } + + let contentType = + response.headers.get("content-type")?.trim() || "application/octet-stream"; + contentType = contentType.toLowerCase(); + + const wantParts = pattern.toLowerCase().trim().split(mediaParamSeparator); + const [wantType = "", ...wantParams] = wantParts; + + if (wantType.split("/").length !== 2) { + return false; + } + + const gotParts = contentType.split(mediaParamSeparator); + const [gotType = "", ...gotParams] = gotParts; + + const [type = "", subtype = ""] = gotType.split("/"); + if (!type || !subtype) { + return false; + } + + if ( + wantType !== "*/*" && + gotType !== wantType && + `${type}/*` !== wantType && + `*/${subtype}` !== wantType + ) { + return false; + } + + if (gotParams.length < wantParams.length) { + return false; + } + + const params = new Set(gotParams); + for (const wantParam of wantParams) { + if (!params.has(wantParam)) { + return false; + } + } + + return true; +} + +const codeRangeRE = new RegExp("^[0-9]xx$", "i"); + +export function matchStatusCode( + response: Response, + codes: StatusCodePredicate, +): boolean { + const actual = `${response.status}`; + const expectedCodes = Array.isArray(codes) ? codes : [codes]; + if (!expectedCodes.length) { + return false; + } + + return expectedCodes.some((ec) => { + const code = `${ec}`; + + if (code === "default") { + return true; + } + + if (!codeRangeRE.test(`${code}`)) { + return code === actual; + } + + const expectFamily = code.charAt(0); + if (!expectFamily) { + throw new Error("Invalid status code range"); + } + + const actualFamily = actual.charAt(0); + if (!actualFamily) { + throw new Error(`Invalid response status code: ${actual}`); + } + + return actualFamily === expectFamily; + }); +} + +export function matchResponse( + response: Response, + code: StatusCodePredicate, + contentTypePattern: string, +): boolean { + return ( + matchStatusCode(response, code) && + matchContentType(response, contentTypePattern) + ); +} + +/** + * Uses various heurisitics to determine if an error is a connection error. + */ +export function isConnectionError(err: unknown): boolean { + if (typeof err !== "object" || err == null) { + return false; + } + + // Covers fetch in Deno as well + const isBrowserErr = + err instanceof TypeError && + err.message.toLowerCase().startsWith("failed to fetch"); + + const isNodeErr = + err instanceof TypeError && + err.message.toLowerCase().startsWith("fetch failed"); + + const isBunErr = "name" in err && err.name === "ConnectionError"; + + const isGenericErr = + "code" in err && + typeof err.code === "string" && + err.code.toLowerCase() === "econnreset"; + + return isBrowserErr || isNodeErr || isGenericErr || isBunErr; +} + +/** + * Uses various heurisitics to determine if an error is a timeout error. + */ +export function isTimeoutError(err: unknown): boolean { + if (typeof err !== "object" || err == null) { + return false; + } + + // Fetch in browser, Node.js, Bun, Deno + const isNative = "name" in err && err.name === "TimeoutError"; + const isLegacyNative = "code" in err && err.code === 23; + + // Node.js HTTP client and Axios + const isGenericErr = + "code" in err && + typeof err.code === "string" && + err.code.toLowerCase() === "econnaborted"; + + return isNative || isLegacyNative || isGenericErr; +} + +/** + * Uses various heurisitics to determine if an error is a abort error. + */ +export function isAbortError(err: unknown): boolean { + if (typeof err !== "object" || err == null) { + return false; + } + + // Fetch in browser, Node.js, Bun, Deno + const isNative = "name" in err && err.name === "AbortError"; + const isLegacyNative = "code" in err && err.code === 20; + + // Node.js HTTP client and Axios + const isGenericErr = + "code" in err && + typeof err.code === "string" && + err.code.toLowerCase() === "econnaborted"; + + return isNative || isLegacyNative || isGenericErr; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/is-plain-object.ts b/frameworks-elysia/sdk-typescript/src/lib/is-plain-object.ts new file mode 100644 index 00000000..61070d3d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/is-plain-object.ts @@ -0,0 +1,43 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/* +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Taken from https://github.com/sindresorhus/is-plain-obj/blob/97f38e8836f86a642cce98fc6ab3058bc36df181/index.js + +export function isPlainObject(value: unknown): value is object { + if (typeof value !== "object" || value === null) { + return false; + } + + const prototype = Object.getPrototypeOf(value); + return ( + (prototype === null || + prototype === Object.prototype || + Object.getPrototypeOf(prototype) === null) && + !(Symbol.toStringTag in value) && + !(Symbol.iterator in value) + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/logger.ts b/frameworks-elysia/sdk-typescript/src/lib/logger.ts new file mode 100644 index 00000000..d181f293 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/logger.ts @@ -0,0 +1,9 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export interface Logger { + group(label?: string): void; + groupEnd(): void; + log(message: any, ...args: any[]): void; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/matchers.ts b/frameworks-elysia/sdk-typescript/src/lib/matchers.ts new file mode 100644 index 00000000..65858ac9 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/matchers.ts @@ -0,0 +1,322 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { APIError } from "../models/errors/apierror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import { Result } from "../types/fp.js"; +import { matchResponse, matchStatusCode, StatusCodePredicate } from "./http.js"; +import { isPlainObject } from "./is-plain-object.js"; +import { safeParse } from "./schemas.js"; + +export type Encoding = + | "json" + | "text" + | "bytes" + | "stream" + | "sse" + | "nil" + | "fail"; + +const DEFAULT_CONTENT_TYPES: Record = { + json: "application/json", + text: "text/plain", + bytes: "application/octet-stream", + stream: "application/octet-stream", + sse: "text/event-stream", + nil: "*", + fail: "*", +}; + +type Schema = { parse(raw: unknown): T }; + +type MatchOptions = { + ctype?: string; + hdrs?: boolean; + key?: string; + sseSentinel?: string; +}; + +export type ValueMatcher = MatchOptions & { + enc: Encoding; + codes: StatusCodePredicate; + schema: Schema; +}; + +export type ErrorMatcher = MatchOptions & { + enc: Encoding; + codes: StatusCodePredicate; + schema: Schema; + err: true; +}; + +export type FailMatcher = { + enc: "fail"; + codes: StatusCodePredicate; +}; + +export type Matcher = ValueMatcher | ErrorMatcher | FailMatcher; + +export function jsonErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "json", codes, schema }; +} +export function json( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "json", codes, schema }; +} + +export function textErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "text", codes, schema }; +} +export function text( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "text", codes, schema }; +} + +export function bytesErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "bytes", codes, schema }; +} +export function bytes( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "bytes", codes, schema }; +} + +export function streamErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "stream", codes, schema }; +} +export function stream( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "stream", codes, schema }; +} + +export function sseErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "sse", codes, schema }; +} +export function sse( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "sse", codes, schema }; +} + +export function nilErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "nil", codes, schema }; +} +export function nil( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "nil", codes, schema }; +} + +export function fail(codes: StatusCodePredicate): FailMatcher { + return { enc: "fail", codes }; +} + +export type MatchedValue = Matchers extends Matcher[] + ? T + : never; +export type MatchedError = Matchers extends Matcher[] + ? E + : never; +export type MatchFunc = ( + response: Response, + options?: { resultKey?: string; extraFields?: Record }, +) => Promise<[result: Result, raw: unknown]>; + +export function match( + ...matchers: Array> +): MatchFunc { + return async function matchFunc( + response: Response, + options?: { resultKey?: string; extraFields?: Record }, + ): Promise< + [result: Result, raw: unknown] + > { + let raw: unknown; + let matcher: Matcher | undefined; + for (const match of matchers) { + const { codes } = match; + const ctpattern = "ctype" in match + ? match.ctype + : DEFAULT_CONTENT_TYPES[match.enc]; + if (ctpattern && matchResponse(response, codes, ctpattern)) { + matcher = match; + break; + } else if (!ctpattern && matchStatusCode(response, codes)) { + matcher = match; + break; + } + } + + if (!matcher) { + const responseBody = await response.text(); + return [{ + ok: false, + error: new APIError( + "Unexpected API response status or content-type", + response, + responseBody, + ), + }, responseBody]; + } + + const encoding = matcher.enc; + switch (encoding) { + case "json": + raw = await response.json(); + break; + case "bytes": + raw = new Uint8Array(await response.arrayBuffer()); + break; + case "stream": + raw = response.body; + break; + case "text": + raw = await response.text(); + break; + case "sse": + raw = response.body; + break; + case "nil": + raw = await discardResponseBody(response); + break; + case "fail": + raw = await response.text(); + break; + default: + encoding satisfies never; + throw new Error(`Unsupported response type: ${encoding}`); + } + + if (matcher.enc === "fail") { + return [{ + ok: false, + error: new APIError( + "API error occurred", + response, + typeof raw === "string" ? raw : "", + ), + }, raw]; + } + + const resultKey = matcher.key || options?.resultKey; + let data: unknown; + + if ("err" in matcher) { + data = { + ...options?.extraFields, + ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null), + ...(isPlainObject(raw) ? raw : null), + }; + } else if (resultKey) { + data = { + ...options?.extraFields, + ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null), + [resultKey]: raw, + }; + } else if (matcher.hdrs) { + data = { + ...options?.extraFields, + ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null), + ...(isPlainObject(raw) ? raw : null), + }; + } else { + data = raw; + } + + if ("err" in matcher) { + const result = safeParse( + data, + (v: unknown) => matcher.schema.parse(v), + "Response validation failed", + ); + return [result.ok ? { ok: false, error: result.value } : result, raw]; + } else { + return [ + safeParse( + data, + (v: unknown) => matcher.schema.parse(v), + "Response validation failed", + ), + raw, + ]; + } + }; +} + +const headerValRE = /, */; +/** + * Iterates over a Headers object and returns an object with all the header + * entries. Values are represented as an array to account for repeated headers. + */ +export function unpackHeaders(headers: Headers): Record { + const out: Record = {}; + + for (const [k, v] of headers.entries()) { + out[k] = v.split(headerValRE); + } + + return out; +} + +/** + * Discards the response body to free up resources. + * + * To learn why this is need, see the undici docs: + * https://undici.nodejs.org/#/?id=garbage-collection + */ +export async function discardResponseBody(res: Response) { + const reader = res.body?.getReader(); + if (reader == null) { + return; + } + + try { + let done = false; + while (!done) { + const res = await reader.read(); + done = res.done; + } + } finally { + reader.releaseLock(); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/primitives.ts b/frameworks-elysia/sdk-typescript/src/lib/primitives.ts new file mode 100644 index 00000000..1dc4ee43 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/primitives.ts @@ -0,0 +1,122 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +class InvariantError extends Error { + constructor(message: string) { + super(message); + this.name = "InvariantError"; + } +} + +export function invariant( + condition: unknown, + message: string, +): asserts condition { + if (!condition) { + throw new InvariantError(message); + } +} + +export type ExactPartial = { + [P in keyof T]?: T[P] | undefined; +}; + +export type Remap = { + [k in keyof Inp as Mapping[k] extends string /* if we have a string mapping for this key then use it */ + ? Mapping[k] + : Mapping[k] extends null /* if the mapping is to `null` then drop the key */ + ? never + : k /* otherwise keep the key as-is */]: Inp[k]; +}; + +/** + * Converts or omits an object's keys according to a mapping. + * + * @param inp An object whose keys will be remapped + * @param mappings A mapping of original keys to new keys. If a key is not present in the mapping, it will be left as is. If a key is mapped to `null`, it will be removed in the resulting object. + * @returns A new object with keys remapped or omitted according to the mappings + */ +export function remap< + Inp extends Record, + const Mapping extends { [k in keyof Inp]?: string | null }, +>(inp: Inp, mappings: Mapping): Remap { + let out: any = {}; + + if (!Object.keys(mappings).length) { + out = inp; + return out; + } + + for (const [k, v] of Object.entries(inp)) { + const j = mappings[k]; + if (j === null) { + continue; + } + out[j ?? k] = v; + } + + return out; +} + +export function combineSignals( + ...signals: Array +): AbortSignal | null { + const filtered: AbortSignal[] = []; + for (const signal of signals) { + if (signal) { + filtered.push(signal); + } + } + + switch (filtered.length) { + case 0: + case 1: + return filtered[0] || null; + default: + if ("any" in AbortSignal && typeof AbortSignal.any === "function") { + return AbortSignal.any(filtered); + } + return abortSignalAny(filtered); + } +} + +export function abortSignalAny(signals: AbortSignal[]): AbortSignal { + const controller = new AbortController(); + const result = controller.signal; + if (!signals.length) { + return controller.signal; + } + + if (signals.length === 1) { + return signals[0] || controller.signal; + } + + for (const signal of signals) { + if (signal.aborted) { + return signal; + } + } + + function abort(this: AbortSignal) { + controller.abort(this.reason); + clean(); + } + + const signalRefs: WeakRef[] = []; + function clean() { + for (const signalRef of signalRefs) { + const signal = signalRef.deref(); + if (signal) { + signal.removeEventListener("abort", abort); + } + } + } + + for (const signal of signals) { + signalRefs.push(new WeakRef(signal)); + signal.addEventListener("abort", abort); + } + + return result; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/retries.ts b/frameworks-elysia/sdk-typescript/src/lib/retries.ts new file mode 100644 index 00000000..93ebc8de --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/retries.ts @@ -0,0 +1,219 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { isConnectionError, isTimeoutError } from "./http.js"; + +export type BackoffStrategy = { + initialInterval: number; + maxInterval: number; + exponent: number; + maxElapsedTime: number; +}; + +const defaultBackoff: BackoffStrategy = { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, +}; + +export type RetryConfig = + | { strategy: "none" } + | { + strategy: "backoff"; + backoff?: BackoffStrategy; + retryConnectionErrors?: boolean; + }; + +/** + * PermanentError is an error that is not recoverable. Throwing this error will + * cause a retry loop to terminate. + */ +export class PermanentError extends Error { + /** The underlying cause of the error. */ + override readonly cause: unknown; + + constructor(message: string, options?: { cause?: unknown }) { + let msg = message; + if (options?.cause) { + msg += `: ${options.cause}`; + } + + super(msg, options); + this.name = "PermanentError"; + // In older runtimes, the cause field would not have been assigned through + // the super() call. + if (typeof this.cause === "undefined") { + this.cause = options?.cause; + } + + Object.setPrototypeOf(this, PermanentError.prototype); + } +} + +/** + * TemporaryError is an error is used to signal that an HTTP request can be + * retried as part of a retry loop. If retry attempts are exhausted and this + * error is thrown, the response will be returned to the caller. + */ +export class TemporaryError extends Error { + response: Response; + + constructor(message: string, response: Response) { + super(message); + this.response = response; + this.name = "TemporaryError"; + + Object.setPrototypeOf(this, TemporaryError.prototype); + } +} + +export async function retry( + fetchFn: () => Promise, + options: { + config: RetryConfig; + statusCodes: string[]; + }, +): Promise { + switch (options.config.strategy) { + case "backoff": + return retryBackoff( + wrapFetcher(fetchFn, { + statusCodes: options.statusCodes, + retryConnectionErrors: !!options.config.retryConnectionErrors, + }), + options.config.backoff ?? defaultBackoff, + ); + default: + return await fetchFn(); + } +} + +function wrapFetcher( + fn: () => Promise, + options: { + statusCodes: string[]; + retryConnectionErrors: boolean; + }, +): () => Promise { + return async () => { + try { + const res = await fn(); + if (isRetryableResponse(res, options.statusCodes)) { + throw new TemporaryError( + "Response failed with retryable status code", + res, + ); + } + + return res; + } catch (err: unknown) { + if (err instanceof TemporaryError) { + throw err; + } + + if ( + options.retryConnectionErrors && + (isTimeoutError(err) || isConnectionError(err)) + ) { + throw err; + } + + throw new PermanentError("Permanent error", { cause: err }); + } + }; +} + +const codeRangeRE = new RegExp("^[0-9]xx$", "i"); + +function isRetryableResponse(res: Response, statusCodes: string[]): boolean { + const actual = `${res.status}`; + + return statusCodes.some((code) => { + if (!codeRangeRE.test(code)) { + return code === actual; + } + + const expectFamily = code.charAt(0); + if (!expectFamily) { + throw new Error("Invalid status code range"); + } + + const actualFamily = actual.charAt(0); + if (!actualFamily) { + throw new Error(`Invalid response status code: ${actual}`); + } + + return actualFamily === expectFamily; + }); +} + +async function retryBackoff( + fn: () => Promise, + strategy: BackoffStrategy, +): Promise { + const { maxElapsedTime, initialInterval, exponent, maxInterval } = strategy; + + const start = Date.now(); + let x = 0; + + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const res = await fn(); + return res; + } catch (err: unknown) { + if (err instanceof PermanentError) { + throw err.cause; + } + const elapsed = Date.now() - start; + if (elapsed > maxElapsedTime) { + if (err instanceof TemporaryError) { + return err.response; + } + + throw err; + } + + let retryInterval = 0; + if (err instanceof TemporaryError) { + retryInterval = retryIntervalFromResponse(err.response); + } + + if (retryInterval <= 0) { + retryInterval = + initialInterval * Math.pow(x, exponent) + Math.random() * 1000; + } + + const d = Math.min(retryInterval, maxInterval); + + await delay(d); + x++; + } + } +} + +function retryIntervalFromResponse(res: Response): number { + const retryVal = res.headers.get("retry-after") || ""; + if (!retryVal) { + return 0; + } + + const parsedNumber = Number(retryVal); + if (Number.isInteger(parsedNumber)) { + return parsedNumber * 1000; + } + + const parsedDate = Date.parse(retryVal); + if (Number.isInteger(parsedDate)) { + const deltaMS = parsedDate - Date.now(); + return deltaMS > 0 ? Math.ceil(deltaMS) : 0; + } + + return 0; +} + +async function delay(delay: number): Promise { + return new Promise((resolve) => setTimeout(resolve, delay)); +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/schemas.ts b/frameworks-elysia/sdk-typescript/src/lib/schemas.ts new file mode 100644 index 00000000..f3856dcb --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/schemas.ts @@ -0,0 +1,86 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { + output, + ZodEffects, + ZodError, + ZodObject, + ZodRawShape, + ZodTypeAny, +} from "zod"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import { ERR, OK, Result } from "../types/fp.js"; + +/** + * Utility function that executes some code which may throw a ZodError. It + * intercepts this error and converts it to an SDKValidationError so as to not + * leak Zod implementation details to user code. + */ +export function parse( + rawValue: Inp, + fn: (value: Inp) => Out, + errorMessage: string, +): Out { + try { + return fn(rawValue); + } catch (err) { + if (err instanceof ZodError) { + throw new SDKValidationError(errorMessage, err, rawValue); + } + throw err; + } +} + +/** + * Utility function that executes some code which may result in a ZodError. It + * intercepts this error and converts it to an SDKValidationError so as to not + * leak Zod implementation details to user code. + */ +export function safeParse( + rawValue: Inp, + fn: (value: Inp) => Out, + errorMessage: string, +): Result { + try { + return OK(fn(rawValue)); + } catch (err) { + return ERR(new SDKValidationError(errorMessage, err, rawValue)); + } +} + +export function collectExtraKeys< + Shape extends ZodRawShape, + Catchall extends ZodTypeAny, + K extends string, +>( + obj: ZodObject, + extrasKey: K, +): ZodEffects< + typeof obj, + & output> + & { + [k in K]: Record>; + } +> { + return obj.transform((val) => { + const extras: Record> = {}; + const { shape } = obj; + for (const [key] of Object.entries(val)) { + if (key in shape) { + continue; + } + + const v = val[key]; + if (typeof v === "undefined") { + continue; + } + + extras[key] = v; + delete val[key]; + } + + return { ...val, [extrasKey]: extras }; + }); +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/sdks.ts b/frameworks-elysia/sdk-typescript/src/lib/sdks.ts new file mode 100644 index 00000000..3c27b591 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/sdks.ts @@ -0,0 +1,392 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKHooks } from "../hooks/hooks.js"; +import { HookContext } from "../hooks/types.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import { ERR, OK, Result } from "../types/fp.js"; +import { stringToBase64 } from "./base64.js"; +import { SDK_METADATA, SDKOptions, serverURLFromOptions } from "./config.js"; +import { encodeForm } from "./encodings.js"; +import { env } from "./env.js"; +import { + HTTPClient, + isAbortError, + isConnectionError, + isTimeoutError, + matchContentType, + matchStatusCode, +} from "./http.js"; +import { Logger } from "./logger.js"; +import { retry, RetryConfig } from "./retries.js"; +import { SecurityState } from "./security.js"; + +export type RequestOptions = { + /** + * Sets a timeout, in milliseconds, on HTTP requests made by an SDK method. If + * `fetchOptions.signal` is set then it will take precedence over this option. + */ + timeoutMs?: number; + /** + * Set or override a retry policy on HTTP calls. + */ + retries?: RetryConfig; + /** + * Specifies the status codes which should be retried using the given retry policy. + */ + retryCodes?: string[]; + /** + * Sets various request options on the `fetch` call made by an SDK method. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options|Request} + */ + fetchOptions?: Omit; +}; + +type RequestConfig = { + method: string; + path: string; + baseURL?: string | URL; + query?: string; + body?: RequestInit["body"]; + headers?: HeadersInit; + security?: SecurityState | null; + uaHeader?: string; + timeoutMs?: number; +}; + +const gt: unknown = typeof globalThis === "undefined" ? null : globalThis; +const webWorkerLike = typeof gt === "object" + && gt != null + && "importScripts" in gt + && typeof gt["importScripts"] === "function"; +const isBrowserLike = webWorkerLike + || (typeof navigator !== "undefined" && "serviceWorker" in navigator) + || (typeof window === "object" && typeof window.document !== "undefined"); + +export class ClientSDK { + readonly #httpClient: HTTPClient; + readonly #hooks: SDKHooks; + readonly #logger?: Logger | undefined; + protected readonly _baseURL: URL | null; + public readonly _options: SDKOptions & { hooks?: SDKHooks }; + + constructor(options: SDKOptions = {}) { + const opt = options as unknown; + if ( + typeof opt === "object" + && opt != null + && "hooks" in opt + && opt.hooks instanceof SDKHooks + ) { + this.#hooks = opt.hooks; + } else { + this.#hooks = new SDKHooks(); + } + this._options = { ...options, hooks: this.#hooks }; + + const url = serverURLFromOptions(options); + if (url) { + url.pathname = url.pathname.replace(/\/+$/, "") + "/"; + } + const { baseURL, client } = this.#hooks.sdkInit({ + baseURL: url, + client: options.httpClient || new HTTPClient(), + }); + this._baseURL = baseURL; + this.#httpClient = client; + this.#logger = options.debugLogger; + if (!this.#logger && env().SDK_DEBUG) { + this.#logger = console; + } + } + + public _createRequest( + context: HookContext, + conf: RequestConfig, + options?: RequestOptions, + ): Result { + const { method, path, query, headers: opHeaders, security } = conf; + + const base = conf.baseURL ?? this._baseURL; + if (!base) { + return ERR(new InvalidRequestError("No base URL provided for operation")); + } + const reqURL = new URL(base); + const inputURL = new URL(path, reqURL); + + if (path) { + reqURL.pathname += inputURL.pathname.replace(/^\/+/, ""); + } + + let finalQuery = query || ""; + + const secQuery: string[] = []; + for (const [k, v] of Object.entries(security?.queryParams || {})) { + secQuery.push(encodeForm(k, v, { charEncoding: "percent" })); + } + if (secQuery.length) { + finalQuery += `&${secQuery.join("&")}`; + } + + if (finalQuery) { + const q = finalQuery.startsWith("&") ? finalQuery.slice(1) : finalQuery; + reqURL.search = `?${q}`; + } + + const headers = new Headers(opHeaders); + + const username = security?.basic.username; + const password = security?.basic.password; + if (username != null || password != null) { + const encoded = stringToBase64( + [username || "", password || ""].join(":"), + ); + headers.set("Authorization", `Basic ${encoded}`); + } + + const securityHeaders = new Headers(security?.headers || {}); + for (const [k, v] of securityHeaders) { + headers.set(k, v); + } + + let cookie = headers.get("cookie") || ""; + for (const [k, v] of Object.entries(security?.cookies || {})) { + cookie += `; ${k}=${v}`; + } + cookie = cookie.startsWith("; ") ? cookie.slice(2) : cookie; + headers.set("cookie", cookie); + + const userHeaders = new Headers(options?.fetchOptions?.headers); + for (const [k, v] of userHeaders) { + headers.set(k, v); + } + + // Only set user agent header in non-browser-like environments since CORS + // policy disallows setting it in browsers e.g. Chrome throws an error. + if (!isBrowserLike) { + headers.set(conf.uaHeader ?? "user-agent", SDK_METADATA.userAgent); + } + + let fetchOptions = options?.fetchOptions; + if (!fetchOptions?.signal && conf.timeoutMs && conf.timeoutMs > 0) { + const timeoutSignal = AbortSignal.timeout(conf.timeoutMs); + if (!fetchOptions) { + fetchOptions = { signal: timeoutSignal }; + } else { + fetchOptions.signal = timeoutSignal; + } + } + + if (conf.body instanceof ReadableStream) { + if (!fetchOptions) { + fetchOptions = { + // @ts-expect-error see https://github.com/node-fetch/node-fetch/issues/1769 + duplex: "half", + }; + } else { + // @ts-expect-error see https://github.com/node-fetch/node-fetch/issues/1769 + fetchOptions.duplex = "half"; + } + } + + let input; + try { + input = this.#hooks.beforeCreateRequest(context, { + url: reqURL, + options: { + ...fetchOptions, + body: conf.body ?? null, + headers, + method, + }, + }); + } catch (err: unknown) { + return ERR( + new UnexpectedClientError("Create request hook failed to execute", { + cause: err, + }), + ); + } + + return OK(new Request(input.url, input.options)); + } + + public async _do( + request: Request, + options: { + context: HookContext; + errorCodes: number | string | (number | string)[]; + retryConfig: RetryConfig; + retryCodes: string[]; + }, + ): Promise< + Result< + Response, + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + | UnexpectedClientError + > + > { + const { context, errorCodes } = options; + + return retry( + async () => { + const req = await this.#hooks.beforeRequest(context, request.clone()); + await logRequest(this.#logger, req).catch((e) => + this.#logger?.log("Failed to log request:", e) + ); + + let response = await this.#httpClient.request(req); + + try { + if (matchStatusCode(response, errorCodes)) { + const result = await this.#hooks.afterError( + context, + response, + null, + ); + if (result.error) { + throw result.error; + } + response = result.response || response; + } else { + response = await this.#hooks.afterSuccess(context, response); + } + } finally { + await logResponse(this.#logger, response, req) + .catch(e => this.#logger?.log("Failed to log response:", e)); + } + + return response; + }, + { config: options.retryConfig, statusCodes: options.retryCodes }, + ).then( + (r) => OK(r), + (err) => { + switch (true) { + case isAbortError(err): + return ERR( + new RequestAbortedError("Request aborted by client", { + cause: err, + }), + ); + case isTimeoutError(err): + return ERR( + new RequestTimeoutError("Request timed out", { cause: err }), + ); + case isConnectionError(err): + return ERR( + new ConnectionError("Unable to make request", { cause: err }), + ); + default: + return ERR( + new UnexpectedClientError("Unexpected HTTP client error", { + cause: err, + }), + ); + } + }, + ); + } +} + +const jsonLikeContentTypeRE = /^application\/(?:.{0,100}\+)?json/; +async function logRequest(logger: Logger | undefined, req: Request) { + if (!logger) { + return; + } + + const contentType = req.headers.get("content-type"); + const ct = contentType?.split(";")[0] || ""; + + logger.group(`> Request: ${req.method} ${req.url}`); + + logger.group("Headers:"); + for (const [k, v] of req.headers.entries()) { + logger.log(`${k}: ${v}`); + } + logger.groupEnd(); + + logger.group("Body:"); + switch (true) { + case jsonLikeContentTypeRE.test(ct): + logger.log(await req.clone().json()); + break; + case ct.startsWith("text/"): + logger.log(await req.clone().text()); + break; + case ct === "multipart/form-data": { + const body = await req.clone().formData(); + for (const [k, v] of body) { + const vlabel = v instanceof Blob ? "" : v; + logger.log(`${k}: ${vlabel}`); + } + break; + } + default: + logger.log(`<${contentType}>`); + break; + } + logger.groupEnd(); + + logger.groupEnd(); +} + +async function logResponse( + logger: Logger | undefined, + res: Response, + req: Request, +) { + if (!logger) { + return; + } + + const contentType = res.headers.get("content-type"); + const ct = contentType?.split(";")[0] || ""; + + logger.group(`< Response: ${req.method} ${req.url}`); + logger.log("Status Code:", res.status, res.statusText); + + logger.group("Headers:"); + for (const [k, v] of res.headers.entries()) { + logger.log(`${k}: ${v}`); + } + logger.groupEnd(); + + logger.group("Body:"); + switch (true) { + case matchContentType(res, "application/json") + || jsonLikeContentTypeRE.test(ct): + logger.log(await res.clone().json()); + break; + case matchContentType(res, "text/event-stream"): + logger.log(`<${contentType}>`); + break; + case matchContentType(res, "text/*"): + logger.log(await res.clone().text()); + break; + case matchContentType(res, "multipart/form-data"): { + const body = await res.clone().formData(); + for (const [k, v] of body) { + const vlabel = v instanceof Blob ? "" : v; + logger.log(`${k}: ${vlabel}`); + } + break; + } + default: + logger.log(`<${contentType}>`); + break; + } + logger.groupEnd(); + + logger.groupEnd(); +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/security.ts b/frameworks-elysia/sdk-typescript/src/lib/security.ts new file mode 100644 index 00000000..321e02fe --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/security.ts @@ -0,0 +1,227 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +type OAuth2PasswordFlow = { + username: string; + password?: string | undefined; + clientID: string; + clientSecret?: string | undefined; + tokenURL: string; +}; + +export enum SecurityErrorCode { + Incomplete = "incomplete", + UnrecognisedSecurityType = "unrecognized_security_type", +} + +export class SecurityError extends Error { + constructor( + public code: SecurityErrorCode, + message: string, + ) { + super(message); + this.name = "SecurityError"; + } + + static incomplete(): SecurityError { + return new SecurityError( + SecurityErrorCode.Incomplete, + "Security requirements not met in order to perform the operation", + ); + } + static unrecognizedType(type: string): SecurityError { + return new SecurityError( + SecurityErrorCode.UnrecognisedSecurityType, + `Unrecognised security type: ${type}`, + ); + } +} + +export type SecurityState = { + basic: { username?: string | undefined; password?: string | undefined }; + headers: Record; + queryParams: Record; + cookies: Record; + oauth2: ({ type: "password" } & OAuth2PasswordFlow) | { type: "none" }; +}; + +type SecurityInputBasic = { + type: "http:basic"; + value: + | { username?: string | undefined; password?: string | undefined } + | null + | undefined; +}; + +type SecurityInputBearer = { + type: "http:bearer"; + value: string | null | undefined; + fieldName: string; +}; + +type SecurityInputAPIKey = { + type: "apiKey:header" | "apiKey:query" | "apiKey:cookie"; + value: string | null | undefined; + fieldName: string; +}; + +type SecurityInputOIDC = { + type: "openIdConnect"; + value: string | null | undefined; + fieldName: string; +}; + +type SecurityInputOAuth2 = { + type: "oauth2"; + value: string | null | undefined; + fieldName: string; +}; + +type SecurityInputOAuth2ClientCredentials = { + type: "oauth2:client_credentials"; + value: + | { clientID?: string | undefined; clientSecret?: string | undefined } + | null + | undefined; +}; + +type SecurityInputOAuth2PasswordCredentials = { + type: "oauth2:password"; + value: + | string + | null + | undefined; + fieldName: string; +}; + +type SecurityInputCustom = { + type: "http:custom"; + value: any | null | undefined; + fieldName: string; +}; + +export type SecurityInput = + | SecurityInputBasic + | SecurityInputBearer + | SecurityInputAPIKey + | SecurityInputOAuth2 + | SecurityInputOAuth2ClientCredentials + | SecurityInputOAuth2PasswordCredentials + | SecurityInputOIDC + | SecurityInputCustom; + +export function resolveSecurity( + ...options: SecurityInput[][] +): SecurityState | null { + const state: SecurityState = { + basic: { username: "", password: "" }, + headers: {}, + queryParams: {}, + cookies: {}, + oauth2: { type: "none" }, + }; + + const option = options.find((opts) => { + return opts.every((o) => { + if (o.value == null) { + return false; + } else if (o.type === "http:basic") { + return o.value.username != null || o.value.password != null; + } else if (o.type === "http:custom") { + return null; + } else if (o.type === "oauth2:password") { + return ( + typeof o.value === "string" && !!o.value + ); + } else if (o.type === "oauth2:client_credentials") { + return o.value.clientID != null || o.value.clientSecret != null; + } else if (typeof o.value === "string") { + return !!o.value; + } else { + throw new Error( + `Unrecognized security type: ${o.type} (value type: ${typeof o + .value})`, + ); + } + }); + }); + if (option == null) { + return null; + } + + option.forEach((spec) => { + if (spec.value == null) { + return; + } + + const { type } = spec; + + switch (type) { + case "apiKey:header": + state.headers[spec.fieldName] = spec.value; + break; + case "apiKey:query": + state.queryParams[spec.fieldName] = spec.value; + break; + case "apiKey:cookie": + state.cookies[spec.fieldName] = spec.value; + break; + case "http:basic": + applyBasic(state, spec); + break; + case "http:custom": + break; + case "http:bearer": + applyBearer(state, spec); + break; + case "oauth2": + applyBearer(state, spec); + break; + case "oauth2:password": + applyBearer(state, spec); + break; + case "oauth2:client_credentials": + break; + case "openIdConnect": + applyBearer(state, spec); + break; + default: + spec satisfies never; + throw SecurityError.unrecognizedType(type); + } + }); + + return state; +} + +function applyBasic( + state: SecurityState, + spec: SecurityInputBasic, +) { + if (spec.value == null) { + return; + } + + state.basic = spec.value; +} + +function applyBearer( + state: SecurityState, + spec: + | SecurityInputBearer + | SecurityInputOAuth2 + | SecurityInputOIDC + | SecurityInputOAuth2PasswordCredentials, +) { + if (typeof spec.value !== "string" || !spec.value) { + return; + } + + let value = spec.value; + if (value.slice(0, 7).toLowerCase() !== "bearer ") { + value = `Bearer ${value}`; + } + + state.headers[spec.fieldName] = value; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/url.ts b/frameworks-elysia/sdk-typescript/src/lib/url.ts new file mode 100644 index 00000000..6bc6356e --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/lib/url.ts @@ -0,0 +1,33 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +const hasOwn = Object.prototype.hasOwnProperty; + +export type Params = Partial>; + +export function pathToFunc( + pathPattern: string, + options?: { charEncoding?: "percent" | "none" }, +): (params?: Params) => string { + const paramRE = /\{([a-zA-Z0-9_]+?)\}/g; + + return function buildURLPath(params: Record = {}): string { + return pathPattern.replace(paramRE, function (_, placeholder) { + if (!hasOwn.call(params, placeholder)) { + throw new Error(`Parameter '${placeholder}' is required`); + } + + const value = params[placeholder]; + if (typeof value !== "string" && typeof value !== "number") { + throw new Error( + `Parameter '${placeholder}' must be a string or number`, + ); + } + + return options?.charEncoding === "percent" + ? encodeURIComponent(`${value}`) + : `${value}`; + }); + }; +} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/id.ts b/frameworks-elysia/sdk-typescript/src/models/components/id.ts new file mode 100644 index 00000000..53670909 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/components/id.ts @@ -0,0 +1,55 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type Id = { + id: string; +}; + +/** @internal */ +export const Id$inboundSchema: z.ZodType = z.object({ + id: z.string(), +}); + +/** @internal */ +export type Id$Outbound = { + id: string; +}; + +/** @internal */ +export const Id$outboundSchema: z.ZodType = z + .object({ + id: z.string(), + }); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace Id$ { + /** @deprecated use `Id$inboundSchema` instead. */ + export const inboundSchema = Id$inboundSchema; + /** @deprecated use `Id$outboundSchema` instead. */ + export const outboundSchema = Id$outboundSchema; + /** @deprecated use `Id$Outbound` instead. */ + export type Outbound = Id$Outbound; +} + +export function idToJSON(id: Id): string { + return JSON.stringify(Id$outboundSchema.parse(id)); +} + +export function idFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => Id$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'Id' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/index.ts b/frameworks-elysia/sdk-typescript/src/models/components/index.ts new file mode 100644 index 00000000..e3ff5bee --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/components/index.ts @@ -0,0 +1,7 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./id.js"; +export * from "./successresponse.js"; +export * from "./user.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts b/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts new file mode 100644 index 00000000..147c8885 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts @@ -0,0 +1,64 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type SuccessResponse = { + success: boolean; +}; + +/** @internal */ +export const SuccessResponse$inboundSchema: z.ZodType< + SuccessResponse, + z.ZodTypeDef, + unknown +> = z.object({ + success: z.boolean(), +}); + +/** @internal */ +export type SuccessResponse$Outbound = { + success: boolean; +}; + +/** @internal */ +export const SuccessResponse$outboundSchema: z.ZodType< + SuccessResponse$Outbound, + z.ZodTypeDef, + SuccessResponse +> = z.object({ + success: z.boolean(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace SuccessResponse$ { + /** @deprecated use `SuccessResponse$inboundSchema` instead. */ + export const inboundSchema = SuccessResponse$inboundSchema; + /** @deprecated use `SuccessResponse$outboundSchema` instead. */ + export const outboundSchema = SuccessResponse$outboundSchema; + /** @deprecated use `SuccessResponse$Outbound` instead. */ + export type Outbound = SuccessResponse$Outbound; +} + +export function successResponseToJSON( + successResponse: SuccessResponse, +): string { + return JSON.stringify(SuccessResponse$outboundSchema.parse(successResponse)); +} + +export function successResponseFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => SuccessResponse$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'SuccessResponse' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/user.ts b/frameworks-elysia/sdk-typescript/src/models/components/user.ts new file mode 100644 index 00000000..162163b2 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/components/user.ts @@ -0,0 +1,64 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type User = { + id: string; + name: string; + age: number; +}; + +/** @internal */ +export const User$inboundSchema: z.ZodType = z + .object({ + id: z.string(), + name: z.string(), + age: z.number(), + }); + +/** @internal */ +export type User$Outbound = { + id: string; + name: string; + age: number; +}; + +/** @internal */ +export const User$outboundSchema: z.ZodType = + z.object({ + id: z.string(), + name: z.string(), + age: z.number(), + }); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace User$ { + /** @deprecated use `User$inboundSchema` instead. */ + export const inboundSchema = User$inboundSchema; + /** @deprecated use `User$outboundSchema` instead. */ + export const outboundSchema = User$outboundSchema; + /** @deprecated use `User$Outbound` instead. */ + export type Outbound = User$Outbound; +} + +export function userToJSON(user: User): string { + return JSON.stringify(User$outboundSchema.parse(user)); +} + +export function userFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => User$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'User' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts new file mode 100644 index 00000000..3a04a1c3 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts @@ -0,0 +1,27 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export class APIError extends Error { + public readonly statusCode: number; + public readonly contentType: string; + + constructor( + message: string, + public readonly rawResponse: Response, + public readonly body: string = "", + ) { + const statusCode = rawResponse.status; + const contentType = rawResponse.headers.get("content-type") || ""; + const bodyString = body.length > 0 ? `\n${body}` : ""; + + super( + `${message}: Status ${statusCode} Content-Type ${contentType} Body ${bodyString}`, + ); + + this.statusCode = statusCode; + this.contentType = contentType; + + this.name = "APIError"; + } +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts b/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts new file mode 100644 index 00000000..077926df --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts @@ -0,0 +1,73 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export type ErrorResponseData = { + status: number; + message: string; +}; + +export class ErrorResponse extends Error { + status: number; + + /** The original data that was passed to this error instance. */ + data$: ErrorResponseData; + + constructor(err: ErrorResponseData) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message); + this.data$ = err; + + this.status = err.status; + + this.name = "ErrorResponse"; + } +} + +/** @internal */ +export const ErrorResponse$inboundSchema: z.ZodType< + ErrorResponse, + z.ZodTypeDef, + unknown +> = z.object({ + status: z.number(), + message: z.string(), +}) + .transform((v) => { + return new ErrorResponse(v); + }); + +/** @internal */ +export type ErrorResponse$Outbound = { + status: number; + message: string; +}; + +/** @internal */ +export const ErrorResponse$outboundSchema: z.ZodType< + ErrorResponse$Outbound, + z.ZodTypeDef, + ErrorResponse +> = z.instanceof(ErrorResponse) + .transform(v => v.data$) + .pipe(z.object({ + status: z.number(), + message: z.string(), + })); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace ErrorResponse$ { + /** @deprecated use `ErrorResponse$inboundSchema` instead. */ + export const inboundSchema = ErrorResponse$inboundSchema; + /** @deprecated use `ErrorResponse$outboundSchema` instead. */ + export const outboundSchema = ErrorResponse$outboundSchema; + /** @deprecated use `ErrorResponse$Outbound` instead. */ + export type Outbound = ErrorResponse$Outbound; +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/httpclienterrors.ts b/frameworks-elysia/sdk-typescript/src/models/errors/httpclienterrors.ts new file mode 100644 index 00000000..b34f6121 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/httpclienterrors.ts @@ -0,0 +1,62 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/** + * Base class for all HTTP errors. + */ +export class HTTPClientError extends Error { + /** The underlying cause of the error. */ + override readonly cause: unknown; + override name = "HTTPClientError"; + constructor(message: string, opts?: { cause?: unknown }) { + let msg = message; + if (opts?.cause) { + msg += `: ${opts.cause}`; + } + + super(msg, opts); + // In older runtimes, the cause field would not have been assigned through + // the super() call. + if (typeof this.cause === "undefined") { + this.cause = opts?.cause; + } + } +} + +/** + * An error to capture unrecognised or unexpected errors when making HTTP calls. + */ +export class UnexpectedClientError extends HTTPClientError { + override name = "UnexpectedClientError"; +} + +/** + * An error that is raised when any inputs used to create a request are invalid. + */ +export class InvalidRequestError extends HTTPClientError { + override name = "InvalidRequestError"; +} + +/** + * An error that is raised when a HTTP request was aborted by the client error. + */ +export class RequestAbortedError extends HTTPClientError { + override readonly name = "RequestAbortedError"; +} + +/** + * An error that is raised when a HTTP request timed out due to an AbortSignal + * signal timeout. + */ +export class RequestTimeoutError extends HTTPClientError { + override readonly name = "RequestTimeoutError"; +} + +/** + * An error that is raised when a HTTP client is unable to make a request to + * a server. + */ +export class ConnectionError extends HTTPClientError { + override readonly name = "ConnectionError"; +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/index.ts b/frameworks-elysia/sdk-typescript/src/models/errors/index.ts new file mode 100644 index 00000000..17185050 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/index.ts @@ -0,0 +1,8 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./apierror.js"; +export * from "./errorresponse.js"; +export * from "./httpclienterrors.js"; +export * from "./sdkvalidationerror.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts new file mode 100644 index 00000000..16929b9e --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts @@ -0,0 +1,97 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export class SDKValidationError extends Error { + /** + * The raw value that failed validation. + */ + public readonly rawValue: unknown; + + /** + * The raw message that failed validation. + */ + public readonly rawMessage: unknown; + + constructor(message: string, cause: unknown, rawValue: unknown) { + super(`${message}: ${cause}`); + this.name = "SDKValidationError"; + this.cause = cause; + this.rawValue = rawValue; + this.rawMessage = message; + } + + /** + * Return a pretty-formatted error message if the underlying validation error + * is a ZodError or some other recognized error type, otherwise return the + * default error message. + */ + public pretty(): string { + if (this.cause instanceof z.ZodError) { + return `${this.rawMessage}\n${formatZodError(this.cause)}`; + } else { + return this.toString(); + } + } +} + +export function formatZodError(err: z.ZodError, level = 0): string { + let pre = " ".repeat(level); + pre = level > 0 ? `│${pre}` : pre; + pre += " ".repeat(level); + + let message = ""; + const append = (str: string) => (message += `\n${pre}${str}`); + + const len = err.issues.length; + const headline = len === 1 ? `${len} issue found` : `${len} issues found`; + + if (len) { + append(`┌ ${headline}:`); + } + + for (const issue of err.issues) { + let path = issue.path.join("."); + path = path ? `.${path}` : ""; + append(`│ • [${path}]: ${issue.message} (${issue.code})`); + switch (issue.code) { + case "invalid_literal": + case "invalid_type": { + append(`│ Want: ${issue.expected}`); + append(`│ Got: ${issue.received}`); + break; + } + case "unrecognized_keys": { + append(`│ Keys: ${issue.keys.join(", ")}`); + break; + } + case "invalid_enum_value": { + append(`│ Allowed: ${issue.options.join(", ")}`); + append(`│ Got: ${issue.received}`); + break; + } + case "invalid_union_discriminator": { + append(`│ Allowed: ${issue.options.join(", ")}`); + break; + } + case "invalid_union": { + const len = issue.unionErrors.length; + append( + `│ ✖︎ Attemped to deserialize into one of ${len} union members:`, + ); + issue.unionErrors.forEach((err, i) => { + append(`│ ✖︎ Member ${i + 1} of ${len}`); + append(`${formatZodError(err, level + 1)}`); + }); + } + } + } + + if (err.issues.length) { + append(`└─*`); + } + + return message.slice(1); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts new file mode 100644 index 00000000..a28e9218 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts @@ -0,0 +1,66 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type DeleteUsersByIdRequest = { + id: string; +}; + +/** @internal */ +export const DeleteUsersByIdRequest$inboundSchema: z.ZodType< + DeleteUsersByIdRequest, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), +}); + +/** @internal */ +export type DeleteUsersByIdRequest$Outbound = { + id: string; +}; + +/** @internal */ +export const DeleteUsersByIdRequest$outboundSchema: z.ZodType< + DeleteUsersByIdRequest$Outbound, + z.ZodTypeDef, + DeleteUsersByIdRequest +> = z.object({ + id: z.string(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace DeleteUsersByIdRequest$ { + /** @deprecated use `DeleteUsersByIdRequest$inboundSchema` instead. */ + export const inboundSchema = DeleteUsersByIdRequest$inboundSchema; + /** @deprecated use `DeleteUsersByIdRequest$outboundSchema` instead. */ + export const outboundSchema = DeleteUsersByIdRequest$outboundSchema; + /** @deprecated use `DeleteUsersByIdRequest$Outbound` instead. */ + export type Outbound = DeleteUsersByIdRequest$Outbound; +} + +export function deleteUsersByIdRequestToJSON( + deleteUsersByIdRequest: DeleteUsersByIdRequest, +): string { + return JSON.stringify( + DeleteUsersByIdRequest$outboundSchema.parse(deleteUsersByIdRequest), + ); +} + +export function deleteUsersByIdRequestFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => DeleteUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'DeleteUsersByIdRequest' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts new file mode 100644 index 00000000..d6c88a1c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts @@ -0,0 +1,66 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type GetUsersByIdRequest = { + id: string; +}; + +/** @internal */ +export const GetUsersByIdRequest$inboundSchema: z.ZodType< + GetUsersByIdRequest, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), +}); + +/** @internal */ +export type GetUsersByIdRequest$Outbound = { + id: string; +}; + +/** @internal */ +export const GetUsersByIdRequest$outboundSchema: z.ZodType< + GetUsersByIdRequest$Outbound, + z.ZodTypeDef, + GetUsersByIdRequest +> = z.object({ + id: z.string(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace GetUsersByIdRequest$ { + /** @deprecated use `GetUsersByIdRequest$inboundSchema` instead. */ + export const inboundSchema = GetUsersByIdRequest$inboundSchema; + /** @deprecated use `GetUsersByIdRequest$outboundSchema` instead. */ + export const outboundSchema = GetUsersByIdRequest$outboundSchema; + /** @deprecated use `GetUsersByIdRequest$Outbound` instead. */ + export type Outbound = GetUsersByIdRequest$Outbound; +} + +export function getUsersByIdRequestToJSON( + getUsersByIdRequest: GetUsersByIdRequest, +): string { + return JSON.stringify( + GetUsersByIdRequest$outboundSchema.parse(getUsersByIdRequest), + ); +} + +export function getUsersByIdRequestFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetUsersByIdRequest' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/index.ts b/frameworks-elysia/sdk-typescript/src/models/operations/index.ts new file mode 100644 index 00000000..83476b75 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/index.ts @@ -0,0 +1,8 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./deleteusersbyid.js"; +export * from "./getusersbyid.js"; +export * from "./patchusersbyid.js"; +export * from "./postusers.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts new file mode 100644 index 00000000..0513699b --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts @@ -0,0 +1,141 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type PatchUsersByIdRequestBody = { + name?: string | undefined; + age?: number | undefined; +}; + +export type PatchUsersByIdRequest = { + id: string; + requestBody: PatchUsersByIdRequestBody; +}; + +/** @internal */ +export const PatchUsersByIdRequestBody$inboundSchema: z.ZodType< + PatchUsersByIdRequestBody, + z.ZodTypeDef, + unknown +> = z.object({ + name: z.string().optional(), + age: z.number().optional(), +}); + +/** @internal */ +export type PatchUsersByIdRequestBody$Outbound = { + name?: string | undefined; + age?: number | undefined; +}; + +/** @internal */ +export const PatchUsersByIdRequestBody$outboundSchema: z.ZodType< + PatchUsersByIdRequestBody$Outbound, + z.ZodTypeDef, + PatchUsersByIdRequestBody +> = z.object({ + name: z.string().optional(), + age: z.number().optional(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace PatchUsersByIdRequestBody$ { + /** @deprecated use `PatchUsersByIdRequestBody$inboundSchema` instead. */ + export const inboundSchema = PatchUsersByIdRequestBody$inboundSchema; + /** @deprecated use `PatchUsersByIdRequestBody$outboundSchema` instead. */ + export const outboundSchema = PatchUsersByIdRequestBody$outboundSchema; + /** @deprecated use `PatchUsersByIdRequestBody$Outbound` instead. */ + export type Outbound = PatchUsersByIdRequestBody$Outbound; +} + +export function patchUsersByIdRequestBodyToJSON( + patchUsersByIdRequestBody: PatchUsersByIdRequestBody, +): string { + return JSON.stringify( + PatchUsersByIdRequestBody$outboundSchema.parse(patchUsersByIdRequestBody), + ); +} + +export function patchUsersByIdRequestBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => PatchUsersByIdRequestBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'PatchUsersByIdRequestBody' from JSON`, + ); +} + +/** @internal */ +export const PatchUsersByIdRequest$inboundSchema: z.ZodType< + PatchUsersByIdRequest, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + RequestBody: z.lazy(() => PatchUsersByIdRequestBody$inboundSchema), +}).transform((v) => { + return remap$(v, { + "RequestBody": "requestBody", + }); +}); + +/** @internal */ +export type PatchUsersByIdRequest$Outbound = { + id: string; + RequestBody: PatchUsersByIdRequestBody$Outbound; +}; + +/** @internal */ +export const PatchUsersByIdRequest$outboundSchema: z.ZodType< + PatchUsersByIdRequest$Outbound, + z.ZodTypeDef, + PatchUsersByIdRequest +> = z.object({ + id: z.string(), + requestBody: z.lazy(() => PatchUsersByIdRequestBody$outboundSchema), +}).transform((v) => { + return remap$(v, { + requestBody: "RequestBody", + }); +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace PatchUsersByIdRequest$ { + /** @deprecated use `PatchUsersByIdRequest$inboundSchema` instead. */ + export const inboundSchema = PatchUsersByIdRequest$inboundSchema; + /** @deprecated use `PatchUsersByIdRequest$outboundSchema` instead. */ + export const outboundSchema = PatchUsersByIdRequest$outboundSchema; + /** @deprecated use `PatchUsersByIdRequest$Outbound` instead. */ + export type Outbound = PatchUsersByIdRequest$Outbound; +} + +export function patchUsersByIdRequestToJSON( + patchUsersByIdRequest: PatchUsersByIdRequest, +): string { + return JSON.stringify( + PatchUsersByIdRequest$outboundSchema.parse(patchUsersByIdRequest), + ); +} + +export function patchUsersByIdRequestFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => PatchUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'PatchUsersByIdRequest' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts b/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts new file mode 100644 index 00000000..5a077b17 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts @@ -0,0 +1,70 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type PostUsersRequestBody = { + name: string; + age: number; +}; + +/** @internal */ +export const PostUsersRequestBody$inboundSchema: z.ZodType< + PostUsersRequestBody, + z.ZodTypeDef, + unknown +> = z.object({ + name: z.string(), + age: z.number(), +}); + +/** @internal */ +export type PostUsersRequestBody$Outbound = { + name: string; + age: number; +}; + +/** @internal */ +export const PostUsersRequestBody$outboundSchema: z.ZodType< + PostUsersRequestBody$Outbound, + z.ZodTypeDef, + PostUsersRequestBody +> = z.object({ + name: z.string(), + age: z.number(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace PostUsersRequestBody$ { + /** @deprecated use `PostUsersRequestBody$inboundSchema` instead. */ + export const inboundSchema = PostUsersRequestBody$inboundSchema; + /** @deprecated use `PostUsersRequestBody$outboundSchema` instead. */ + export const outboundSchema = PostUsersRequestBody$outboundSchema; + /** @deprecated use `PostUsersRequestBody$Outbound` instead. */ + export type Outbound = PostUsersRequestBody$Outbound; +} + +export function postUsersRequestBodyToJSON( + postUsersRequestBody: PostUsersRequestBody, +): string { + return JSON.stringify( + PostUsersRequestBody$outboundSchema.parse(postUsersRequestBody), + ); +} + +export function postUsersRequestBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => PostUsersRequestBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'PostUsersRequestBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/index.ts b/frameworks-elysia/sdk-typescript/src/sdk/index.ts new file mode 100644 index 00000000..ecac2264 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/index.ts @@ -0,0 +1,5 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export * from "./sdk.js"; diff --git a/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts b/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts new file mode 100644 index 00000000..e0d3fd62 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts @@ -0,0 +1,13 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { ClientSDK } from "../lib/sdks.js"; +import { Users } from "./users.js"; + +export class SDK extends ClientSDK { + private _users?: Users; + get users(): Users { + return (this._users ??= new Users(this._options)); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/users.ts b/frameworks-elysia/sdk-typescript/src/sdk/users.ts new file mode 100644 index 00000000..aee12068 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/users.ts @@ -0,0 +1,98 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { usersDeleteUsersById } from "../funcs/usersDeleteUsersById.js"; +import { usersGetUsers } from "../funcs/usersGetUsers.js"; +import { usersGetUsersById } from "../funcs/usersGetUsersById.js"; +import { usersPatchUsersById } from "../funcs/usersPatchUsersById.js"; +import { usersPostUsers } from "../funcs/usersPostUsers.js"; +import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import * as components from "../models/components/index.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; + +export class Users extends ClientSDK { + /** + * Get all users + * + * @remarks + * Get all users from the database + */ + async getUsers( + options?: RequestOptions, + ): Promise> { + return unwrapAsync(usersGetUsers( + this, + options, + )); + } + + /** + * Create user + * + * @remarks + * Add user to the database + */ + async postUsers( + request: operations.PostUsersRequestBody, + options?: RequestOptions, + ): Promise { + return unwrapAsync(usersPostUsers( + this, + request, + options, + )); + } + + /** + * Get user + * + * @remarks + * Get user by id from the database + */ + async getUsersById( + request: operations.GetUsersByIdRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(usersGetUsersById( + this, + request, + options, + )); + } + + /** + * Delete user + * + * @remarks + * Delete user by id from the database + */ + async deleteUsersById( + request: operations.DeleteUsersByIdRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(usersDeleteUsersById( + this, + request, + options, + )); + } + + /** + * Update user + * + * @remarks + * Update user by id from the database + */ + async patchUsersById( + request: operations.PatchUsersByIdRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(usersPatchUsersById( + this, + request, + options, + )); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/types/blobs.ts b/frameworks-elysia/sdk-typescript/src/types/blobs.ts new file mode 100644 index 00000000..4ce84602 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/blobs.ts @@ -0,0 +1,31 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export const blobLikeSchema: z.ZodType = + z.custom(isBlobLike, { + message: "expected a Blob, File or Blob-like object", + fatal: true, + }); + +export function isBlobLike(val: unknown): val is Blob { + if (val instanceof Blob) { + return true; + } + + if (typeof val !== "object" || val == null || !(Symbol.toStringTag in val)) { + return false; + } + + const name = val[Symbol.toStringTag]; + if (typeof name !== "string") { + return false; + } + if (name !== "Blob" && name !== "File") { + return false; + } + + return "stream" in val && typeof val.stream === "function"; +} diff --git a/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts b/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts new file mode 100644 index 00000000..c0a4409c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts @@ -0,0 +1,15 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export function constDateTime( + val: string, +): z.ZodType { + return z.custom((v) => { + return ( + typeof v === "string" && new Date(v).getTime() === new Date(val).getTime() + ); + }, `Value must be equivelant to ${val}`); +} diff --git a/frameworks-elysia/sdk-typescript/src/types/enums.ts b/frameworks-elysia/sdk-typescript/src/types/enums.ts new file mode 100644 index 00000000..6fb6d910 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/enums.ts @@ -0,0 +1,16 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +declare const __brand: unique symbol; +export type Unrecognized = T & { [__brand]: "unrecognized" }; + +export function catchUnrecognizedEnum(value: T): Unrecognized { + return value as Unrecognized; +} + +type Prettify = { [K in keyof T]: T[K] } & {}; +export type ClosedEnum = T[keyof T]; +export type OpenEnum = + | Prettify + | Unrecognized; diff --git a/frameworks-elysia/sdk-typescript/src/types/fp.ts b/frameworks-elysia/sdk-typescript/src/types/fp.ts new file mode 100644 index 00000000..ccbe51ea --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/fp.ts @@ -0,0 +1,50 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/** + * A monad that captures the result of a function call or an error if it was not + * successful. Railway programming, enabled by this type, can be a nicer + * alternative to traditional exception throwing because it allows functions to + * declare all _known_ errors with static types and then check for them + * exhaustively in application code. Thrown exception have a type of `unknown` + * and break out of regular control flow of programs making them harder to + * inspect and more verbose work with due to try-catch blocks. + */ +export type Result = + | { ok: true; value: T; error?: never } + | { ok: false; value?: never; error: E }; + +export function OK(value: V): Result { + return { ok: true, value }; +} + +export function ERR(error: E): Result { + return { ok: false, error }; +} + +/** + * unwrap is a convenience function for extracting a value from a result or + * throwing if there was an error. + */ +export function unwrap(r: Result): T { + if (!r.ok) { + throw r.error; + } + return r.value; +} + +/** + * unwrapAsync is a convenience function for resolving a value from a Promise + * of a result or rejecting if an error occurred. + */ +export async function unwrapAsync( + pr: Promise>, +): Promise { + const r = await pr; + if (!r.ok) { + throw r.error; + } + + return r.value; +} diff --git a/frameworks-elysia/sdk-typescript/src/types/index.ts b/frameworks-elysia/sdk-typescript/src/types/index.ts new file mode 100644 index 00000000..e124e817 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/index.ts @@ -0,0 +1,11 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export { blobLikeSchema, isBlobLike } from "./blobs.js"; +export { catchUnrecognizedEnum } from "./enums.js"; +export type { ClosedEnum, OpenEnum, Unrecognized } from "./enums.js"; +export type { Result } from "./fp.js"; +export type { PageIterator, Paginator } from "./operations.js"; +export { createPageIterator } from "./operations.js"; +export { RFCDate } from "./rfcdate.js"; diff --git a/frameworks-elysia/sdk-typescript/src/types/operations.ts b/frameworks-elysia/sdk-typescript/src/types/operations.ts new file mode 100644 index 00000000..beb81e10 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/operations.ts @@ -0,0 +1,105 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { Result } from "./fp.js"; + +export type Paginator = () => Promise }> | null; + +export type PageIterator = V & { + next: Paginator; + [Symbol.asyncIterator]: () => AsyncIterableIterator; + "~next"?: PageState | undefined; +}; + +export function createPageIterator( + page: V & { next: Paginator }, + halt: (v: V) => boolean, +): { + [Symbol.asyncIterator]: () => AsyncIterableIterator; +} { + return { + [Symbol.asyncIterator]: async function* paginator() { + yield page; + if (halt(page)) { + return; + } + + let p: typeof page | null = page; + for (p = await p.next(); p != null; p = await p.next()) { + yield p; + if (halt(p)) { + return; + } + } + }, + }; +} + +/** + * This utility create a special iterator that yields a single value and + * terminates. It is useful in paginated SDK functions that have early return + * paths when things go wrong. + */ +export function haltIterator( + v: V, +): PageIterator { + return { + ...v, + next: () => null, + [Symbol.asyncIterator]: async function* paginator() { + yield v; + }, + }; +} + +/** + * Converts an async iterator of `Result` into an async iterator of `V`. + * When error results occur, the underlying error value is thrown. + */ +export async function unwrapResultIterator( + iteratorPromise: Promise, PageState>>, +): Promise> { + const resultIter = await iteratorPromise; + + if (!resultIter.ok) { + throw resultIter.error; + } + + return { + ...resultIter.value, + next: unwrapPaginator(resultIter.next), + "~next": resultIter["~next"], + [Symbol.asyncIterator]: async function* paginator() { + for await (const page of resultIter) { + if (!page.ok) { + throw page.error; + } + yield page.value; + } + }, + }; +} + +function unwrapPaginator( + paginator: Paginator>, +): Paginator { + return () => { + const nextResult = paginator(); + if (nextResult == null) { + return null; + } + return nextResult.then((res) => { + if (!res.ok) { + throw res.error; + } + const out = { + ...res.value, + next: unwrapPaginator(res.next), + }; + return out; + }); + }; +} + +export const URL_OVERRIDE = Symbol("URL_OVERRIDE"); diff --git a/frameworks-elysia/sdk-typescript/src/types/rfcdate.ts b/frameworks-elysia/sdk-typescript/src/types/rfcdate.ts new file mode 100644 index 00000000..c79b3f53 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/rfcdate.ts @@ -0,0 +1,54 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +const dateRE = /^\d{4}-\d{2}-\d{2}$/; + +export class RFCDate { + private serialized: string; + + /** + * Creates a new RFCDate instance using today's date. + */ + static today(): RFCDate { + return new RFCDate(new Date()); + } + + /** + * Creates a new RFCDate instance using the provided input. + * If a string is used then in must be in the format YYYY-MM-DD. + * + * @param date A Date object or a date string in YYYY-MM-DD format + * @example + * new RFCDate("2022-01-01") + * @example + * new RFCDate(new Date()) + */ + constructor(date: Date | string) { + if (typeof date === "string" && !dateRE.test(date)) { + throw new RangeError( + "RFCDate: date strings must be in the format YYYY-MM-DD: " + date, + ); + } + + const value = new Date(date); + if (isNaN(+value)) { + throw new RangeError("RFCDate: invalid date provided: " + date); + } + + this.serialized = value.toISOString().slice(0, "YYYY-MM-DD".length); + if (!dateRE.test(this.serialized)) { + throw new TypeError( + `RFCDate: failed to build valid date with given value: ${date} serialized to ${this.serialized}`, + ); + } + } + + toJSON(): string { + return this.toString(); + } + + toString(): string { + return this.serialized; + } +} diff --git a/frameworks-elysia/sdk-typescript/src/types/streams.ts b/frameworks-elysia/sdk-typescript/src/types/streams.ts new file mode 100644 index 00000000..a0163e7a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/streams.ts @@ -0,0 +1,21 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export function isReadableStream( + val: unknown, +): val is ReadableStream { + if (typeof val !== "object" || val === null) { + return false; + } + + // Check for the presence of methods specific to ReadableStream + const stream = val as ReadableStream; + + // ReadableStream has methods like getReader, cancel, and tee + return ( + typeof stream.getReader === "function" && + typeof stream.cancel === "function" && + typeof stream.tee === "function" + ); +} diff --git a/frameworks-elysia/sdk-typescript/tsconfig.json b/frameworks-elysia/sdk-typescript/tsconfig.json new file mode 100644 index 00000000..f9d286a7 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "incremental": true, + "tsBuildInfoFile": ".tsbuildinfo", + "target": "ES2018", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + + "module": "Node16", + "moduleResolution": "Node16", + + "allowJs": true, + + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": ".", + + + // https://github.com/tsconfig/bases/blob/a1bf7c0fa2e094b068ca3e1448ca2ece4157977e/bases/strictest.json + "strict": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": true, + "useUnknownInCatchVariables": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "isolatedModules": true, + "checkJs": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/frameworks-elysia/src/app.ts b/frameworks-elysia/src/app.ts new file mode 100644 index 00000000..cdb806dd --- /dev/null +++ b/frameworks-elysia/src/app.ts @@ -0,0 +1,115 @@ +import { Elysia } from "elysia"; +import { stationsController } from "./controllers/stations"; +import { tripsController } from "./controllers/trips"; +import { bookingsController } from "./controllers/bookings"; +import { openapi } from "@elysia/openapi"; +import packageJson from "../package.json"; +import { cors } from "@elysiajs/cors"; + +export const createApp = () => + new Elysia() + .onError(({ error, code }) => { + if (code === "NOT_FOUND") { + return { + type: "https://example.com/errors/not-found", + title: "Not Found", + status: 404, + detail: "The requested resource was not found.", + }; + } + + console.error(error); + }) + .use( + cors({ + origin: "http://localhost:5173", + }) + ) + .use(stationsController) + .use(tripsController) + .use(bookingsController) + .use( + openapi({ + documentation: { + info: { + title: "Train Travel API", + description: + "API for finding and booking train trips across Europe.", + version: packageJson.version, + contact: { + name: "Train Support", + url: "https://example.com/support", + email: "support@example.com", + }, + }, + servers: [ + { + url: "https://api.example.com", + description: "Production", + }, + { + url: "http://localhost:3000", + description: "Development server", + }, + ], + security: [ + { + OAuth2: ["read"], + }, + ], + components: { + securitySchemes: { + OAuth2: { + type: "oauth2", + description: "OAuth 2.0 authorization code flow.", + flows: { + authorizationCode: { + authorizationUrl: "https://example.com/oauth/authorize", + tokenUrl: "https://example.com/oauth/token", + scopes: { + read: "Read access", + write: "Write access", + }, + }, + }, + }, + }, + }, + "x-speakeasy-retries": { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + maxElapsedTime: 3600000, + exponent: 1.5, + }, + statusCodes: ["5XX"], + retryConnectionErrors: true, + }, + tags: [ + { + name: "Stations", + description: + "Find and filter train stations across Europe, including their location and local timezone.", + }, + { + name: "Trips", + description: + "Timetables and routes for train trips between stations, including pricing and availability.", + }, + { + name: "Bookings", + description: + "Create and manage bookings for train trips, including passenger details and optional extras.", + }, + { + name: "Payments", + description: + "Pay for bookings using a card or bank account, and view payment status and history.", + }, + ], + }, + }) + ); + +export type App = ReturnType; diff --git a/frameworks-elysia/src/controllers/bookings.ts b/frameworks-elysia/src/controllers/bookings.ts new file mode 100644 index 00000000..4898af3f --- /dev/null +++ b/frameworks-elysia/src/controllers/bookings.ts @@ -0,0 +1,338 @@ +import { Elysia, t } from 'elysia'; +import { + createBooking, + createBookingPayment, + deleteBooking, + findBooking, + hasTrip, + listBookings, +} from '../train/data'; +import { + bookingPaymentRequestSchema, + bookingPaymentSchema, + bookingSchema, + createBookingRequestSchema, + linksPaginationSchema, + linksSelfSchema, + problemSchema, +} from '../train/schemas'; + +const bookingWithLinksSchema = t.Intersect([ + bookingSchema, + t.Object({ + links: linksSelfSchema, + }), +]); + +const bookingsCollectionSchema = t.Object({ + data: t.Array(bookingSchema), + links: t.Intersect([linksSelfSchema, linksPaginationSchema]), +}); + +const paymentWithLinkSchema = t.Intersect([ + bookingPaymentSchema, + t.Object({ + links: t.Object({ + booking: t.String({ + format: 'uri', + example: 'https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb', + }), + }), + }), +]); + +export const bookingsController = new Elysia({ prefix: '/bookings' }) + .get( + '/', + ({ query }) => { + const page = Number(query.page ?? 1); + const limit = Number(query.limit ?? 10); + const offset = (page - 1) * limit; + const rows = listBookings(); + const pageData = rows.slice(offset, offset + limit); + + return { + data: pageData, + links: { + self: `https://api.example.com/bookings?page=${page}&limit=${limit}`, + next: + offset + limit < rows.length + ? `https://api.example.com/bookings?page=${page + 1}&limit=${limit}` + : undefined, + prev: + page > 1 + ? `https://api.example.com/bookings?page=${page - 1}&limit=${limit}` + : undefined, + }, + }; + }, + { + query: t.Object({ + page: t.Optional(t.Number({ minimum: 1, default: 1 })), + limit: t.Optional(t.Number({ minimum: 1, maximum: 100, default: 10 })), + }), + detail: { + operationId: 'get-bookings', + summary: 'List existing bookings', + description: 'Returns a list of all trip bookings by the authenticated user.', + tags: ['Bookings'], + responses: { + 200: { + description: 'A list of bookings', + content: { + 'application/json': { + schema: bookingsCollectionSchema, + }, + }, + }, + 401: { + description: 'Unauthorized', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + 500: { + description: 'Internal Server Error', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, + ) + .post( + '/', + ({ body, set, error }) => { + if (!hasTrip(body.trip_id)) { + return error(404, { + type: 'https://example.com/errors/not-found', + title: 'Not Found', + status: 404, + detail: 'Trip not found.', + }); + } + + const booking = createBooking(body); + + set.status = 201; + + return { + ...booking, + links: { + self: `https://api.example.com/bookings/${booking.id}`, + }, + }; + }, + { + type: 'json', + body: createBookingRequestSchema, + detail: { + operationId: 'create-booking', + summary: 'Create a booking', + description: + 'A booking is a temporary hold on a trip. It is not confirmed until payment is processed.', + tags: ['Bookings'], + security: [ + { + OAuth2: ['write'], + }, + ], + 'x-speakeasy-retries': { + strategy: 'backoff', + backoff: { + initialInterval: 300, + maxInterval: 40000, + maxElapsedTime: 3000000, + exponent: 1.2, + }, + statusCodes: ['5XX'], + retryConnectionErrors: true, + }, + responses: { + 201: { + description: 'Booking successful', + content: { + 'application/json': { + schema: bookingWithLinksSchema, + }, + }, + }, + 404: { + description: 'Not Found', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + 409: { + description: 'Conflict', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, + ) + .get( + '/:bookingId', + ({ params, error }) => { + const booking = findBooking(params.bookingId); + + if (!booking) { + return error(404, { + type: 'https://example.com/errors/not-found', + title: 'Not Found', + status: 404, + detail: 'The requested resource was not found.', + }); + } + + return { + ...booking, + links: { + self: `https://api.example.com/bookings/${booking.id}`, + }, + }; + }, + { + params: t.Object({ + bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + }), + detail: { + operationId: 'get-booking', + summary: 'Get a booking', + description: 'Returns the details of a specific booking.', + tags: ['Bookings'], + responses: { + 200: { + description: 'The booking details', + content: { + 'application/json': { + schema: bookingWithLinksSchema, + }, + }, + }, + 404: { + description: 'Not Found', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, + ) + .delete( + '/:bookingId', + ({ params, set, error }) => { + const removed = deleteBooking(params.bookingId); + + if (!removed) { + return error(404, { + type: 'https://example.com/errors/not-found', + title: 'Not Found', + status: 404, + detail: 'The requested resource was not found.', + }); + } + + set.status = 204; + return ''; + }, + { + params: t.Object({ + bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + }), + detail: { + operationId: 'delete-booking', + summary: 'Delete a booking', + description: 'Deletes a booking, cancelling the hold on the trip.', + tags: ['Bookings'], + security: [ + { + OAuth2: ['write'], + }, + ], + responses: { + 204: { + description: 'Booking deleted', + }, + 404: { + description: 'Not Found', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, + ) + .post( + '/:bookingId/payment', + ({ params, body, error }) => { + const booking = findBooking(params.bookingId); + + if (!booking) { + return error(404, { + type: 'https://example.com/errors/not-found', + title: 'Not Found', + status: 404, + detail: 'The requested resource was not found.', + }); + } + + const payment = createBookingPayment(params.bookingId, body); + + return { + ...payment, + links: { + booking: `https://api.example.com/bookings/${booking.id}`, + }, + }; + }, + { + type: 'json', + params: t.Object({ + bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + }), + body: bookingPaymentRequestSchema, + detail: { + operationId: 'create-booking-payment', + summary: 'Pay for a booking', + description: + 'A payment attempt confirms the booking and enables ticket retrieval.', + tags: ['Payments'], + responses: { + 200: { + description: 'Payment successful', + content: { + 'application/json': { + schema: paymentWithLinkSchema, + }, + }, + }, + 404: { + description: 'Not Found', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, + ); diff --git a/frameworks-elysia/src/controllers/stations.ts b/frameworks-elysia/src/controllers/stations.ts new file mode 100644 index 00000000..909545ad --- /dev/null +++ b/frameworks-elysia/src/controllers/stations.ts @@ -0,0 +1,73 @@ +import { Elysia, t } from 'elysia'; +import { listStations } from '../train/data'; +import { + linksPaginationSchema, + linksSelfSchema, + problemSchema, + stationSchema, +} from '../train/schemas'; + +const stationsCollectionSchema = t.Object({ + data: t.Array(stationSchema), + links: t.Intersect([linksSelfSchema, linksPaginationSchema]), +}); + +export const stationsController = new Elysia({ prefix: '/stations' }).get( + '/', + ({ query }) => { + const page = Number(query.page ?? 1); + const limit = Number(query.limit ?? 10); + const offset = (page - 1) * limit; + const rows = listStations({ search: query.search, country: query.country }); + const pageData = rows.slice(offset, offset + limit); + + return { + data: pageData, + links: { + self: `https://api.example.com/stations?page=${page}&limit=${limit}`, + next: + offset + limit < rows.length + ? `https://api.example.com/stations?page=${page + 1}&limit=${limit}` + : undefined, + prev: + page > 1 + ? `https://api.example.com/stations?page=${page - 1}&limit=${limit}` + : undefined, + }, + }; + }, + { + query: t.Object({ + page: t.Optional(t.Number({ minimum: 1, default: 1 })), + limit: t.Optional(t.Number({ minimum: 1, maximum: 100, default: 10 })), + coordinates: t.Optional(t.String({ example: '52.5200,13.4050' })), + search: t.Optional(t.String({ example: 'Milano Centrale' })), + country: t.Optional(t.String({ minLength: 2, maxLength: 2, example: 'DE' })), + }), + detail: { + operationId: 'get-stations', + summary: 'Get a list of train stations', + description: + 'Returns a paginated and searchable list of all train stations.', + tags: ['Stations'], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: stationsCollectionSchema, + }, + }, + }, + 400: { + description: 'Bad Request', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, +); diff --git a/frameworks-elysia/src/controllers/trips.ts b/frameworks-elysia/src/controllers/trips.ts new file mode 100644 index 00000000..c3905f78 --- /dev/null +++ b/frameworks-elysia/src/controllers/trips.ts @@ -0,0 +1,89 @@ +import { Elysia, t } from 'elysia'; +import { listTrips } from '../train/data'; +import { + linksPaginationSchema, + linksSelfSchema, + problemSchema, + tripSchema, +} from '../train/schemas'; + +const tripsCollectionSchema = t.Object({ + data: t.Array(tripSchema), + links: t.Intersect([linksSelfSchema, linksPaginationSchema]), +}); + +export const tripsController = new Elysia({ prefix: '/trips' }).get( + '/', + ({ query, error }) => { + if (!query.origin || !query.destination || !query.date) { + return error(400, { + type: 'https://example.com/errors/bad-request', + title: 'Bad Request', + status: 400, + detail: 'origin, destination, and date are required.', + }); + } + + const page = Number(query.page ?? 1); + const limit = Number(query.limit ?? 10); + const offset = (page - 1) * limit; + const rows = listTrips({ + origin: query.origin, + destination: query.destination, + bicycles: query.bicycles, + dogs: query.dogs, + }); + const pageData = rows.slice(offset, offset + limit); + + return { + data: pageData, + links: { + self: `https://api.example.com/trips?origin=${query.origin}&destination=${query.destination}&date=${query.date}`, + next: + offset + limit < rows.length + ? `https://api.example.com/trips?origin=${query.origin}&destination=${query.destination}&date=${query.date}&page=${page + 1}&limit=${limit}` + : undefined, + prev: + page > 1 + ? `https://api.example.com/trips?origin=${query.origin}&destination=${query.destination}&date=${query.date}&page=${page - 1}&limit=${limit}` + : undefined, + }, + }; + }, + { + query: t.Object({ + page: t.Optional(t.Number({ minimum: 1, default: 1 })), + limit: t.Optional(t.Number({ minimum: 1, maximum: 100, default: 10 })), + origin: t.String({ format: 'uuid', example: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e' }), + destination: t.String({ format: 'uuid', example: 'b2e783e1-c824-4d63-b37a-d8d698862f1d' }), + date: t.String({ format: 'date-time', example: '2024-02-01T09:00:00Z' }), + bicycles: t.Optional(t.Boolean({ default: false })), + dogs: t.Optional(t.Boolean({ default: false })), + }), + detail: { + operationId: 'get-trips', + summary: 'Get available train trips', + description: + 'Returns a list of available train trips between the specified origin and destination stations on the given date.', + tags: ['Trips'], + responses: { + 200: { + description: 'A list of available train trips', + content: { + 'application/json': { + schema: tripsCollectionSchema, + }, + }, + }, + 400: { + description: 'Bad Request', + content: { + 'application/problem+json': { + schema: problemSchema, + }, + }, + }, + }, + }, + }, +); diff --git a/frameworks-elysia/src/generateOpenAPIDocument.ts b/frameworks-elysia/src/generateOpenAPIDocument.ts new file mode 100644 index 00000000..12713890 --- /dev/null +++ b/frameworks-elysia/src/generateOpenAPIDocument.ts @@ -0,0 +1,31 @@ +import * as yaml from "js-yaml"; +import { createApp } from "./app"; + +async function generateOpenAPI() { + try { + const app = createApp(); + const response = await app.handle( + new Request("http://localhost/openapi/json") + ); + + if (!response.ok) { + throw new Error( + `Failed to generate OpenAPI JSON: ${response.status} ${response.statusText}` + ); + } + + const openAPIObject = await response.json(); + + // Convert to YAML + const yamlString = yaml.dump(openAPIObject); + + // Save the YAML string to a file + await Bun.write("openapi.yaml", yamlString); + + console.log("OpenAPI spec saved to openapi.yaml"); + } catch (error) { + console.error("Error generating OpenAPI spec:", error); + } +} + +generateOpenAPI(); diff --git a/frameworks-elysia/src/index.ts b/frameworks-elysia/src/index.ts new file mode 100644 index 00000000..89d02217 --- /dev/null +++ b/frameworks-elysia/src/index.ts @@ -0,0 +1,3 @@ +import { createApp } from './app' + +createApp().listen(3000) \ No newline at end of file diff --git a/frameworks-elysia/src/train/data.ts b/frameworks-elysia/src/train/data.ts new file mode 100644 index 00000000..33110768 --- /dev/null +++ b/frameworks-elysia/src/train/data.ts @@ -0,0 +1,159 @@ +import type { + Booking, + BookingPayment, + BookingPaymentRequest, + CreateBookingRequest, + Station, + Trip, +} from './schemas'; + +const stations: Station[] = [ + { + id: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e', + name: 'Berlin Hauptbahnhof', + address: 'Invalidenstrasse 10557 Berlin, Germany', + country_code: 'DE', + timezone: 'Europe/Berlin', + }, + { + id: 'b2e783e1-c824-4d63-b37a-d8d698862f1d', + name: 'Paris Gare du Nord', + address: '18 Rue de Dunkerque 75010 Paris, France', + country_code: 'FR', + timezone: 'Europe/Paris', + }, +]; + +const trips: Trip[] = [ + { + id: 'ea399ba1-6d95-433f-92d1-83f67b775594', + origin: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e', + destination: 'b2e783e1-c824-4d63-b37a-d8d698862f1d', + departure_time: '2024-02-01T10:00:00Z', + arrival_time: '2024-02-01T16:00:00Z', + price: 50, + operator: 'Deutsche Bahn', + bicycles_allowed: true, + dogs_allowed: true, + }, + { + id: '4d67459c-af07-40bb-bb12-178dbb88e09f', + origin: 'b2e783e1-c824-4d63-b37a-d8d698862f1d', + destination: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e', + departure_time: '2024-02-01T12:00:00Z', + arrival_time: '2024-02-01T18:00:00Z', + price: 50, + operator: 'SNCF', + bicycles_allowed: true, + dogs_allowed: true, + }, +]; + +const bookings: Booking[] = [ + { + id: '1725ff48-ab45-4bb5-9d02-88745177dedb', + trip_id: 'ea399ba1-6d95-433f-92d1-83f67b775594', + passenger_name: 'John Doe', + has_bicycle: true, + has_dog: false, + }, +]; + +const payments: BookingPayment[] = []; + +export function listStations(filters: { search?: string; country?: string }): Station[] { + const search = filters.search?.trim().toLowerCase(); + const country = filters.country?.trim().toUpperCase(); + + return stations.filter((station) => { + if (country && station.country_code !== country) { + return false; + } + + if (!search) { + return true; + } + + return ( + station.name.toLowerCase().includes(search) || + station.address.toLowerCase().includes(search) + ); + }); +} + +export function listTrips(filters: { + origin: string; + destination: string; + bicycles?: boolean; + dogs?: boolean; +}): Trip[] { + return trips.filter((trip) => { + if (trip.origin !== filters.origin || trip.destination !== filters.destination) { + return false; + } + + if (filters.bicycles && !trip.bicycles_allowed) { + return false; + } + + if (filters.dogs && !trip.dogs_allowed) { + return false; + } + + return true; + }); +} + +export function listBookings(): Booking[] { + return bookings; +} + +export function findBooking(bookingId: string): Booking | undefined { + return bookings.find((booking) => booking.id === bookingId); +} + +export function createBooking(input: CreateBookingRequest): Booking { + const booking: Booking = { + id: crypto.randomUUID(), + trip_id: input.trip_id, + passenger_name: input.passenger_name, + has_bicycle: input.has_bicycle ?? false, + has_dog: input.has_dog ?? false, + }; + + bookings.push(booking); + + return booking; +} + +export function deleteBooking(bookingId: string): boolean { + const index = bookings.findIndex((booking) => booking.id === bookingId); + + if (index === -1) { + return false; + } + + bookings.splice(index, 1); + return true; +} + +export function createBookingPayment( + bookingId: string, + input: BookingPaymentRequest, +): BookingPayment { + const payment: BookingPayment = { + id: crypto.randomUUID(), + amount: input.amount, + currency: input.currency, + source: input.source, + status: 'succeeded', + }; + + payments.push(payment); + + return payment; +} + +export function hasTrip(tripId: string): boolean { + return trips.some((trip) => trip.id === tripId); +} diff --git a/frameworks-elysia/src/train/schemas.ts b/frameworks-elysia/src/train/schemas.ts new file mode 100644 index 00000000..89e464f4 --- /dev/null +++ b/frameworks-elysia/src/train/schemas.ts @@ -0,0 +1,128 @@ +import { t } from 'elysia'; + +export const stationSchema = t.Object( + { + id: t.String({ format: 'uuid', example: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e' }), + name: t.String({ example: 'Berlin Hauptbahnhof' }), + address: t.String({ example: 'Invalidenstrasse 10557 Berlin, Germany' }), + country_code: t.String({ example: 'DE' }), + timezone: t.String({ example: 'Europe/Berlin' }), + }, + { + description: 'A train station.', + }, +); + +export const tripSchema = t.Object( + { + id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), + origin: t.String({ format: 'uuid', example: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e' }), + destination: t.String({ format: 'uuid', example: 'b2e783e1-c824-4d63-b37a-d8d698862f1d' }), + departure_time: t.String({ format: 'date-time', example: '2024-02-01T10:00:00Z' }), + arrival_time: t.String({ format: 'date-time', example: '2024-02-01T16:00:00Z' }), + operator: t.String({ example: 'Deutsche Bahn' }), + price: t.Number({ example: 50 }), + bicycles_allowed: t.Boolean({ example: true }), + dogs_allowed: t.Boolean({ example: true }), + }, + { + description: 'A train trip.', + }, +); + +export const bookingSchema = t.Object( + { + id: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + trip_id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), + passenger_name: t.String({ example: 'John Doe' }), + has_bicycle: t.Boolean({ example: true }), + has_dog: t.Boolean({ example: false }), + }, + { + description: 'A booking for a train trip.', + }, +); + +export const createBookingRequestSchema = t.Object( + { + trip_id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), + passenger_name: t.String({ example: 'John Doe' }), + has_bicycle: t.Optional(t.Boolean({ example: true })), + has_dog: t.Optional(t.Boolean({ example: false })), + }, + { + description: 'Booking details.', + example: { + trip_id: 'ea399ba1-6d95-433f-92d1-83f67b775594', + passenger_name: 'John Doe', + has_bicycle: true, + has_dog: false, + }, + }, +); + +export const cardPaymentSourceSchema = t.Object({ + object: t.Literal('card'), + name: t.String({ example: 'J. Doe' }), + number: t.String({ example: '4242424242424242' }), + cvc: t.String({ minLength: 3, maxLength: 4, example: '123' }), + exp_month: t.Number({ example: 12 }), + exp_year: t.Number({ example: 2025 }), + address_country: t.String({ example: 'gb' }), + address_post_code: t.Optional(t.String({ example: 'N12 9XX' })), +}); + +export const bankPaymentSourceSchema = t.Object({ + object: t.Literal('bank_account'), + name: t.String({ example: 'J. Doe' }), + number: t.String({ example: '00012345' }), + sort_code: t.Optional(t.String({ example: '000123' })), + account_type: t.Union([t.Literal('individual'), t.Literal('company')]), + bank_name: t.String({ example: 'Starling Bank' }), + country: t.String({ example: 'gb' }), +}); + +export const bookingPaymentRequestSchema = t.Object({ + amount: t.Number({ exclusiveMinimum: 0, example: 49.99 }), + currency: t.Union([ + t.Literal('bam'), + t.Literal('bgn'), + t.Literal('chf'), + t.Literal('eur'), + t.Literal('gbp'), + t.Literal('nok'), + t.Literal('sek'), + ]), + source: t.Union([cardPaymentSourceSchema, bankPaymentSourceSchema]), +}); + +export const bookingPaymentSchema = t.Object({ + id: t.String({ format: 'uuid', example: '2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a' }), + amount: t.Number({ example: 49.99 }), + currency: t.String({ example: 'gbp' }), + source: t.Union([cardPaymentSourceSchema, bankPaymentSourceSchema]), + status: t.Union([t.Literal('pending'), t.Literal('succeeded'), t.Literal('failed')]), +}); + +export const linksSelfSchema = t.Object({ + self: t.String({ format: 'uri', example: 'https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb' }), +}); + +export const linksPaginationSchema = t.Object({ + next: t.Optional(t.String({ format: 'uri', example: 'https://api.example.com/bookings?page=2' })), + prev: t.Optional(t.String({ format: 'uri', example: 'https://api.example.com/bookings?page=1' })), +}); + +export const problemSchema = t.Object({ + type: t.String({ example: 'https://example.com/errors/not-found' }), + title: t.String({ example: 'Not Found' }), + status: t.Number({ example: 404 }), + detail: t.String({ example: 'The requested resource was not found.' }), +}); + +export type Station = typeof stationSchema.static; +export type Trip = typeof tripSchema.static; +export type Booking = typeof bookingSchema.static; +export type CreateBookingRequest = typeof createBookingRequestSchema.static; +export type BookingPayment = typeof bookingPaymentSchema.static; +export type BookingPaymentRequest = typeof bookingPaymentRequestSchema.static; diff --git a/frameworks-elysia/tsconfig.json b/frameworks-elysia/tsconfig.json new file mode 100644 index 00000000..23be3eec --- /dev/null +++ b/frameworks-elysia/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ES2022", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From e5e6b37e2c92ceb72c533f7865e941adfc549790 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:28:26 +0100 Subject: [PATCH 2/6] added null propery example --- frameworks-elysia/bun.lockb | Bin 6280 -> 12043 bytes frameworks-elysia/openapi.yaml | 626 ++++++++++++++++++++----- frameworks-elysia/package.json | 3 +- frameworks-elysia/src/train/schemas.ts | 163 ++++--- 4 files changed, 608 insertions(+), 184 deletions(-) diff --git a/frameworks-elysia/bun.lockb b/frameworks-elysia/bun.lockb index 319767d16319d73c3c90a01169ceb47409cb5164..d1bf3d0f31126d18e6a6a5ed5609c9e90503af19 100755 GIT binary patch delta 4671 zcmcgvd0bOh7Jly~kg!T15dsRK3MiU{L=Y5ZaX|(}tsn?0B|y+9NgxS|%NVNQQYs3! zEf$K!r5$juNF55c?&E@}qv*Kcf>uz$s^dawt8?z-J(@1_=giIT<-B{&x#xc8+;iW( zXRV?rWut89`QQqtiula~YZ~{|?5LjTz`xV6p`|_XeLvSz6*bRWT$afQx_Oo)dQtto zO7e!78-O7oi2M$cARK^R0cr#EHr30&4Ac(#8ns#-927_taR|Z*`guTIfErB(lYZd{ z;wb1jLq9{EmOBq@YK^^9?PKhf0TqM12&g^KbiIC|Momm6nn2GH7%Y(8OkbU~#Hdjb z1fxi727W)#!^SbdE?zG%CBN6;eO}3PU$a*wbtlmIKzqO2755aysf+D-)mu{nPyRi{ z`f||0XB@TTyZ6gpezrHiU}o-{8D0~*`8U@wt5(YE^WWB zi0c|^wZHhp6swtshqFMY4=CD|kWi@}Uv;nh*4S%>jG`5aCiBP+bcCEld6LMMiV`P4 zWP-pkAavt0bO7?EVkbPoWos2O@=)9OZMJ1fyYb z!hmDVm>`jWD=($^f(j6fw3vfJ&!}L*Mc|GFE~8Cw&_yy>;0ORFT5u`WNE`@)L14@1 zb70b6ERs3=OxL;jpF6v5?7RFG;oXSG0asxD(vZ#B?C&__9>1dpuYp;B%X)y+fKfrRnV zJ62JYnU5A&jWdHPfgcPFGL~+bLMr3^M>k7~10`bkn8FefZcP8rD7Fjxi@*W#VCX=g zxB)e@FMSjb@T7ZxPO;nz9tb!wn9;)&^L^mK6ZtXyAwY4%6w7h@t;4TmRJuarzA8k-zWZI=UM-H`Rh{`jFV;^nX{pErRKqR*89Rn=$w|czWYRd zC1{cR=5>BWUpPjRPapPZHD5LiddPY3sO|PAX#kBR-t>C|l#6U^645Na19IR`j%9Z+ z_J(`Ramwn02b`vD+vL$acT^eqm3@6lX#EQJ+m8e`WbB5fupWn7-?c6d-kCUltZVF| zCrcdTl6Vg~T$2;Ld7fsE0`v>t&AjJ%skNlOxoYLwk$>ID*>$drbLax^7-c(H`#LSU z`)1o`$)_J=3nyQ?;u5#6Id9SO^vs5`I7w{lm}u8Soa2M=Il)3@^Oy#gE4sNxzVgCa z+h^%VAA1}f5FedX=&|E(6C~TN`)@d$6XbB7x-_hcC+>17`p;s@y4T9?eMucNZ63|HK*xTbXmq2yPy7^?D_<(V(3u}MN!NT* z*4Py^X2r9%TdVxMs_Ls#r)Ezob)GBsXc!WC|DVFT^{wsgUPCJ8tzKTHlFg=KZ=$)j zZf5(DB}+YquS!_IYem>~@x9BQKU78*te;x^&YY4(;|E^+VxafrGb#JuOKED9&Q9dW zjzzr^ee!*U@=R9LfL9-%IPj?jI{2RSHEyZQTg|)spzcM4^6bVt+j_iK#$WR<|NN-p zt^9eEW@AgtBgMw8tCZrecb!!iic(k45pCXY@A*RT^ye|{Rw>>~s*r=7oB4XG{HHS+ z9$VICdgpHZSI~$2yEpc8j*mZc&PWq#(+iAxWjcUwRC!{FM?%C=5{Ps+NQ>dDi} zS3P@pZr{q5T_G0e;49bHxD&Dhl9xMuJMp~*&p$q>Ep%%PJ5f;C#LcdVdD0OQ7w_=o z)2S-;xkhv1634c)scDTnr_OlzO*j9={H?{aBR;%xv)aNioZx+p+mU3fKX5ifd-~em zbMX?Nyy*1iJ@ZeJ&*%G$Jze-ic7uFN!W!Sbo$aDik6&I5-)Zdf${`+4svPuP-Li?T z8F3$3*o7-e!mozU3-56LQkpvM`s1p$@_W-Ae=gd&BLDEHxcd0nm3EOo&PLf^eEB^u z%3pRc*WJg7J;Z^_LD`Lwn3=2>aKhX>~o4&^F{zt*4U^~tS;omC1 zZtl2)x@Jyux!C5axv{ip$HdQLt{k_$;Qz{I*CFeJQeExa$g+9fr?-4_baPf+&eeiW zw@%B=4mYU2#$75Wwl?2eIK?xn#ORwtyo@~kw(dfCwU2gy($Adgvi|U2llO++ow4TC zqF{9MJ(smX;c%Wr@p_YDQ+~2(IZJ6Z_&n8ApNRZ5F zbTa-%`oe=xCHzUk2Mpf)aBaoMHNG{{rx8A_@DYm_69--h4?Z&Saf&153J*Ry10?VV z?J_p+YsNETwf^v6H9QQT#t;ws5X7diNo*R@kYK>R#jx<qc74G$lT7#fDi zLd7sKbPN@b$73)YpmG`?Hja&9Ar|0+4Pza^P`)?3KvVi4TY)duB<3N7Ks=4THn$FR zZ(BUL@;SxN2AK?2fW2t5H&lvDQOE*ia9e8t4VW;Wy~BbeKsF*!7CZIrUxlya8WEn9?s$*wh&-%(6k)eB|Nf8JO?8nbbUn&d)s#+Z!?nLyWm8=1PLy1*g}Q9;WIeE z1Gbc5YXFcaz;ClGh+wNAwtN85NEtvR2)0gQ3k*C+7KGhmDhr^pHOEXWW&$LBr zU513GXGnDV4E1|jeMWAU+9;3c^-HeLR_j#R8i}v3BrR7b(ddjORaO?;H2^CuSCf^2 z_PNY-GHP_`St^Y|Zd#J9PSfWhuJE7`wpEDCG;gUoPnB+xYBdIf-hft!#51&NtzKi$ z7)=pa-6#k1^h>%ylWl@+0Di+SQQ5Iyw8SIi7hBFoCql0)jEiUL9WqdW~oeSn$c@DSEDn9s0;?x5~(`RWKbEg z<)MGzg6Ti-q_73hbfI^Yg*ni(=t=4ALt{wO8`O(6Cb%i z%o|Jsxq~i>Bp$RD?FRkUHx)z$!x$X#$2qW0--OZtnG&5BdAl*601z^7Qv3w~XJ8iZ zUuR*0g|YO84GaX*SiF4b-3StzO6iS=-8ANAXX_0nBY2nvYY!grwMJ0W8l@;qG+5l1 z2$;tv1vZNvKxv|6Z_C^PCCe_xFAD~cUZ_#z%z^JQ28>4ZAB&!eJh=d36wS!)?}=I< SJ!*vRG;I`#Ym58$kpBToa|tT| delta 1190 zcmcgrT}V@L6u1WoFn5F#NrI{~-gMF_WQwPH>^696}e9hrSL!Db@%z{G3nAgG|8)Lop7C#dN zgCHDiLX;4Fq0p{?Ul5j|oQ`roI;0^6RosebMA?q0LmU=az( zjr@rK-?^J7Gnmr4c|U{aqFZ+t%W22(44Al_OB@`!I{3`BY%LrS8~F(idNdy6a9Ueu zH(_l=$!bj*h;#?5T5Ad70+gYHTPX-%C&F!=o5w}qdN-dIVGV+u1jG7<1IZK!84D2R zAQKU4knzF_{R@&mHd={;#Rwdk3Z-*wv_ga=6RCN3{GY^$kyM$%l`IeBrWs%$&BHVh z%kaV@lr-5MHV33MFZ3D>a52-vbg(+h3wDzMHlr>DMzX!|5+y^9hZ$gFju)co2Dp>s zV@DGO=4A{_qCHV>zOVd1y*aKosWXyIV71iD!~6dD`J3qO)SqV6B5DG?)dpuRSq|Jg zMMdq`BIEuEdSq%9S>IA!gmiLg!L?M>WJcyVb)}iqc?v;pG{q!j%1wG=%1#rdX%SYa z<4MYdH&$EK?B?(L*f}1}_)w_jyE`KO?ua1FzKz%O@}_#^_!q8qp}P||EeN#*66=RO z1&%-FaK505V{aSn&D)Tm0ExVqeXTw+gf43c2jaWE0;JU zoqhG)fuL`9N1&@bvN!DC9_odf63HA2`-2_fKpCBND<5B1ARK{1#dE=EUkSA(8)2qY Yg0Bnb!uY}l(3jT1(bD;e^s?{l7ZXwH%m4rY diff --git a/frameworks-elysia/openapi.yaml b/frameworks-elysia/openapi.yaml index 28663fa0..4a92e369 100644 --- a/frameworks-elysia/openapi.yaml +++ b/frameworks-elysia/openapi.yaml @@ -1,4 +1,3 @@ -openapi: 3.0.3 info: title: Train Travel API description: API for finding and booking train trips across Europe. @@ -55,6 +54,7 @@ tags: description: >- Pay for bookings using a card or bank account, and view payment status and history. +openapi: 3.1.2 paths: /stations/: get: @@ -70,12 +70,21 @@ paths: application/json: schema: type: object + required: + - data + - links properties: data: type: array items: description: A train station. type: object + required: + - id + - name + - address + - country_code + - timezone properties: id: format: uuid @@ -93,24 +102,18 @@ paths: timezone: example: Europe/Berlin type: string - required: - - id - - name - - address - - country_code - - timezone links: type: object allOf: - type: object + required: + - self properties: self: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - self - type: object properties: next: @@ -121,15 +124,17 @@ paths: format: uri example: https://api.example.com/bookings?page=1 type: string - required: - - data - - links '400': description: Bad Request content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -143,11 +148,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: page in: query @@ -200,12 +200,25 @@ paths: application/json: schema: type: object + required: + - data + - links properties: data: type: array items: description: A train trip. type: object + required: + - id + - origin + - destination + - departure_time + - arrival_time + - operator + - price + - bicycles_allowed + - dogs_allowed properties: id: format: uuid @@ -239,28 +252,18 @@ paths: dogs_allowed: example: true type: boolean - required: - - id - - origin - - destination - - departure_time - - arrival_time - - operator - - price - - bicycles_allowed - - dogs_allowed links: type: object allOf: - type: object + required: + - self properties: self: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - self - type: object properties: next: @@ -271,15 +274,17 @@ paths: format: uri example: https://api.example.com/bookings?page=1 type: string - required: - - data - - links '400': description: Bad Request content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -293,11 +298,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: page in: query @@ -361,12 +361,21 @@ paths: application/json: schema: type: object + required: + - data + - links properties: data: type: array items: description: A booking for a train trip. type: object + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog properties: id: format: uuid @@ -385,24 +394,18 @@ paths: has_dog: example: false type: boolean - required: - - id - - trip_id - - passenger_name - - has_bicycle - - has_dog links: type: object allOf: - type: object + required: + - self properties: self: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - self - type: object properties: next: @@ -413,15 +416,17 @@ paths: format: uri example: https://api.example.com/bookings?page=1 type: string - required: - - data - - links '401': description: Unauthorized content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -435,17 +440,17 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail '500': description: Internal Server Error content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -459,11 +464,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: page in: query @@ -511,6 +511,12 @@ paths: allOf: - description: A booking for a train trip. type: object + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog properties: id: format: uuid @@ -529,32 +535,31 @@ paths: has_dog: example: false type: boolean - required: - - id - - trip_id - - passenger_name - - has_bicycle - - has_dog - type: object + required: + - links properties: links: type: object + required: + - self properties: self: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - self - required: - - links '404': description: Not Found content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -568,17 +573,17 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail '409': description: Conflict content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -592,15 +597,88 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail requestBody: description: Booking details. - content: {} required: true + content: + application/json: + schema: + description: Booking details. + example: + trip_id: ea399ba1-6d95-433f-92d1-83f67b775594 + passenger_name: John Doe + has_bicycle: true + has_dog: false + type: object + required: + - trip_id + - passenger_name + properties: + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean + application/x-www-form-urlencoded: + schema: + description: Booking details. + example: + trip_id: ea399ba1-6d95-433f-92d1-83f67b775594 + passenger_name: John Doe + has_bicycle: true + has_dog: false + type: object + required: + - trip_id + - passenger_name + properties: + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean + multipart/form-data: + schema: + description: Booking details. + example: + trip_id: ea399ba1-6d95-433f-92d1-83f67b775594 + passenger_name: John Doe + has_bicycle: true + has_dog: false + type: object + required: + - trip_id + - passenger_name + properties: + trip_id: + format: uuid + example: ea399ba1-6d95-433f-92d1-83f67b775594 + type: string + passenger_name: + example: John Doe + type: string + has_bicycle: + example: true + type: boolean + has_dog: + example: false + type: boolean /bookings/{bookingId}: get: operationId: get-booking @@ -618,6 +696,12 @@ paths: allOf: - description: A booking for a train trip. type: object + required: + - id + - trip_id + - passenger_name + - has_bicycle + - has_dog properties: id: format: uuid @@ -636,32 +720,31 @@ paths: has_dog: example: false type: boolean - required: - - id - - trip_id - - passenger_name - - has_bicycle - - has_dog - type: object + required: + - links properties: links: type: object + required: + - self properties: self: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - self - required: - - links '404': description: Not Found content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -675,11 +758,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: bookingId in: path @@ -706,6 +784,11 @@ paths: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -719,11 +802,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: bookingId in: path @@ -748,6 +826,12 @@ paths: type: object allOf: - type: object + required: + - id + - amount + - currency + - source + - status properties: id: format: uuid @@ -762,6 +846,14 @@ paths: source: anyOf: - type: object + required: + - object + - name + - number + - cvc + - exp_month + - exp_year + - address_country properties: object: const: card @@ -789,15 +881,14 @@ paths: address_post_code: example: N12 9XX type: string + - type: object required: - object - name - number - - cvc - - exp_month - - exp_year - - address_country - - type: object + - account_type + - bank_name + - country properties: object: const: bank_account @@ -823,13 +914,6 @@ paths: country: example: gb type: string - required: - - object - - name - - number - - account_type - - bank_name - - country status: anyOf: - const: pending @@ -838,32 +922,31 @@ paths: type: string - const: failed type: string - required: - - id - - amount - - currency - - source - - status - type: object + required: + - links properties: links: type: object + required: + - booking properties: booking: format: uri example: >- https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb type: string - required: - - booking - required: - - links '404': description: Not Found content: application/problem+json: schema: type: object + required: + - type + - title + - status + - detail properties: type: example: https://example.com/errors/not-found @@ -877,11 +960,6 @@ paths: detail: example: The requested resource was not found. type: string - required: - - type - - title - - status - - detail parameters: - name: bookingId in: path @@ -891,5 +969,299 @@ paths: example: 1725ff48-ab45-4bb5-9d02-88745177dedb type: string requestBody: - content: {} required: true + content: + application/json: + schema: + type: object + required: + - amount + - currency + - source + properties: + amount: + exclusiveMinimum: 0 + example: 49.99 + type: number + currency: + type: string + enum: + - bam + - bgn + - chf + - eur + - gbp + - nok + - sek + promo_code: + anyOf: + - example: SUMMER20 + type: string + - type: 'null' + source: + anyOf: + - type: object + required: + - object + - name + - number + - cvc + - exp_month + - exp_year + - address_country + properties: + object: + const: card + type: string + name: + example: J. Doe + type: string + number: + example: '4242424242424242' + type: string + cvc: + minLength: 3 + maxLength: 4 + example: '123' + type: string + exp_month: + example: 12 + type: number + exp_year: + example: 2025 + type: number + address_country: + example: gb + type: string + address_post_code: + example: N12 9XX + type: string + - type: object + required: + - object + - name + - number + - account_type + - bank_name + - country + properties: + object: + const: bank_account + type: string + name: + example: J. Doe + type: string + number: + example: '00012345' + type: string + sort_code: + example: '000123' + type: string + account_type: + anyOf: + - const: individual + type: string + - const: company + type: string + bank_name: + example: Starling Bank + type: string + country: + example: gb + type: string + application/x-www-form-urlencoded: + schema: + type: object + required: + - amount + - currency + - source + properties: + amount: + exclusiveMinimum: 0 + example: 49.99 + type: number + currency: + type: string + enum: + - bam + - bgn + - chf + - eur + - gbp + - nok + - sek + promo_code: + anyOf: + - example: SUMMER20 + type: string + - type: 'null' + source: + anyOf: + - type: object + required: + - object + - name + - number + - cvc + - exp_month + - exp_year + - address_country + properties: + object: + const: card + type: string + name: + example: J. Doe + type: string + number: + example: '4242424242424242' + type: string + cvc: + minLength: 3 + maxLength: 4 + example: '123' + type: string + exp_month: + example: 12 + type: number + exp_year: + example: 2025 + type: number + address_country: + example: gb + type: string + address_post_code: + example: N12 9XX + type: string + - type: object + required: + - object + - name + - number + - account_type + - bank_name + - country + properties: + object: + const: bank_account + type: string + name: + example: J. Doe + type: string + number: + example: '00012345' + type: string + sort_code: + example: '000123' + type: string + account_type: + anyOf: + - const: individual + type: string + - const: company + type: string + bank_name: + example: Starling Bank + type: string + country: + example: gb + type: string + multipart/form-data: + schema: + type: object + required: + - amount + - currency + - source + properties: + amount: + exclusiveMinimum: 0 + example: 49.99 + type: number + currency: + type: string + enum: + - bam + - bgn + - chf + - eur + - gbp + - nok + - sek + promo_code: + anyOf: + - example: SUMMER20 + type: string + - type: 'null' + source: + anyOf: + - type: object + required: + - object + - name + - number + - cvc + - exp_month + - exp_year + - address_country + properties: + object: + const: card + type: string + name: + example: J. Doe + type: string + number: + example: '4242424242424242' + type: string + cvc: + minLength: 3 + maxLength: 4 + example: '123' + type: string + exp_month: + example: 12 + type: number + exp_year: + example: 2025 + type: number + address_country: + example: gb + type: string + address_post_code: + example: N12 9XX + type: string + - type: object + required: + - object + - name + - number + - account_type + - bank_name + - country + properties: + object: + const: bank_account + type: string + name: + example: J. Doe + type: string + number: + example: '00012345' + type: string + sort_code: + example: '000123' + type: string + account_type: + anyOf: + - const: individual + type: string + - const: company + type: string + bank_name: + example: Starling Bank + type: string + country: + example: gb + type: string diff --git a/frameworks-elysia/package.json b/frameworks-elysia/package.json index 6ebb2244..3c222595 100644 --- a/frameworks-elysia/package.json +++ b/frameworks-elysia/package.json @@ -10,8 +10,9 @@ "dependencies": { "@elysiajs/cors": "^1.4.2", "@elysia/openapi": "github:philsturgeon/elysia-openapi#feat/oas3-1", + "@sinclair/typebox": "^0.34.0", "@types/js-yaml": "^4.0.9", - "elysia": "latest", + "elysia": "^1.4.19", "js-yaml": "^4.2.0" }, "devDependencies": { diff --git a/frameworks-elysia/src/train/schemas.ts b/frameworks-elysia/src/train/schemas.ts index 89e464f4..ecc6c9dd 100644 --- a/frameworks-elysia/src/train/schemas.ts +++ b/frameworks-elysia/src/train/schemas.ts @@ -1,123 +1,174 @@ -import { t } from 'elysia'; +import { t } from "elysia"; export const stationSchema = t.Object( { - id: t.String({ format: 'uuid', example: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e' }), - name: t.String({ example: 'Berlin Hauptbahnhof' }), - address: t.String({ example: 'Invalidenstrasse 10557 Berlin, Germany' }), - country_code: t.String({ example: 'DE' }), - timezone: t.String({ example: 'Europe/Berlin' }), + id: t.String({ + format: "uuid", + example: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + }), + name: t.String({ example: "Berlin Hauptbahnhof" }), + address: t.String({ example: "Invalidenstrasse 10557 Berlin, Germany" }), + country_code: t.String({ example: "DE" }), + timezone: t.String({ example: "Europe/Berlin" }), }, { - description: 'A train station.', - }, + description: "A train station.", + } ); export const tripSchema = t.Object( { - id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), - origin: t.String({ format: 'uuid', example: 'efdbb9d1-02c2-4bc3-afb7-6788d8782b1e' }), - destination: t.String({ format: 'uuid', example: 'b2e783e1-c824-4d63-b37a-d8d698862f1d' }), - departure_time: t.String({ format: 'date-time', example: '2024-02-01T10:00:00Z' }), - arrival_time: t.String({ format: 'date-time', example: '2024-02-01T16:00:00Z' }), - operator: t.String({ example: 'Deutsche Bahn' }), + id: t.String({ + format: "uuid", + example: "ea399ba1-6d95-433f-92d1-83f67b775594", + }), + origin: t.String({ + format: "uuid", + example: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + }), + destination: t.String({ + format: "uuid", + example: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + }), + departure_time: t.String({ + format: "date-time", + example: "2024-02-01T10:00:00Z", + }), + arrival_time: t.String({ + format: "date-time", + example: "2024-02-01T16:00:00Z", + }), + operator: t.String({ example: "Deutsche Bahn" }), price: t.Number({ example: 50 }), bicycles_allowed: t.Boolean({ example: true }), dogs_allowed: t.Boolean({ example: true }), }, { - description: 'A train trip.', - }, + description: "A train trip.", + } ); export const bookingSchema = t.Object( { - id: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), - trip_id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), - passenger_name: t.String({ example: 'John Doe' }), + id: t.String({ + format: "uuid", + example: "1725ff48-ab45-4bb5-9d02-88745177dedb", + }), + trip_id: t.String({ + format: "uuid", + example: "ea399ba1-6d95-433f-92d1-83f67b775594", + }), + passenger_name: t.String({ example: "John Doe" }), has_bicycle: t.Boolean({ example: true }), has_dog: t.Boolean({ example: false }), }, { - description: 'A booking for a train trip.', - }, + description: "A booking for a train trip.", + } ); export const createBookingRequestSchema = t.Object( { - trip_id: t.String({ format: 'uuid', example: 'ea399ba1-6d95-433f-92d1-83f67b775594' }), - passenger_name: t.String({ example: 'John Doe' }), + trip_id: t.String({ + format: "uuid", + example: "ea399ba1-6d95-433f-92d1-83f67b775594", + }), + passenger_name: t.String({ example: "John Doe" }), has_bicycle: t.Optional(t.Boolean({ example: true })), has_dog: t.Optional(t.Boolean({ example: false })), }, { - description: 'Booking details.', + description: "Booking details.", example: { - trip_id: 'ea399ba1-6d95-433f-92d1-83f67b775594', - passenger_name: 'John Doe', + trip_id: "ea399ba1-6d95-433f-92d1-83f67b775594", + passenger_name: "John Doe", has_bicycle: true, has_dog: false, }, - }, + } ); export const cardPaymentSourceSchema = t.Object({ - object: t.Literal('card'), - name: t.String({ example: 'J. Doe' }), - number: t.String({ example: '4242424242424242' }), - cvc: t.String({ minLength: 3, maxLength: 4, example: '123' }), + object: t.Literal("card"), + name: t.String({ example: "J. Doe" }), + number: t.String({ example: "4242424242424242" }), + cvc: t.String({ minLength: 3, maxLength: 4, example: "123" }), exp_month: t.Number({ example: 12 }), exp_year: t.Number({ example: 2025 }), - address_country: t.String({ example: 'gb' }), - address_post_code: t.Optional(t.String({ example: 'N12 9XX' })), + address_country: t.String({ example: "gb" }), + address_post_code: t.Optional(t.String({ example: "N12 9XX" })), }); export const bankPaymentSourceSchema = t.Object({ - object: t.Literal('bank_account'), - name: t.String({ example: 'J. Doe' }), - number: t.String({ example: '00012345' }), - sort_code: t.Optional(t.String({ example: '000123' })), - account_type: t.Union([t.Literal('individual'), t.Literal('company')]), - bank_name: t.String({ example: 'Starling Bank' }), - country: t.String({ example: 'gb' }), + object: t.Literal("bank_account"), + name: t.String({ example: "J. Doe" }), + number: t.String({ example: "00012345" }), + sort_code: t.Optional(t.String({ example: "000123" })), + account_type: t.Union([t.Literal("individual"), t.Literal("company")]), + bank_name: t.String({ example: "Starling Bank" }), + country: t.String({ example: "gb" }), }); export const bookingPaymentRequestSchema = t.Object({ amount: t.Number({ exclusiveMinimum: 0, example: 49.99 }), currency: t.Union([ - t.Literal('bam'), - t.Literal('bgn'), - t.Literal('chf'), - t.Literal('eur'), - t.Literal('gbp'), - t.Literal('nok'), - t.Literal('sek'), + t.Literal("bam"), + t.Literal("bgn"), + t.Literal("chf"), + t.Literal("eur"), + t.Literal("gbp"), + t.Literal("nok"), + t.Literal("sek"), ]), + promo_code: t.Optional( + t.Union([t.String({ example: "SUMMER20" }), t.Null()]) + ), source: t.Union([cardPaymentSourceSchema, bankPaymentSourceSchema]), }); export const bookingPaymentSchema = t.Object({ - id: t.String({ format: 'uuid', example: '2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a' }), + id: t.String({ + format: "uuid", + example: "2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a", + }), amount: t.Number({ example: 49.99 }), - currency: t.String({ example: 'gbp' }), + currency: t.String({ example: "gbp" }), source: t.Union([cardPaymentSourceSchema, bankPaymentSourceSchema]), - status: t.Union([t.Literal('pending'), t.Literal('succeeded'), t.Literal('failed')]), + status: t.Union([ + t.Literal("pending"), + t.Literal("succeeded"), + t.Literal("failed"), + ]), }); export const linksSelfSchema = t.Object({ - self: t.String({ format: 'uri', example: 'https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb' }), + self: t.String({ + format: "uri", + example: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + }), }); export const linksPaginationSchema = t.Object({ - next: t.Optional(t.String({ format: 'uri', example: 'https://api.example.com/bookings?page=2' })), - prev: t.Optional(t.String({ format: 'uri', example: 'https://api.example.com/bookings?page=1' })), + next: t.Optional( + t.String({ + format: "uri", + example: "https://api.example.com/bookings?page=2", + }) + ), + prev: t.Optional( + t.String({ + format: "uri", + example: "https://api.example.com/bookings?page=1", + }) + ), }); export const problemSchema = t.Object({ - type: t.String({ example: 'https://example.com/errors/not-found' }), - title: t.String({ example: 'Not Found' }), + type: t.String({ example: "https://example.com/errors/not-found" }), + title: t.String({ example: "Not Found" }), status: t.Number({ example: 404 }), - detail: t.String({ example: 'The requested resource was not found.' }), + detail: t.String({ example: "The requested resource was not found." }), }); export type Station = typeof stationSchema.static; From 364ce46c75c82818dd3d93751c98bfb09a55afc6 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:00:49 +0100 Subject: [PATCH 3/6] elysia: improve openapi export --- frameworks-elysia/README.md | 2 +- frameworks-elysia/bun.lockb | Bin 12043 -> 11988 bytes frameworks-elysia/package.json | 2 +- frameworks-elysia/src/app.ts | 1 + frameworks-elysia/src/controllers/bookings.ts | 175 ++++++++++-------- .../src/generateOpenAPIDocument.ts | 4 +- 6 files changed, 98 insertions(+), 86 deletions(-) diff --git a/frameworks-elysia/README.md b/frameworks-elysia/README.md index 5a17faac..1d130121 100644 --- a/frameworks-elysia/README.md +++ b/frameworks-elysia/README.md @@ -35,7 +35,7 @@ Scalar UI is available at `http://localhost:3000/openapi`. ## Generate OpenAPI YAML -Keep the server running, then run: +Run: ```bash bun run generate:openapi diff --git a/frameworks-elysia/bun.lockb b/frameworks-elysia/bun.lockb index d1bf3d0f31126d18e6a6a5ed5609c9e90503af19..5f12ad91cc4f2a42473e3681274cd692a8fb4260 100755 GIT binary patch delta 979 zcmZ8feN2r}7(dVZy4`NyH&eZC)UBH=_1^AB(tMPu-o#3OMy2GkyQrwN{-9(s+D+FJ z31wp%Cgh50{z;?x7-Jb`QPM1IV%jJh&%O0-=KS&do%8(8bI$Xe^Q+Gr%xx64wikDr z#mzYbZ%$eYzwUXGRd?i4c)g}7D7vBDzApHAPqIBTtJ=mGQ!`f63ygUaUnEu$cXBiF zc4ALjTP+q#e4Lr(@{IY>I-PhfaasB9@{%GGYodMrwBBmjQn8)R+*w9IqjvT@E3rU& zF0mJJVM$4m)j}z4w8@78av{}dfIw|2MSUsiJjz+lE#*uZ)5Om74u=&afL`q6ByNJ? z6qgE%aWyY-gMdf)R0zOlyrjyes+QCC00ce}?qb0l3B2$U;ZFQUcpeiJ5;x3ats)g7 z@PR^t98|kW(2Ch^l4@uUW6_k(;cH4);W#O4(4chcRZ2-cq+rZUI`!llfS`y6HLBbt z$iOVZMr(1+k5ffCmera9~$ zk3Eu%U8(L<33cTuqrXoCeK|Dtvha4zSX$j%&r_d|ecEty&x-ZQ3x8FvE!yTadBNxE ztC*C>-5Z|WIGnw%`R7>EFW)3b>%0R1R~*{FSS2O}-g5+mTn6B=FSI}-zxdFC`R^-r zt=~DwGl*u<5XY) zXUvM;VS+|Bf=AsVI#C@iKsqiV%*B*& z6JZr$J9ZF0#Sx0zaGK^e)ay*(>V!izu`;4)o z!6+`9RvwE8f?Fs=R6sNyjj%g17WKQ~k4Q~ul4VC#nYBP)QfetKD7ETi^f{qg(V^StML->-jLW5G$m_`>1S z`qsB6`R`oycV5noQ@-qTjsRnE#IK1p#Dm_8#Ji#2)WXue;pF9#CE)*~L;}O)2%P@DR|s9_iOY%u~FP zIF`7`?JjpoR1&15cyh>tbfE?G#&+^1kT=vSG|pGm*cevzSou)E1tP!*-rz)T2H+@{ z2ODsiLgY9O8x(o49A7F#%`uv4F_lk2P%MFO=$s%z7WxT&_?_@2E>enI`~*Ct%!76K zR4GCO>Y_w=hMS^9O^lMUc~s8f8!C6;XNpv#MHPzIszhB(6k~RZ(@x<72ucSmL5*63 zeV9*p4_gU;;Rm(InN>JPlQWxcFMOP|Qs^csh(i~!H?rbU;xw|+$)(^oP7Qv%tqJvj zXc2O7C1G8lIXW1g<6pNAK1KJCEGGn78ZZl^!t0o{8a;nu4d@7o<&Z zPoAGt_OK)HD1PWf&pFk+t&dzKm)2I4Z5ar(O+E}T5HRX9Rj5_W#-;kUz?9@p06pGM zaT?@Dc$YNo<8D*i4^CZ0lM6Ik7iJrIgZyO4ZQOf%;>}?W3Ni(oUC3lXtTxsg(1%-6`8Bd4V^x>W71$r& z(!%qIrew_~4EjD .use(bookingsController) .use( openapi({ + openapiVersion: "3.1.2", documentation: { info: { title: "Train Travel API", diff --git a/frameworks-elysia/src/controllers/bookings.ts b/frameworks-elysia/src/controllers/bookings.ts index 4898af3f..1cec4433 100644 --- a/frameworks-elysia/src/controllers/bookings.ts +++ b/frameworks-elysia/src/controllers/bookings.ts @@ -1,4 +1,4 @@ -import { Elysia, t } from 'elysia'; +import { Elysia, t } from "elysia"; import { createBooking, createBookingPayment, @@ -6,7 +6,7 @@ import { findBooking, hasTrip, listBookings, -} from '../train/data'; +} from "../train/data"; import { bookingPaymentRequestSchema, bookingPaymentSchema, @@ -15,7 +15,7 @@ import { linksPaginationSchema, linksSelfSchema, problemSchema, -} from '../train/schemas'; +} from "../train/schemas"; const bookingWithLinksSchema = t.Intersect([ bookingSchema, @@ -34,16 +34,17 @@ const paymentWithLinkSchema = t.Intersect([ t.Object({ links: t.Object({ booking: t.String({ - format: 'uri', - example: 'https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb', + format: "uri", + example: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", }), }), }), ]); -export const bookingsController = new Elysia({ prefix: '/bookings' }) +export const bookingsController = new Elysia({ prefix: "/bookings" }) .get( - '/', + "/", ({ query }) => { const page = Number(query.page ?? 1); const limit = Number(query.limit ?? 10); @@ -72,48 +73,49 @@ export const bookingsController = new Elysia({ prefix: '/bookings' }) limit: t.Optional(t.Number({ minimum: 1, maximum: 100, default: 10 })), }), detail: { - operationId: 'get-bookings', - summary: 'List existing bookings', - description: 'Returns a list of all trip bookings by the authenticated user.', - tags: ['Bookings'], + operationId: "get-bookings", + summary: "List existing bookings", + description: + "Returns a list of all trip bookings by the authenticated user.", + tags: ["Bookings"], responses: { 200: { - description: 'A list of bookings', + description: "A list of bookings", content: { - 'application/json': { + "application/json": { schema: bookingsCollectionSchema, }, }, }, 401: { - description: 'Unauthorized', + description: "Unauthorized", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, 500: { - description: 'Internal Server Error', + description: "Internal Server Error", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, }, }, - }, + } ) .post( - '/', + "/", ({ body, set, error }) => { if (!hasTrip(body.trip_id)) { return error(404, { - type: 'https://example.com/errors/not-found', - title: 'Not Found', + type: "https://example.com/errors/not-found", + title: "Not Found", status: 404, - detail: 'Trip not found.', + detail: "Trip not found.", }); } @@ -129,70 +131,70 @@ export const bookingsController = new Elysia({ prefix: '/bookings' }) }; }, { - type: 'json', + type: "json", body: createBookingRequestSchema, detail: { - operationId: 'create-booking', - summary: 'Create a booking', + operationId: "create-booking", + summary: "Create a booking", description: - 'A booking is a temporary hold on a trip. It is not confirmed until payment is processed.', - tags: ['Bookings'], + "A booking is a temporary hold on a trip. It is not confirmed until payment is processed.", + tags: ["Bookings"], security: [ { - OAuth2: ['write'], + OAuth2: ["write"], }, ], - 'x-speakeasy-retries': { - strategy: 'backoff', + "x-speakeasy-retries": { + strategy: "backoff", backoff: { initialInterval: 300, maxInterval: 40000, maxElapsedTime: 3000000, exponent: 1.2, }, - statusCodes: ['5XX'], + statusCodes: ["5XX"], retryConnectionErrors: true, }, responses: { 201: { - description: 'Booking successful', + description: "Booking successful", content: { - 'application/json': { + "application/json": { schema: bookingWithLinksSchema, }, }, }, 404: { - description: 'Not Found', + description: "Not Found", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, 409: { - description: 'Conflict', + description: "Conflict", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, }, }, - }, + } ) .get( - '/:bookingId', + "/:bookingId", ({ params, error }) => { const booking = findBooking(params.bookingId); if (!booking) { return error(404, { - type: 'https://example.com/errors/not-found', - title: 'Not Found', + type: "https://example.com/errors/not-found", + title: "Not Found", status: 404, - detail: 'The requested resource was not found.', + detail: "The requested resource was not found.", }); } @@ -205,92 +207,98 @@ export const bookingsController = new Elysia({ prefix: '/bookings' }) }, { params: t.Object({ - bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + bookingId: t.String({ + format: "uuid", + example: "1725ff48-ab45-4bb5-9d02-88745177dedb", + }), }), detail: { - operationId: 'get-booking', - summary: 'Get a booking', - description: 'Returns the details of a specific booking.', - tags: ['Bookings'], + operationId: "get-booking", + summary: "Get a booking", + description: "Returns the details of a specific booking.", + tags: ["Bookings"], responses: { 200: { - description: 'The booking details', + description: "The booking details", content: { - 'application/json': { + "application/json": { schema: bookingWithLinksSchema, }, }, }, 404: { - description: 'Not Found', + description: "Not Found", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, }, }, - }, + } ) .delete( - '/:bookingId', + "/:bookingId", ({ params, set, error }) => { const removed = deleteBooking(params.bookingId); if (!removed) { return error(404, { - type: 'https://example.com/errors/not-found', - title: 'Not Found', + type: "https://example.com/errors/not-found", + title: "Not Found", status: 404, - detail: 'The requested resource was not found.', + detail: "The requested resource was not found.", }); } set.status = 204; - return ''; + return ""; }, { params: t.Object({ - bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + bookingId: t.String({ + format: "uuid", + example: "1725ff48-ab45-4bb5-9d02-88745177dedb", + }), }), detail: { - operationId: 'delete-booking', - summary: 'Delete a booking', - description: 'Deletes a booking, cancelling the hold on the trip.', - tags: ['Bookings'], + operationId: "delete-booking", + summary: "Delete a booking", + description: "Deletes a booking, cancelling the hold on the trip.", + tags: ["Bookings"], security: [ { - OAuth2: ['write'], + OAuth2: ["write"], }, ], responses: { 204: { - description: 'Booking deleted', + description: "Booking deleted", }, 404: { - description: 'Not Found', + description: "Not Found", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, }, }, - }, + } ) .post( - '/:bookingId/payment', + "/:bookingId/payment", ({ params, body, error }) => { const booking = findBooking(params.bookingId); if (!booking) { return error(404, { - type: 'https://example.com/errors/not-found', - title: 'Not Found', + type: "https://example.com/errors/not-found", + title: "Not Found", status: 404, - detail: 'The requested resource was not found.', + detail: "The requested resource was not found.", }); } @@ -304,35 +312,38 @@ export const bookingsController = new Elysia({ prefix: '/bookings' }) }; }, { - type: 'json', + type: "json", params: t.Object({ - bookingId: t.String({ format: 'uuid', example: '1725ff48-ab45-4bb5-9d02-88745177dedb' }), + bookingId: t.String({ + format: "uuid", + example: "1725ff48-ab45-4bb5-9d02-88745177dedb", + }), }), body: bookingPaymentRequestSchema, detail: { - operationId: 'create-booking-payment', - summary: 'Pay for a booking', + operationId: "create-booking-payment", + summary: "Pay for a booking", description: - 'A payment attempt confirms the booking and enables ticket retrieval.', - tags: ['Payments'], + "A payment attempt confirms the booking and enables ticket retrieval.", + tags: ["Payments"], responses: { 200: { - description: 'Payment successful', + description: "Payment successful", content: { - 'application/json': { + "application/json": { schema: paymentWithLinkSchema, }, }, }, 404: { - description: 'Not Found', + description: "Not Found", content: { - 'application/problem+json': { + "application/problem+json": { schema: problemSchema, }, }, }, }, }, - }, + } ); diff --git a/frameworks-elysia/src/generateOpenAPIDocument.ts b/frameworks-elysia/src/generateOpenAPIDocument.ts index 12713890..de856a49 100644 --- a/frameworks-elysia/src/generateOpenAPIDocument.ts +++ b/frameworks-elysia/src/generateOpenAPIDocument.ts @@ -5,7 +5,7 @@ async function generateOpenAPI() { try { const app = createApp(); const response = await app.handle( - new Request("http://localhost/openapi/json") + new Request("http://elysia/openapi/json") ); if (!response.ok) { @@ -22,7 +22,7 @@ async function generateOpenAPI() { // Save the YAML string to a file await Bun.write("openapi.yaml", yamlString); - console.log("OpenAPI spec saved to openapi.yaml"); + console.log("OpenAPI document saved to openapi.yaml"); } catch (error) { console.error("Error generating OpenAPI spec:", error); } From 8384a94dd6f29e1c7c071d35c34fa87323990d23 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:03:52 +0100 Subject: [PATCH 4/6] make laravel more 3.1 --- frameworks-laravel/README.md | 12 ++++++++++-- frameworks-laravel/composer.json | 2 +- frameworks-laravel/config/scribe.php | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frameworks-laravel/README.md b/frameworks-laravel/README.md index 629437bc..69444f87 100644 --- a/frameworks-laravel/README.md +++ b/frameworks-laravel/README.md @@ -86,14 +86,22 @@ All endpoints are prefixed with `/api`. ## Generating API Documentation -Generate API documentation using Scribe: +This example uses [Scribe v5](https://scribe.knuckles.wtf/laravel/). Generate API documentation with: ```bash php artisan scribe:generate ``` ## OpenAPI -The API description is exported by [Scribe](https://scribe.knuckles.wtf/laravel/) and can be found in `./storage/app/private/scribe/openapi.yaml`. +The API description is exported by [Scribe](https://scribe.knuckles.wtf/laravel/) as OpenAPI v3.1 and can be found in `./storage/app/scribe/openapi.yaml`. + +OpenAPI version is configured in `config/scribe.php`: +```php +'openapi' => [ + 'enabled' => true, + 'version' => '3.1.0', +], +``` ## License diff --git a/frameworks-laravel/composer.json b/frameworks-laravel/composer.json index 98560483..cf27435e 100644 --- a/frameworks-laravel/composer.json +++ b/frameworks-laravel/composer.json @@ -13,7 +13,7 @@ }, "require-dev": { "fakerphp/faker": "^1.23", - "knuckleswtf/scribe": "^5.5", + "knuckleswtf/scribe": "^5.6", "laravel/pail": "^1.2.2", "laravel/pint": "^1.24", "laravel/sail": "^1.41", diff --git a/frameworks-laravel/config/scribe.php b/frameworks-laravel/config/scribe.php index 04a5b948..51926e33 100644 --- a/frameworks-laravel/config/scribe.php +++ b/frameworks-laravel/config/scribe.php @@ -146,13 +146,16 @@ ], ], - // Generate an OpenAPI spec (v3.0.1) in addition to docs webpage. + // Generate an OpenAPI spec (v3.1.x) in addition to docs webpage. // For 'static' docs, the collection will be generated to public/docs/openapi.yaml. // For 'laravel' docs, it will be generated to storage/app/scribe/openapi.yaml. // Setting `laravel.add_routes` to true (above) will also add a route for the spec. 'openapi' => [ 'enabled' => true, + // Set OpenAPI output version. + 'version' => '3.1.0', + 'overrides' => [ 'info.contact' => [ 'name' => 'API Support', From 7eb8a72be9a71d6089dbe4e7abf3ad747aed601b Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:04:34 +0100 Subject: [PATCH 5/6] until PR is merged no version switch --- frameworks-elysia/src/app.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frameworks-elysia/src/app.ts b/frameworks-elysia/src/app.ts index 29e00cdd..cdb806dd 100644 --- a/frameworks-elysia/src/app.ts +++ b/frameworks-elysia/src/app.ts @@ -30,7 +30,6 @@ export const createApp = () => .use(bookingsController) .use( openapi({ - openapiVersion: "3.1.2", documentation: { info: { title: "Train Travel API", From 38c93db68ddd9ce25e2d7b9968cccdcbede45d4b Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:05:45 +0100 Subject: [PATCH 6/6] rerun sdk g eneration --- .../sdk-typescript/.devcontainer/setup.sh | 4 +- .../sdk-typescript/.eslintrc.cjs | 28 - frameworks-elysia/sdk-typescript/.gitignore | 12 + frameworks-elysia/sdk-typescript/.npmignore | 8 +- .../sdk-typescript/.speakeasy/gen.lock | 725 ++++++++++++++++-- .../sdk-typescript/.speakeasy/gen.yaml | 51 +- frameworks-elysia/sdk-typescript/FUNCTIONS.md | 43 +- frameworks-elysia/sdk-typescript/README.md | 278 +++++-- frameworks-elysia/sdk-typescript/RUNTIMES.md | 34 +- frameworks-elysia/sdk-typescript/USAGE.md | 11 +- .../docs/models/components/id.md | 17 - .../docs/models/components/security.md | 15 + .../docs/models/components/successresponse.md | 17 - .../docs/models/components/user.md | 21 - .../createbookingbookingsresponsebody.md | 20 + .../createbookingpaymentresponsebody.md | 20 + .../errors/createbookingresponsebody.md | 20 + .../errors/deletebookingresponsebody.md | 20 + .../docs/models/errors/errorresponse.md | 16 - .../models/errors/getbookingresponsebody.md | 20 + .../errors/getbookingsbookingsresponsebody.md | 20 + .../models/errors/getbookingsresponsebody.md | 20 + .../models/errors/getstationsresponsebody.md | 20 + .../models/errors/gettripsresponsebody.md | 20 + ...createbookingbookingsrequestrequestbody.md | 25 + .../models/operations/createbookinglinks.md | 17 + .../operations/createbookingpaymentlinks.md | 18 + .../createbookingpaymentpaymentscurrency.md | 15 + ...ookingpaymentpaymentsrequestrequestbody.md | 31 + ...atebookingpaymentpaymentsresponsesource.md | 34 + .../createbookingpaymentpaymentssource.md | 34 + .../operations/createbookingpaymentrequest.md | 32 + .../createbookingpaymentresponsebody.md | 40 + .../operations/createbookingpaymentsource1.md | 31 + .../operations/createbookingpaymentsource2.md | 29 + .../createbookingpaymentsourceaccounttype.md | 15 + .../createbookingpaymentsourcepayments1.md | 31 + .../createbookingpaymentsourcepayments2.md | 29 + ...bookingpaymentsourcepaymentsaccounttype.md | 15 + .../operations/createbookingresponsebody.md | 32 + .../docs/models/operations/data.md | 27 + .../models/operations/deletebookingrequest.md | 17 + .../operations/deleteusersbyidrequest.md | 17 - .../docs/models/operations/getbookinglinks.md | 17 + .../models/operations/getbookingrequest.md | 17 + .../operations/getbookingresponsebody.md | 32 + .../docs/models/operations/getbookingsdata.md | 27 + .../models/operations/getbookingslinks.md | 21 + .../models/operations/getbookingsrequest.md | 16 + .../operations/getbookingsresponsebody.md | 34 + .../models/operations/getstationsrequest.md | 23 + .../operations/getstationsresponsebody.md | 34 + .../docs/models/operations/gettripsdata.md | 35 + .../docs/models/operations/gettripslinks.md | 21 + .../docs/models/operations/gettripsrequest.md | 25 + .../models/operations/gettripsresponsebody.md | 38 + .../models/operations/getusersbyidrequest.md | 17 - .../docs/models/operations/links.md | 21 + .../operations/patchusersbyidrequest.md | 21 - .../operations/patchusersbyidrequestbody.md | 18 - .../models/operations/postusersrequestbody.md | 19 - .../docs/models/operations/status.md | 15 + .../docs/sdks/{users => bookings}/README.md | 297 +++---- .../docs/sdks/payments/README.md | 111 +++ .../sdk-typescript/docs/sdks/sdk/README.md | 10 - .../docs/sdks/stations/README.md | 87 +++ .../sdk-typescript/docs/sdks/trips/README.md | 87 +++ .../sdk-typescript/eslint.config.mjs | 22 + .../sdk-typescript/examples/.env.template | 14 + .../sdk-typescript/examples/README.md | 31 + .../sdk-typescript/examples/package.json | 18 + .../examples/stationsGetStations.example.ts | 30 + frameworks-elysia/sdk-typescript/jsr.json | 2 +- frameworks-elysia/sdk-typescript/package.json | 22 +- .../src/funcs/bookingsCreateBooking.ts | 192 +++++ .../src/funcs/bookingsDeleteBooking.ts | 189 +++++ .../src/funcs/bookingsGetBooking.ts | 188 +++++ .../src/funcs/bookingsGetBookings.ts | 194 +++++ .../src/funcs/paymentsCreateBookingPayment.ts | 190 +++++ .../src/funcs/stationsGetStations.ts | 191 +++++ .../sdk-typescript/src/funcs/tripsGetTrips.ts | 193 +++++ .../src/funcs/usersDeleteUsersById.ts | 142 ---- .../sdk-typescript/src/funcs/usersGetUsers.ts | 120 --- .../src/funcs/usersGetUsersById.ts | 142 ---- .../src/funcs/usersPatchUsersById.ts | 143 ---- .../src/funcs/usersPostUsers.ts | 136 ---- .../sdk-typescript/src/hooks/hooks.ts | 23 +- .../sdk-typescript/src/hooks/oauth2scopes.ts | 19 + .../sdk-typescript/src/hooks/types.ts | 12 +- frameworks-elysia/sdk-typescript/src/index.ts | 2 + .../sdk-typescript/src/lib/base64.ts | 2 +- .../sdk-typescript/src/lib/config.ts | 24 +- .../sdk-typescript/src/lib/encodings.ts | 204 +++-- .../sdk-typescript/src/lib/env.ts | 30 +- .../sdk-typescript/src/lib/files.ts | 66 +- .../sdk-typescript/src/lib/matchers.ts | 110 +-- .../sdk-typescript/src/lib/primitives.ts | 28 + .../sdk-typescript/src/lib/retries.ts | 1 - .../sdk-typescript/src/lib/schemas.ts | 7 +- .../sdk-typescript/src/lib/sdks.ts | 82 +- .../sdk-typescript/src/lib/security.ts | 66 +- .../sdk-typescript/src/lib/url.ts | 32 +- .../src/models/components/id.ts | 55 -- .../src/models/components/index.ts | 4 +- .../src/models/components/security.ts | 32 + .../src/models/components/successresponse.ts | 64 -- .../src/models/components/user.ts | 64 -- .../src/models/errors/apierror.ts | 45 +- .../src/models/errors/createbooking.ts | 130 ++++ .../src/models/errors/createbookingpayment.ts | 68 ++ .../src/models/errors/deletebooking.ts | 68 ++ .../src/models/errors/errorresponse.ts | 73 -- .../src/models/errors/getbooking.ts | 68 ++ .../src/models/errors/getbookings.ts | 130 ++++ .../src/models/errors/getstations.ts | 68 ++ .../src/models/errors/gettrips.ts | 68 ++ .../sdk-typescript/src/models/errors/index.ts | 10 +- .../models/errors/responsevalidationerror.ts | 50 ++ .../src/models/errors/sdkerror.ts | 35 + .../src/models/errors/sdkvalidationerror.ts | 14 +- .../src/models/operations/createbooking.ts | 123 +++ .../models/operations/createbookingpayment.ts | 468 +++++++++++ .../src/models/operations/deletebooking.ts | 31 + .../src/models/operations/deleteusersbyid.ts | 66 -- .../src/models/operations/getbooking.ts | 101 +++ .../src/models/operations/getbookings.ts | 134 ++++ .../src/models/operations/getstations.ts | 134 ++++ .../src/models/operations/gettrips.ts | 159 ++++ .../src/models/operations/getusersbyid.ts | 66 -- .../src/models/operations/index.ts | 11 +- .../src/models/operations/patchusersbyid.ts | 141 ---- .../src/models/operations/postusers.ts | 70 -- .../sdk-typescript/src/sdk/bookings.ts | 81 ++ .../sdk-typescript/src/sdk/payments.ts | 27 + .../sdk-typescript/src/sdk/sdk.ts | 26 +- .../sdk-typescript/src/sdk/stations.ts | 27 + .../sdk-typescript/src/sdk/trips.ts | 27 + .../sdk-typescript/src/sdk/users.ts | 98 --- .../sdk-typescript/src/types/async.ts | 69 ++ .../sdk-typescript/src/types/blobs.ts | 13 +- .../sdk-typescript/src/types/constdatetime.ts | 4 +- .../sdk-typescript/src/types/enums.ts | 47 +- .../sdk-typescript/src/types/index.ts | 4 +- .../sdk-typescript/src/types/unrecognized.ts | 35 + .../sdk-typescript/tsconfig.json | 8 +- 145 files changed, 6658 insertions(+), 2217 deletions(-) delete mode 100644 frameworks-elysia/sdk-typescript/.eslintrc.cjs delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/id.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/security.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/components/user.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/createbookingbookingsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/createbookingpaymentresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/createbookingresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/deletebookingresponsebody.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/getbookingresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsbookingsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/getstationsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/errors/gettripsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingbookingsrequestrequestbody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookinglinks.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentlinks.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentscurrency.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsrequestrequestbody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsresponsesource.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentssource.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource1.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource2.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourceaccounttype.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments1.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments2.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepaymentsaccounttype.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/createbookingresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/data.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/deletebookingrequest.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookinglinks.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsdata.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingslinks.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getstationsrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getstationsresponsebody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/gettripsdata.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/gettripslinks.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/gettripsrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/gettripsresponsebody.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/links.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md create mode 100644 frameworks-elysia/sdk-typescript/docs/models/operations/status.md rename frameworks-elysia/sdk-typescript/docs/sdks/{users => bookings}/README.md (67%) create mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/payments/README.md delete mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md create mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/stations/README.md create mode 100644 frameworks-elysia/sdk-typescript/docs/sdks/trips/README.md create mode 100644 frameworks-elysia/sdk-typescript/eslint.config.mjs create mode 100644 frameworks-elysia/sdk-typescript/examples/.env.template create mode 100644 frameworks-elysia/sdk-typescript/examples/README.md create mode 100644 frameworks-elysia/sdk-typescript/examples/package.json create mode 100644 frameworks-elysia/sdk-typescript/examples/stationsGetStations.example.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/bookingsCreateBooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/bookingsDeleteBooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBookings.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/paymentsCreateBookingPayment.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/stationsGetStations.ts create mode 100644 frameworks-elysia/sdk-typescript/src/funcs/tripsGetTrips.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/hooks/oauth2scopes.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/components/id.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/components/security.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/components/user.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/createbooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/createbookingpayment.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/deletebooking.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/getbooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/getbookings.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/getstations.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/gettrips.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/responsevalidationerror.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/errors/sdkerror.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/createbooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/createbookingpayment.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/deletebooking.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/getbooking.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/getbookings.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/getstations.ts create mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/gettrips.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/bookings.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/payments.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/stations.ts create mode 100644 frameworks-elysia/sdk-typescript/src/sdk/trips.ts delete mode 100644 frameworks-elysia/sdk-typescript/src/sdk/users.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/async.ts create mode 100644 frameworks-elysia/sdk-typescript/src/types/unrecognized.ts diff --git a/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh b/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh index 57f84b5b..90285db9 100644 --- a/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh +++ b/frameworks-elysia/sdk-typescript/.devcontainer/setup.sh @@ -7,8 +7,8 @@ curl -fsSL https://raw.githubusercontent.com/speakeasy-api/speakeasy/main/instal rmdir samples || true mkdir samples -npm install -npm install -g ts-node +npm install --ignore-scripts +npm install -g ts-node --ignore-scripts npm link npm link sdk TS_CONFIG_CONTENT=$(cat < [!NOTE] -> This section is useful if you are using a bundler and targetting browsers and +> This section is useful if you are using a bundler and targeting browsers and > runtimes where the size of an application affects performance and load times. Every method in this SDK is also available as a standalone function. This -alternative API is suitable when targetting the browser or serverless runtimes +alternative API is suitable when targeting the browser or serverless runtimes and using a bundler to build your application since all unused functionality will be tree-shaken away. This includes code for unused methods, Zod schemas, encoding helpers and response handlers. The result is dramatically smaller @@ -20,37 +20,26 @@ specific category of applications. ```typescript import { SDKCore } from "sdk/core.js"; -import { usersGetUsers } from "sdk/funcs/usersGetUsers.js"; -import { SDKValidationError } from "sdk/models/errors/sdkvalidationerror.js"; +import { stationsGetStations } from "sdk/funcs/stationsGetStations.js"; // Use `SDKCore` for best tree-shaking performance. // You can create one instance of it to use across an application. -const sdk = new SDKCore(); +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const res = await usersGetUsers(sdk); - - switch (true) { - case res.ok: - // The success case will be handled outside of the switch block - break; - case res.error instanceof SDKValidationError: - // Pretty-print validation errors. - return console.log(res.error.pretty()); - case res.error instanceof Error: - return console.log(res.error); - default: - // TypeScript's type checking will fail on the following line if the above - // cases were not exhaustive. - res.error satisfies never; - throw new Error("Assertion failed: expected error checks to be exhaustive: " + res.error); + const res = await stationsGetStations(sdk, { + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("stationsGetStations failed:", res.error); } - - - const { value: result } = res; - - // Handle the result - console.log(result); } run(); diff --git a/frameworks-elysia/sdk-typescript/README.md b/frameworks-elysia/sdk-typescript/README.md index 9cc0e975..3fe06501 100644 --- a/frameworks-elysia/sdk-typescript/README.md +++ b/frameworks-elysia/sdk-typescript/README.md @@ -17,9 +17,7 @@ Developer-friendly & type-safe Typescript SDK specifically catered to leverage * ## Summary -Users app documentation: Development documentation - -For more information about the API: [Find out more about the Users API](www.example.com) +Train Travel API: API for finding and booking train trips across Europe. @@ -29,6 +27,7 @@ For more information about the API: [Find out more about the Users API](www.exam * [SDK Installation](#sdk-installation) * [Requirements](#requirements) * [SDK Example Usage](#sdk-example-usage) + * [Authentication](#authentication) * [Available Resources and Operations](#available-resources-and-operations) * [Standalone functions](#standalone-functions) * [Retries](#retries) @@ -45,6 +44,10 @@ For more information about the API: [Find out more about the Users API](www.exam ## SDK Installation +> [!TIP] +> To finish publishing your SDK to npm and others you must [run your first generation action](https://www.speakeasy.com/docs/github-setup#step-by-step-guide). + + The SDK can be installed with either [npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/), [bun](https://bun.sh/) or [yarn](https://classic.yarnpkg.com/en/) package managers. ### NPM @@ -68,10 +71,7 @@ bun add ### Yarn ```bash -yarn add zod - -# Note that Yarn does not install peer dependencies automatically. You will need -# to install zod as shown above. +yarn add ``` @@ -89,12 +89,17 @@ For supported JavaScript runtimes, please consult [RUNTIMES.md](RUNTIMES.md). ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.getUsers(); + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); - // Handle the result console.log(result); } @@ -103,20 +108,64 @@ run(); ``` + +## Authentication + +### Per-Client Security Schemes + +This SDK supports the following security scheme globally: + +| Name | Type | Scheme | Environment Variable | +| -------- | ------ | ------------ | -------------------- | +| `oAuth2` | oauth2 | OAuth2 token | `SDK_O_AUTH2` | + +To authenticate with the API the `oAuth2` parameter must be set when initializing the SDK client instance. For example: +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + + console.log(result); +} + +run(); + +``` + + ## Available Resources and Operations
Available methods +### [Bookings](docs/sdks/bookings/README.md) + +* [getBookings](docs/sdks/bookings/README.md#getbookings) - List existing bookings +* [createBooking](docs/sdks/bookings/README.md#createbooking) - Create a booking +* [getBooking](docs/sdks/bookings/README.md#getbooking) - Get a booking +* [deleteBooking](docs/sdks/bookings/README.md#deletebooking) - Delete a booking -### [users](docs/sdks/users/README.md) +### [Payments](docs/sdks/payments/README.md) -* [getUsers](docs/sdks/users/README.md#getusers) - Get all users -* [postUsers](docs/sdks/users/README.md#postusers) - Create user -* [getUsersById](docs/sdks/users/README.md#getusersbyid) - Get user -* [deleteUsersById](docs/sdks/users/README.md#deleteusersbyid) - Delete user -* [patchUsersById](docs/sdks/users/README.md#patchusersbyid) - Update user +* [createBookingPayment](docs/sdks/payments/README.md#createbookingpayment) - Pay for a booking + +### [Stations](docs/sdks/stations/README.md) + +* [getStations](docs/sdks/stations/README.md#getstations) - Get a list of train stations + +### [Trips](docs/sdks/trips/README.md) + +* [getTrips](docs/sdks/trips/README.md#gettrips) - Get available train trips
@@ -136,11 +185,13 @@ To read more about standalone functions, check [FUNCTIONS.md](./FUNCTIONS.md). Available standalone functions -- [`usersDeleteUsersById`](docs/sdks/users/README.md#deleteusersbyid) - Delete user -- [`usersGetUsers`](docs/sdks/users/README.md#getusers) - Get all users -- [`usersGetUsersById`](docs/sdks/users/README.md#getusersbyid) - Get user -- [`usersPatchUsersById`](docs/sdks/users/README.md#patchusersbyid) - Update user -- [`usersPostUsers`](docs/sdks/users/README.md#postusers) - Create user +- [`bookingsCreateBooking`](docs/sdks/bookings/README.md#createbooking) - Create a booking +- [`bookingsDeleteBooking`](docs/sdks/bookings/README.md#deletebooking) - Delete a booking +- [`bookingsGetBooking`](docs/sdks/bookings/README.md#getbooking) - Get a booking +- [`bookingsGetBookings`](docs/sdks/bookings/README.md#getbookings) - List existing bookings +- [`paymentsCreateBookingPayment`](docs/sdks/payments/README.md#createbookingpayment) - Pay for a booking +- [`stationsGetStations`](docs/sdks/stations/README.md#getstations) - Get a list of train stations +- [`tripsGetTrips`](docs/sdks/trips/README.md#gettrips) - Get available train trips @@ -154,10 +205,16 @@ To change the default retry strategy for a single API call, simply provide a ret ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.getUsers({ + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }, { retries: { strategy: "backoff", backoff: { @@ -170,7 +227,6 @@ async function run() { }, }); - // Handle the result console.log(result); } @@ -193,12 +249,16 @@ const sdk = new SDK({ }, retryConnectionErrors: false, }, + oAuth2: process.env["SDK_O_AUTH2"] ?? "", }); async function run() { - const result = await sdk.users.getUsers(); + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); - // Handle the result console.log(result); } @@ -210,54 +270,49 @@ run(); ## Error Handling -All SDK methods return a response object or throw an error. By default, an API error will throw a `errors.APIError`. - -If a HTTP request fails, an operation my also throw an error from the `models/errors/httpclienterrors.ts` module: - -| HTTP Client Error | Description | -| ---------------------------------------------------- | ---------------------------------------------------- | -| RequestAbortedError | HTTP request was aborted by the client | -| RequestTimeoutError | HTTP request timed out due to an AbortSignal signal | -| ConnectionError | HTTP client was unable to make a request to a server | -| InvalidRequestError | Any input used to create a request is invalid | -| UnexpectedClientError | Unrecognised or unexpected error | +[`SDKError`](./src/models/errors/sdkerror.ts) is the base class for all HTTP error responses. It has the following properties: -In addition, when custom error responses are specified for an operation, the SDK may throw their associated Error type. You can refer to respective *Errors* tables in SDK docs for more details on possible error types for each operation. For example, the `getUsers` method may throw the following errors: - -| Error Type | Status Code | Content Type | -| -------------------- | ----------- | ---------------- | -| errors.ErrorResponse | 500 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | +| Property | Type | Description | +| ------------------- | ---------- | --------------------------------------------------------------------------------------- | +| `error.message` | `string` | Error message | +| `error.statusCode` | `number` | HTTP response status code eg `404` | +| `error.headers` | `Headers` | HTTP response headers | +| `error.body` | `string` | HTTP body. Can be empty string if no body is returned. | +| `error.rawResponse` | `Response` | Raw HTTP response | +| `error.data$` | | Optional. Some errors may contain structured data. [See Error Classes](#error-classes). | +### Example ```typescript import { SDK } from "sdk"; -import { ErrorResponse, SDKValidationError } from "sdk/models/errors"; +import * as errors from "sdk/models/errors"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - let result; try { - result = await sdk.users.getUsers(); + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); - // Handle the result console.log(result); - } catch (err) { - switch (true) { - case (err instanceof SDKValidationError): { - // Validation errors can be pretty-printed - console.error(err.pretty()); - // Raw value may also be inspected - console.error(err.rawValue); - return; - } - case (err instanceof ErrorResponse): { - // Handle err.data$: ErrorResponseData - console.error(err); - return; - } - default: { - throw err; + } catch (error) { + // The base class for HTTP error responses + if (error instanceof errors.SDKError) { + console.log(error.message); + console.log(error.statusCode); + console.log(error.body); + console.log(error.headers); + + // Depending on the method different errors may be thrown + if (error instanceof errors.GetStationsResponseBody) { + console.log(error.data$.type); // string + console.log(error.data$.title); // string + console.log(error.data$.status); // number + console.log(error.data$.detail); // string } } } @@ -267,12 +322,75 @@ run(); ``` -Validation errors can also occur when either method arguments or data returned from the server do not match the expected format. The `SDKValidationError` that is thrown as a result will capture the raw value that failed validation in an attribute called `rawValue`. Additionally, a `pretty()` method is available on this error that can be used to log a nicely formatted string since validation errors can list many issues and the plain error string may be difficult read when debugging. +### Error Classes +**Primary error:** +* [`SDKError`](./src/models/errors/sdkerror.ts): The base class for HTTP error responses. + +
Less common errors (15) + +
+ +**Network errors:** +* [`ConnectionError`](./src/models/errors/httpclienterrors.ts): HTTP client was unable to make a request to a server. +* [`RequestTimeoutError`](./src/models/errors/httpclienterrors.ts): HTTP request timed out due to an AbortSignal signal. +* [`RequestAbortedError`](./src/models/errors/httpclienterrors.ts): HTTP request was aborted by the client. +* [`InvalidRequestError`](./src/models/errors/httpclienterrors.ts): Any input used to create a request is invalid. +* [`UnexpectedClientError`](./src/models/errors/httpclienterrors.ts): Unrecognised or unexpected error. + + +**Inherit from [`SDKError`](./src/models/errors/sdkerror.ts)**: +* [`GetStationsResponseBody`](./src/models/errors/getstationsresponsebody.ts): Bad Request. Status code `400`. Applicable to 1 of 7 methods.* +* [`GetTripsResponseBody`](./src/models/errors/gettripsresponsebody.ts): Bad Request. Status code `400`. Applicable to 1 of 7 methods.* +* [`GetBookingsResponseBody`](./src/models/errors/getbookingsresponsebody.ts): Unauthorized. Status code `401`. Applicable to 1 of 7 methods.* +* [`CreateBookingResponseBody`](./src/models/errors/createbookingresponsebody.ts): Not Found. Status code `404`. Applicable to 1 of 7 methods.* +* [`GetBookingResponseBody`](./src/models/errors/getbookingresponsebody.ts): Not Found. Status code `404`. Applicable to 1 of 7 methods.* +* [`DeleteBookingResponseBody`](./src/models/errors/deletebookingresponsebody.ts): Not Found. Status code `404`. Applicable to 1 of 7 methods.* +* [`CreateBookingPaymentResponseBody`](./src/models/errors/createbookingpaymentresponsebody.ts): Not Found. Status code `404`. Applicable to 1 of 7 methods.* +* [`CreateBookingBookingsResponseBody`](./src/models/errors/createbookingbookingsresponsebody.ts): Conflict. Status code `409`. Applicable to 1 of 7 methods.* +* [`GetBookingsBookingsResponseBody`](./src/models/errors/getbookingsbookingsresponsebody.ts): Internal Server Error. Status code `500`. Applicable to 1 of 7 methods.* +* [`ResponseValidationError`](./src/models/errors/responsevalidationerror.ts): Type mismatch between the data returned from the server and the structure expected by the SDK. See `error.rawValue` for the raw value and `error.pretty()` for a nicely formatted multi-line string. + +
+ +\* Check [the method documentation](#available-resources-and-operations) to see if the error is applicable. ## Server Selection +### Select Server by Index + +You can override the default server globally by passing a server index to the `serverIdx: number` optional parameter when initializing the SDK client instance. The selected server will then be used as the default on the operations that use it. This table lists the indexes associated with the available servers: + +| # | Server | Description | +| --- | ------------------------- | ------------------ | +| 0 | `https://api.example.com` | Production | +| 1 | `http://localhost:3000` | Development server | + +#### Example + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + serverIdx: 0, + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + + console.log(result); +} + +run(); + +``` + ### Override Server URL Per-Client The default server can also be overridden globally by passing a URL to the `serverURL: string` optional parameter when initializing the SDK client instance. For example: @@ -280,13 +398,17 @@ The default server can also be overridden globally by passing a URL to the `serv import { SDK } from "sdk"; const sdk = new SDK({ - serverURL: "http://localhost:3000/", + serverURL: "http://localhost:3000", + oAuth2: process.env["SDK_O_AUTH2"] ?? "", }); async function run() { - const result = await sdk.users.getUsers(); + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); - // Handle the result console.log(result); } @@ -308,19 +430,23 @@ The `HTTPClient` constructor takes an optional `fetcher` argument that can be used to integrate a third-party HTTP client or when writing tests to mock out the HTTP client and feed in fixtures. -The following example shows how to use the `"beforeRequest"` hook to to add a -custom header and a timeout to requests and how to use the `"requestError"` hook -to log errors: +The following example shows how to: +- route requests through a proxy server using [undici](https://www.npmjs.com/package/undici)'s ProxyAgent +- use the `"beforeRequest"` hook to add a custom header and a timeout to requests +- use the `"requestError"` hook to log errors ```typescript import { SDK } from "sdk"; +import { ProxyAgent } from "undici"; import { HTTPClient } from "sdk/lib/http"; +const dispatcher = new ProxyAgent("http://proxy.example.com:8080"); + const httpClient = new HTTPClient({ - // fetcher takes a function that has the same signature as native `fetch`. - fetcher: (request) => { - return fetch(request); - } + // 'fetcher' takes a function that has the same signature as native 'fetch'. + fetcher: (input, init) => + // 'dispatcher' is specific to undici and not part of the standard Fetch API. + fetch(input, { ...init, dispatcher } as RequestInit), }); httpClient.addHook("beforeRequest", (request) => { @@ -340,7 +466,7 @@ httpClient.addHook("requestError", (error, request) => { console.groupEnd(); }); -const sdk = new SDK({ httpClient }); +const sdk = new SDK({ httpClient: httpClient }); ``` diff --git a/frameworks-elysia/sdk-typescript/RUNTIMES.md b/frameworks-elysia/sdk-typescript/RUNTIMES.md index d08a0c07..27731c3b 100644 --- a/frameworks-elysia/sdk-typescript/RUNTIMES.md +++ b/frameworks-elysia/sdk-typescript/RUNTIMES.md @@ -1,10 +1,10 @@ # Supported JavaScript runtimes -This SDK is intended to be used in JavaScript runtimes that support the following features: +This SDK is intended to be used in JavaScript runtimes that support ECMAScript 2020 or newer. The SDK uses the following features: -* [Web Fetch API][web-fetch] -* [Web Streams API][web-streams] and in particular `ReadableStream` -* [Async iterables][async-iter] using `Symbol.asyncIterator` +- [Web Fetch API][web-fetch] +- [Web Streams API][web-streams] and in particular `ReadableStream` +- [Async iterables][async-iter] using `Symbol.asyncIterator` [web-fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API [web-streams]: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API @@ -20,3 +20,29 @@ Runtime environments that are explicitly supported are: - Note that Deno does not currently have native support for streaming file uploads backed by the filesystem ([issue link][deno-file-streaming]) [deno-file-streaming]: https://github.com/denoland/deno/issues/11018 + +## Recommended TypeScript compiler options + +The following `tsconfig.json` options are recommended for projects using this +SDK in order to get static type support for features like async iterables, +streams and `fetch`-related APIs ([`for await...of`][for-await-of], +[`AbortSignal`][abort-signal], [`Request`][request], [`Response`][response] and +so on): + +[for-await-of]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of +[abort-signal]: https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal +[request]: https://developer.mozilla.org/en-US/docs/Web/API/Request +[response]: https://developer.mozilla.org/en-US/docs/Web/API/Response + +```jsonc +{ + "compilerOptions": { + "target": "es2020", // or higher + "lib": ["es2020", "dom", "dom.iterable"] + } +} +``` + +While `target` can be set to older ECMAScript versions, it may result in extra, +unnecessary compatibility code being generated if you are not targeting old +runtimes. diff --git a/frameworks-elysia/sdk-typescript/USAGE.md b/frameworks-elysia/sdk-typescript/USAGE.md index d24de951..3c0a5ee3 100644 --- a/frameworks-elysia/sdk-typescript/USAGE.md +++ b/frameworks-elysia/sdk-typescript/USAGE.md @@ -2,12 +2,17 @@ ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.getUsers(); + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); - // Handle the result console.log(result); } diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/id.md b/frameworks-elysia/sdk-typescript/docs/models/components/id.md deleted file mode 100644 index 00405d3f..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/components/id.md +++ /dev/null @@ -1,17 +0,0 @@ -# Id - -## Example Usage - -```typescript -import { Id } from "sdk/models/components"; - -let value: Id = { - id: "1", -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/security.md b/frameworks-elysia/sdk-typescript/docs/models/components/security.md new file mode 100644 index 00000000..5ef3a75f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/components/security.md @@ -0,0 +1,15 @@ +# Security + +## Example Usage + +```typescript +import { Security } from "sdk/models/components"; + +let value: Security = {}; +``` + +## Fields + +| Field | Type | Required | Description | +| ------------------ | ------------------ | ------------------ | ------------------ | +| `oAuth2` | *string* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md b/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md deleted file mode 100644 index 39b5825f..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/components/successresponse.md +++ /dev/null @@ -1,17 +0,0 @@ -# SuccessResponse - -## Example Usage - -```typescript -import { SuccessResponse } from "sdk/models/components"; - -let value: SuccessResponse = { - success: true, -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `success` | *boolean* | :heavy_check_mark: | N/A | true | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/components/user.md b/frameworks-elysia/sdk-typescript/docs/models/components/user.md deleted file mode 100644 index 3f29da87..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/components/user.md +++ /dev/null @@ -1,21 +0,0 @@ -# User - -## Example Usage - -```typescript -import { User } from "sdk/models/components"; - -let value: User = { - id: "1", - name: "Alice", - age: 20, -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `id` | *string* | :heavy_check_mark: | N/A | 1 | -| `name` | *string* | :heavy_check_mark: | N/A | Alice | -| `age` | *number* | :heavy_check_mark: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingbookingsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingbookingsresponsebody.md new file mode 100644 index 00000000..1ee2b75a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingbookingsresponsebody.md @@ -0,0 +1,20 @@ +# CreateBookingBookingsResponseBody + +Conflict + +## Example Usage + +```typescript +import { CreateBookingBookingsResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingpaymentresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingpaymentresponsebody.md new file mode 100644 index 00000000..1047acc7 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingpaymentresponsebody.md @@ -0,0 +1,20 @@ +# CreateBookingPaymentResponseBody + +Not Found + +## Example Usage + +```typescript +import { CreateBookingPaymentResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingresponsebody.md new file mode 100644 index 00000000..920a109c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/createbookingresponsebody.md @@ -0,0 +1,20 @@ +# CreateBookingResponseBody + +Not Found + +## Example Usage + +```typescript +import { CreateBookingResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/deletebookingresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/deletebookingresponsebody.md new file mode 100644 index 00000000..789eede4 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/deletebookingresponsebody.md @@ -0,0 +1,20 @@ +# DeleteBookingResponseBody + +Not Found + +## Example Usage + +```typescript +import { DeleteBookingResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md b/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md deleted file mode 100644 index 11a01f62..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/errors/errorresponse.md +++ /dev/null @@ -1,16 +0,0 @@ -# ErrorResponse - -## Example Usage - -```typescript -import { ErrorResponse } from "sdk/models/errors"; - -// No examples available for this model -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `status` | *number* | :heavy_check_mark: | N/A | 404 | -| `message` | *string* | :heavy_check_mark: | N/A | User not found :( | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingresponsebody.md new file mode 100644 index 00000000..04a980e1 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingresponsebody.md @@ -0,0 +1,20 @@ +# GetBookingResponseBody + +Not Found + +## Example Usage + +```typescript +import { GetBookingResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsbookingsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsbookingsresponsebody.md new file mode 100644 index 00000000..7743a6e0 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsbookingsresponsebody.md @@ -0,0 +1,20 @@ +# GetBookingsBookingsResponseBody + +Internal Server Error + +## Example Usage + +```typescript +import { GetBookingsBookingsResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsresponsebody.md new file mode 100644 index 00000000..8e57e781 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/getbookingsresponsebody.md @@ -0,0 +1,20 @@ +# GetBookingsResponseBody + +Unauthorized + +## Example Usage + +```typescript +import { GetBookingsResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/getstationsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/getstationsresponsebody.md new file mode 100644 index 00000000..5d539051 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/getstationsresponsebody.md @@ -0,0 +1,20 @@ +# GetStationsResponseBody + +Bad Request + +## Example Usage + +```typescript +import { GetStationsResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/errors/gettripsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/errors/gettripsresponsebody.md new file mode 100644 index 00000000..aaefe467 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/errors/gettripsresponsebody.md @@ -0,0 +1,20 @@ +# GetTripsResponseBody + +Bad Request + +## Example Usage + +```typescript +import { GetTripsResponseBody } from "sdk/models/errors"; + +// No examples available for this model +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | ------------------------------------- | +| `type` | *string* | :heavy_check_mark: | N/A | https://example.com/errors/not-found | +| `title` | *string* | :heavy_check_mark: | N/A | Not Found | +| `status` | *number* | :heavy_check_mark: | N/A | 404 | +| `detail` | *string* | :heavy_check_mark: | N/A | The requested resource was not found. | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingbookingsrequestrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingbookingsrequestrequestbody.md new file mode 100644 index 00000000..032c3922 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingbookingsrequestrequestbody.md @@ -0,0 +1,25 @@ +# CreateBookingBookingsRequestRequestBody + +Booking details. + +## Example Usage + +```typescript +import { CreateBookingBookingsRequestRequestBody } from "sdk/models/operations"; + +let value: CreateBookingBookingsRequestRequestBody = { + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | +| `tripId` | *string* | :heavy_check_mark: | N/A | ea399ba1-6d95-433f-92d1-83f67b775594 | +| `passengerName` | *string* | :heavy_check_mark: | N/A | John Doe | +| `hasBicycle` | *boolean* | :heavy_minus_sign: | N/A | true | +| `hasDog` | *boolean* | :heavy_minus_sign: | N/A | false | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookinglinks.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookinglinks.md new file mode 100644 index 00000000..8e505848 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookinglinks.md @@ -0,0 +1,17 @@ +# CreateBookingLinks + +## Example Usage + +```typescript +import { CreateBookingLinks } from "sdk/models/operations"; + +let value: CreateBookingLinks = { + self: "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `self` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentlinks.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentlinks.md new file mode 100644 index 00000000..f20641ae --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentlinks.md @@ -0,0 +1,18 @@ +# CreateBookingPaymentLinks + +## Example Usage + +```typescript +import { CreateBookingPaymentLinks } from "sdk/models/operations"; + +let value: CreateBookingPaymentLinks = { + booking: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `booking` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentscurrency.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentscurrency.md new file mode 100644 index 00000000..fc1bb9bb --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentscurrency.md @@ -0,0 +1,15 @@ +# CreateBookingPaymentPaymentsCurrency + +## Example Usage + +```typescript +import { CreateBookingPaymentPaymentsCurrency } from "sdk/models/operations"; + +let value: CreateBookingPaymentPaymentsCurrency = "bam"; +``` + +## Values + +```typescript +"bam" | "bgn" | "chf" | "eur" | "gbp" | "nok" | "sek" +``` \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsrequestrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsrequestrequestbody.md new file mode 100644 index 00000000..ccbda0e5 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsrequestrequestbody.md @@ -0,0 +1,31 @@ +# CreateBookingPaymentPaymentsRequestRequestBody + +## Example Usage + +```typescript +import { CreateBookingPaymentPaymentsRequestRequestBody } from "sdk/models/operations"; + +let value: CreateBookingPaymentPaymentsRequestRequestBody = { + amount: 49.99, + currency: "eur", + promoCode: "SUMMER20", + source: { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | +| `amount` | *number* | :heavy_check_mark: | N/A | 49.99 | +| `currency` | [operations.CreateBookingPaymentPaymentsCurrency](../../models/operations/createbookingpaymentpaymentscurrency.md) | :heavy_check_mark: | N/A | | +| `promoCode` | *string* | :heavy_minus_sign: | N/A | SUMMER20 | +| `source` | *operations.CreateBookingPaymentPaymentsSource* | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsresponsesource.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsresponsesource.md new file mode 100644 index 00000000..daee501b --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentsresponsesource.md @@ -0,0 +1,34 @@ +# CreateBookingPaymentPaymentsResponseSource + + +## Supported Types + +### `operations.CreateBookingPaymentSourcePayments1` + +```typescript +const value: operations.CreateBookingPaymentSourcePayments1 = { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + addressPostCode: "N12 9XX", +}; +``` + +### `operations.CreateBookingPaymentSourcePayments2` + +```typescript +const value: operations.CreateBookingPaymentSourcePayments2 = { + object: "bank_account", + name: "J. Doe", + number: "00012345", + sortCode: "000123", + accountType: "individual", + bankName: "Starling Bank", + country: "gb", +}; +``` + diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentssource.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentssource.md new file mode 100644 index 00000000..42b2b71d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentpaymentssource.md @@ -0,0 +1,34 @@ +# CreateBookingPaymentPaymentsSource + + +## Supported Types + +### `operations.CreateBookingPaymentSource1` + +```typescript +const value: operations.CreateBookingPaymentSource1 = { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + addressPostCode: "N12 9XX", +}; +``` + +### `operations.CreateBookingPaymentSource2` + +```typescript +const value: operations.CreateBookingPaymentSource2 = { + object: "bank_account", + name: "J. Doe", + number: "00012345", + sortCode: "000123", + accountType: "company", + bankName: "Starling Bank", + country: "gb", +}; +``` + diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentrequest.md new file mode 100644 index 00000000..f19843e6 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentrequest.md @@ -0,0 +1,32 @@ +# CreateBookingPaymentRequest + +## Example Usage + +```typescript +import { CreateBookingPaymentRequest } from "sdk/models/operations"; + +let value: CreateBookingPaymentRequest = { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", + requestBody: { + amount: 49.99, + currency: "gbp", + promoCode: "SUMMER20", + source: { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + }, + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `bookingId` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | +| `requestBody` | [operations.CreateBookingPaymentPaymentsRequestRequestBody](../../models/operations/createbookingpaymentpaymentsrequestrequestbody.md) | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentresponsebody.md new file mode 100644 index 00000000..a44bec2d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentresponsebody.md @@ -0,0 +1,40 @@ +# CreateBookingPaymentResponseBody + +Payment successful + +## Example Usage + +```typescript +import { CreateBookingPaymentResponseBody } from "sdk/models/operations"; + +let value: CreateBookingPaymentResponseBody = { + id: "2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a", + amount: 49.99, + currency: "gbp", + source: { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + }, + status: "failed", + links: { + booking: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `id` | *string* | :heavy_check_mark: | N/A | 2e3b4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a | +| `amount` | *number* | :heavy_check_mark: | N/A | 49.99 | +| `currency` | *string* | :heavy_check_mark: | N/A | gbp | +| `source` | *operations.CreateBookingPaymentPaymentsResponseSource* | :heavy_check_mark: | N/A | | +| `status` | [operations.Status](../../models/operations/status.md) | :heavy_check_mark: | N/A | | +| `links` | [operations.CreateBookingPaymentLinks](../../models/operations/createbookingpaymentlinks.md) | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource1.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource1.md new file mode 100644 index 00000000..7c1925c4 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource1.md @@ -0,0 +1,31 @@ +# CreateBookingPaymentSource1 + +## Example Usage + +```typescript +import { CreateBookingPaymentSource1 } from "sdk/models/operations"; + +let value: CreateBookingPaymentSource1 = { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + addressPostCode: "N12 9XX", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `object` | *"card"* | :heavy_check_mark: | N/A | | +| `name` | *string* | :heavy_check_mark: | N/A | J. Doe | +| `number` | *string* | :heavy_check_mark: | N/A | 4242424242424242 | +| `cvc` | *string* | :heavy_check_mark: | N/A | 123 | +| `expMonth` | *number* | :heavy_check_mark: | N/A | 12 | +| `expYear` | *number* | :heavy_check_mark: | N/A | 2025 | +| `addressCountry` | *string* | :heavy_check_mark: | N/A | gb | +| `addressPostCode` | *string* | :heavy_minus_sign: | N/A | N12 9XX | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource2.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource2.md new file mode 100644 index 00000000..10860e66 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsource2.md @@ -0,0 +1,29 @@ +# CreateBookingPaymentSource2 + +## Example Usage + +```typescript +import { CreateBookingPaymentSource2 } from "sdk/models/operations"; + +let value: CreateBookingPaymentSource2 = { + object: "bank_account", + name: "J. Doe", + number: "00012345", + sortCode: "000123", + accountType: "company", + bankName: "Starling Bank", + country: "gb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `object` | *"bank_account"* | :heavy_check_mark: | N/A | | +| `name` | *string* | :heavy_check_mark: | N/A | J. Doe | +| `number` | *string* | :heavy_check_mark: | N/A | 00012345 | +| `sortCode` | *string* | :heavy_minus_sign: | N/A | 000123 | +| `accountType` | [operations.CreateBookingPaymentSourceAccountType](../../models/operations/createbookingpaymentsourceaccounttype.md) | :heavy_check_mark: | N/A | | +| `bankName` | *string* | :heavy_check_mark: | N/A | Starling Bank | +| `country` | *string* | :heavy_check_mark: | N/A | gb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourceaccounttype.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourceaccounttype.md new file mode 100644 index 00000000..13045acb --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourceaccounttype.md @@ -0,0 +1,15 @@ +# CreateBookingPaymentSourceAccountType + +## Example Usage + +```typescript +import { CreateBookingPaymentSourceAccountType } from "sdk/models/operations"; + +let value: CreateBookingPaymentSourceAccountType = "individual"; +``` + +## Values + +```typescript +"individual" | "company" +``` \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments1.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments1.md new file mode 100644 index 00000000..3695fceb --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments1.md @@ -0,0 +1,31 @@ +# CreateBookingPaymentSourcePayments1 + +## Example Usage + +```typescript +import { CreateBookingPaymentSourcePayments1 } from "sdk/models/operations"; + +let value: CreateBookingPaymentSourcePayments1 = { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + addressPostCode: "N12 9XX", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `object` | *"card"* | :heavy_check_mark: | N/A | | +| `name` | *string* | :heavy_check_mark: | N/A | J. Doe | +| `number` | *string* | :heavy_check_mark: | N/A | 4242424242424242 | +| `cvc` | *string* | :heavy_check_mark: | N/A | 123 | +| `expMonth` | *number* | :heavy_check_mark: | N/A | 12 | +| `expYear` | *number* | :heavy_check_mark: | N/A | 2025 | +| `addressCountry` | *string* | :heavy_check_mark: | N/A | gb | +| `addressPostCode` | *string* | :heavy_minus_sign: | N/A | N12 9XX | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments2.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments2.md new file mode 100644 index 00000000..5ec7a56d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepayments2.md @@ -0,0 +1,29 @@ +# CreateBookingPaymentSourcePayments2 + +## Example Usage + +```typescript +import { CreateBookingPaymentSourcePayments2 } from "sdk/models/operations"; + +let value: CreateBookingPaymentSourcePayments2 = { + object: "bank_account", + name: "J. Doe", + number: "00012345", + sortCode: "000123", + accountType: "individual", + bankName: "Starling Bank", + country: "gb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | +| `object` | *"bank_account"* | :heavy_check_mark: | N/A | | +| `name` | *string* | :heavy_check_mark: | N/A | J. Doe | +| `number` | *string* | :heavy_check_mark: | N/A | 00012345 | +| `sortCode` | *string* | :heavy_minus_sign: | N/A | 000123 | +| `accountType` | [operations.CreateBookingPaymentSourcePaymentsAccountType](../../models/operations/createbookingpaymentsourcepaymentsaccounttype.md) | :heavy_check_mark: | N/A | | +| `bankName` | *string* | :heavy_check_mark: | N/A | Starling Bank | +| `country` | *string* | :heavy_check_mark: | N/A | gb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepaymentsaccounttype.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepaymentsaccounttype.md new file mode 100644 index 00000000..23d3013c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingpaymentsourcepaymentsaccounttype.md @@ -0,0 +1,15 @@ +# CreateBookingPaymentSourcePaymentsAccountType + +## Example Usage + +```typescript +import { CreateBookingPaymentSourcePaymentsAccountType } from "sdk/models/operations"; + +let value: CreateBookingPaymentSourcePaymentsAccountType = "individual"; +``` + +## Values + +```typescript +"individual" | "company" +``` \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingresponsebody.md new file mode 100644 index 00000000..58b02515 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/createbookingresponsebody.md @@ -0,0 +1,32 @@ +# CreateBookingResponseBody + +A booking for a train trip. + +## Example Usage + +```typescript +import { CreateBookingResponseBody } from "sdk/models/operations"; + +let value: CreateBookingResponseBody = { + id: "1725ff48-ab45-4bb5-9d02-88745177dedb", + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, + links: { + self: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | +| `tripId` | *string* | :heavy_check_mark: | N/A | ea399ba1-6d95-433f-92d1-83f67b775594 | +| `passengerName` | *string* | :heavy_check_mark: | N/A | John Doe | +| `hasBicycle` | *boolean* | :heavy_check_mark: | N/A | true | +| `hasDog` | *boolean* | :heavy_check_mark: | N/A | false | +| `links` | [operations.CreateBookingLinks](../../models/operations/createbookinglinks.md) | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/data.md b/frameworks-elysia/sdk-typescript/docs/models/operations/data.md new file mode 100644 index 00000000..3547186d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/data.md @@ -0,0 +1,27 @@ +# Data + +A train station. + +## Example Usage + +```typescript +import { Data } from "sdk/models/operations"; + +let value: Data = { + id: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + name: "Berlin Hauptbahnhof", + address: "Invalidenstrasse 10557 Berlin, Germany", + countryCode: "DE", + timezone: "Europe/Berlin", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | +| `id` | *string* | :heavy_check_mark: | N/A | efdbb9d1-02c2-4bc3-afb7-6788d8782b1e | +| `name` | *string* | :heavy_check_mark: | N/A | Berlin Hauptbahnhof | +| `address` | *string* | :heavy_check_mark: | N/A | Invalidenstrasse 10557 Berlin, Germany | +| `countryCode` | *string* | :heavy_check_mark: | N/A | DE | +| `timezone` | *string* | :heavy_check_mark: | N/A | Europe/Berlin | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/deletebookingrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/deletebookingrequest.md new file mode 100644 index 00000000..5082d2e8 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/deletebookingrequest.md @@ -0,0 +1,17 @@ +# DeleteBookingRequest + +## Example Usage + +```typescript +import { DeleteBookingRequest } from "sdk/models/operations"; + +let value: DeleteBookingRequest = { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | +| `bookingId` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md deleted file mode 100644 index 63293192..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/operations/deleteusersbyidrequest.md +++ /dev/null @@ -1,17 +0,0 @@ -# DeleteUsersByIdRequest - -## Example Usage - -```typescript -import { DeleteUsersByIdRequest } from "sdk/models/operations"; - -let value: DeleteUsersByIdRequest = { - id: "1", -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookinglinks.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookinglinks.md new file mode 100644 index 00000000..630a166d --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookinglinks.md @@ -0,0 +1,17 @@ +# GetBookingLinks + +## Example Usage + +```typescript +import { GetBookingLinks } from "sdk/models/operations"; + +let value: GetBookingLinks = { + self: "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `self` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingrequest.md new file mode 100644 index 00000000..6248731a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingrequest.md @@ -0,0 +1,17 @@ +# GetBookingRequest + +## Example Usage + +```typescript +import { GetBookingRequest } from "sdk/models/operations"; + +let value: GetBookingRequest = { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | +| `bookingId` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingresponsebody.md new file mode 100644 index 00000000..3e2d973f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingresponsebody.md @@ -0,0 +1,32 @@ +# GetBookingResponseBody + +A booking for a train trip. + +## Example Usage + +```typescript +import { GetBookingResponseBody } from "sdk/models/operations"; + +let value: GetBookingResponseBody = { + id: "1725ff48-ab45-4bb5-9d02-88745177dedb", + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, + links: { + self: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | +| `tripId` | *string* | :heavy_check_mark: | N/A | ea399ba1-6d95-433f-92d1-83f67b775594 | +| `passengerName` | *string* | :heavy_check_mark: | N/A | John Doe | +| `hasBicycle` | *boolean* | :heavy_check_mark: | N/A | true | +| `hasDog` | *boolean* | :heavy_check_mark: | N/A | false | +| `links` | [operations.GetBookingLinks](../../models/operations/getbookinglinks.md) | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsdata.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsdata.md new file mode 100644 index 00000000..4c278c44 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsdata.md @@ -0,0 +1,27 @@ +# GetBookingsData + +A booking for a train trip. + +## Example Usage + +```typescript +import { GetBookingsData } from "sdk/models/operations"; + +let value: GetBookingsData = { + id: "1725ff48-ab45-4bb5-9d02-88745177dedb", + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ | +| `id` | *string* | :heavy_check_mark: | N/A | 1725ff48-ab45-4bb5-9d02-88745177dedb | +| `tripId` | *string* | :heavy_check_mark: | N/A | ea399ba1-6d95-433f-92d1-83f67b775594 | +| `passengerName` | *string* | :heavy_check_mark: | N/A | John Doe | +| `hasBicycle` | *boolean* | :heavy_check_mark: | N/A | true | +| `hasDog` | *boolean* | :heavy_check_mark: | N/A | false | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingslinks.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingslinks.md new file mode 100644 index 00000000..14deec96 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingslinks.md @@ -0,0 +1,21 @@ +# GetBookingsLinks + +## Example Usage + +```typescript +import { GetBookingsLinks } from "sdk/models/operations"; + +let value: GetBookingsLinks = { + self: "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `self` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | +| `next` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=2 | +| `prev` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsrequest.md new file mode 100644 index 00000000..4faff3d9 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsrequest.md @@ -0,0 +1,16 @@ +# GetBookingsRequest + +## Example Usage + +```typescript +import { GetBookingsRequest } from "sdk/models/operations"; + +let value: GetBookingsRequest = {}; +``` + +## Fields + +| Field | Type | Required | Description | +| ------------------ | ------------------ | ------------------ | ------------------ | +| `page` | *number* | :heavy_minus_sign: | N/A | +| `limit` | *number* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsresponsebody.md new file mode 100644 index 00000000..469a3939 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getbookingsresponsebody.md @@ -0,0 +1,34 @@ +# GetBookingsResponseBody + +A list of bookings + +## Example Usage + +```typescript +import { GetBookingsResponseBody } from "sdk/models/operations"; + +let value: GetBookingsResponseBody = { + data: [ + { + id: "1725ff48-ab45-4bb5-9d02-88745177dedb", + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, + }, + ], + links: { + self: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | +| `data` | [operations.GetBookingsData](../../models/operations/getbookingsdata.md)[] | :heavy_check_mark: | N/A | +| `links` | [operations.GetBookingsLinks](../../models/operations/getbookingslinks.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsrequest.md new file mode 100644 index 00000000..1623a939 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsrequest.md @@ -0,0 +1,23 @@ +# GetStationsRequest + +## Example Usage + +```typescript +import { GetStationsRequest } from "sdk/models/operations"; + +let value: GetStationsRequest = { + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | +| `page` | *number* | :heavy_minus_sign: | N/A | | +| `limit` | *number* | :heavy_minus_sign: | N/A | | +| `coordinates` | *string* | :heavy_minus_sign: | N/A | 52.5200,13.4050 | +| `search` | *string* | :heavy_minus_sign: | N/A | Milano Centrale | +| `country` | *string* | :heavy_minus_sign: | N/A | DE | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsresponsebody.md new file mode 100644 index 00000000..59321a7a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/getstationsresponsebody.md @@ -0,0 +1,34 @@ +# GetStationsResponseBody + +OK + +## Example Usage + +```typescript +import { GetStationsResponseBody } from "sdk/models/operations"; + +let value: GetStationsResponseBody = { + data: [ + { + id: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + name: "Berlin Hauptbahnhof", + address: "Invalidenstrasse 10557 Berlin, Germany", + countryCode: "DE", + timezone: "Europe/Berlin", + }, + ], + links: { + self: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | +| ---------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- | +| `data` | [operations.Data](../../models/operations/data.md)[] | :heavy_check_mark: | N/A | +| `links` | [operations.Links](../../models/operations/links.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsdata.md b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsdata.md new file mode 100644 index 00000000..411803de --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsdata.md @@ -0,0 +1,35 @@ +# GetTripsData + +A train trip. + +## Example Usage + +```typescript +import { GetTripsData } from "sdk/models/operations"; + +let value: GetTripsData = { + id: "ea399ba1-6d95-433f-92d1-83f67b775594", + origin: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + destination: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + departureTime: new Date("2024-02-01T10:00:00Z"), + arrivalTime: new Date("2024-02-01T16:00:00Z"), + operator: "Deutsche Bahn", + price: 50, + bicyclesAllowed: true, + dogsAllowed: true, +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `id` | *string* | :heavy_check_mark: | N/A | ea399ba1-6d95-433f-92d1-83f67b775594 | +| `origin` | *string* | :heavy_check_mark: | N/A | efdbb9d1-02c2-4bc3-afb7-6788d8782b1e | +| `destination` | *string* | :heavy_check_mark: | N/A | b2e783e1-c824-4d63-b37a-d8d698862f1d | +| `departureTime` | [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | :heavy_check_mark: | N/A | 2024-02-01T10:00:00Z | +| `arrivalTime` | [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | :heavy_check_mark: | N/A | 2024-02-01T16:00:00Z | +| `operator` | *string* | :heavy_check_mark: | N/A | Deutsche Bahn | +| `price` | *number* | :heavy_check_mark: | N/A | 50 | +| `bicyclesAllowed` | *boolean* | :heavy_check_mark: | N/A | true | +| `dogsAllowed` | *boolean* | :heavy_check_mark: | N/A | true | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/gettripslinks.md b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripslinks.md new file mode 100644 index 00000000..edcc2165 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripslinks.md @@ -0,0 +1,21 @@ +# GetTripsLinks + +## Example Usage + +```typescript +import { GetTripsLinks } from "sdk/models/operations"; + +let value: GetTripsLinks = { + self: "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `self` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | +| `next` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=2 | +| `prev` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsrequest.md new file mode 100644 index 00000000..9c429925 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsrequest.md @@ -0,0 +1,25 @@ +# GetTripsRequest + +## Example Usage + +```typescript +import { GetTripsRequest } from "sdk/models/operations"; + +let value: GetTripsRequest = { + origin: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + destination: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + date: new Date("2024-02-01T09:00:00Z"), +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `page` | *number* | :heavy_minus_sign: | N/A | | +| `limit` | *number* | :heavy_minus_sign: | N/A | | +| `origin` | *string* | :heavy_check_mark: | N/A | efdbb9d1-02c2-4bc3-afb7-6788d8782b1e | +| `destination` | *string* | :heavy_check_mark: | N/A | b2e783e1-c824-4d63-b37a-d8d698862f1d | +| `date` | [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | :heavy_check_mark: | N/A | 2024-02-01T09:00:00Z | +| `bicycles` | *boolean* | :heavy_minus_sign: | N/A | | +| `dogs` | *boolean* | :heavy_minus_sign: | N/A | | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsresponsebody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsresponsebody.md new file mode 100644 index 00000000..169ac890 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/gettripsresponsebody.md @@ -0,0 +1,38 @@ +# GetTripsResponseBody + +A list of available train trips + +## Example Usage + +```typescript +import { GetTripsResponseBody } from "sdk/models/operations"; + +let value: GetTripsResponseBody = { + data: [ + { + id: "ea399ba1-6d95-433f-92d1-83f67b775594", + origin: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + destination: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + departureTime: new Date("2024-02-01T10:00:00Z"), + arrivalTime: new Date("2024-02-01T16:00:00Z"), + operator: "Deutsche Bahn", + price: 50, + bicyclesAllowed: true, + dogsAllowed: true, + }, + ], + links: { + self: + "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", + }, +}; +``` + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | +| `data` | [operations.GetTripsData](../../models/operations/gettripsdata.md)[] | :heavy_check_mark: | N/A | +| `links` | [operations.GetTripsLinks](../../models/operations/gettripslinks.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md deleted file mode 100644 index 3291d6b4..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/operations/getusersbyidrequest.md +++ /dev/null @@ -1,17 +0,0 @@ -# GetUsersByIdRequest - -## Example Usage - -```typescript -import { GetUsersByIdRequest } from "sdk/models/operations"; - -let value: GetUsersByIdRequest = { - id: "1", -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `id` | *string* | :heavy_check_mark: | N/A | 1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/links.md b/frameworks-elysia/sdk-typescript/docs/models/operations/links.md new file mode 100644 index 00000000..161fdb60 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/links.md @@ -0,0 +1,21 @@ +# Links + +## Example Usage + +```typescript +import { Links } from "sdk/models/operations"; + +let value: Links = { + self: "https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb", + next: "https://api.example.com/bookings?page=2", + prev: "https://api.example.com/bookings?page=1", +}; +``` + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `self` | *string* | :heavy_check_mark: | N/A | https://api.example.com/bookings/1725ff48-ab45-4bb5-9d02-88745177dedb | +| `next` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=2 | +| `prev` | *string* | :heavy_minus_sign: | N/A | https://api.example.com/bookings?page=1 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md deleted file mode 100644 index acbcd606..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequest.md +++ /dev/null @@ -1,21 +0,0 @@ -# PatchUsersByIdRequest - -## Example Usage - -```typescript -import { PatchUsersByIdRequest } from "sdk/models/operations"; - -let value: PatchUsersByIdRequest = { - id: "1", - requestBody: { - age: 21, - }, -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -| `id` | *string* | :heavy_check_mark: | N/A | 1 | -| `requestBody` | [operations.PatchUsersByIdRequestBody](../../models/operations/patchusersbyidrequestbody.md) | :heavy_check_mark: | N/A | {
"age": 21
} | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md deleted file mode 100644 index d4ccc987..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/operations/patchusersbyidrequestbody.md +++ /dev/null @@ -1,18 +0,0 @@ -# PatchUsersByIdRequestBody - -## Example Usage - -```typescript -import { PatchUsersByIdRequestBody } from "sdk/models/operations"; - -let value: PatchUsersByIdRequestBody = { - age: 21, -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `name` | *string* | :heavy_minus_sign: | N/A | Alice | -| `age` | *number* | :heavy_minus_sign: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md b/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md deleted file mode 100644 index 111238b1..00000000 --- a/frameworks-elysia/sdk-typescript/docs/models/operations/postusersrequestbody.md +++ /dev/null @@ -1,19 +0,0 @@ -# PostUsersRequestBody - -## Example Usage - -```typescript -import { PostUsersRequestBody } from "sdk/models/operations"; - -let value: PostUsersRequestBody = { - name: "Alice", - age: 20, -}; -``` - -## Fields - -| Field | Type | Required | Description | Example | -| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | -| `name` | *string* | :heavy_check_mark: | N/A | Alice | -| `age` | *number* | :heavy_check_mark: | N/A | 20 | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/models/operations/status.md b/frameworks-elysia/sdk-typescript/docs/models/operations/status.md new file mode 100644 index 00000000..d98c8c30 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/models/operations/status.md @@ -0,0 +1,15 @@ +# Status + +## Example Usage + +```typescript +import { Status } from "sdk/models/operations"; + +let value: Status = "succeeded"; +``` + +## Values + +```typescript +"pending" | "succeeded" | "failed" +``` \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/users/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/bookings/README.md similarity index 67% rename from frameworks-elysia/sdk-typescript/docs/sdks/users/README.md rename to frameworks-elysia/sdk-typescript/docs/sdks/bookings/README.md index 6c8e00bc..2851f53d 100644 --- a/frameworks-elysia/sdk-typescript/docs/sdks/users/README.md +++ b/frameworks-elysia/sdk-typescript/docs/sdks/bookings/README.md @@ -1,36 +1,33 @@ -# Users -(*users*) +# Bookings ## Overview -Users operations - -Find more info here - +Create and manage bookings for train trips, including passenger details and optional extras. ### Available Operations -* [getUsers](#getusers) - Get all users -* [postUsers](#postusers) - Create user -* [getUsersById](#getusersbyid) - Get user -* [deleteUsersById](#deleteusersbyid) - Delete user -* [patchUsersById](#patchusersbyid) - Update user +* [getBookings](#getbookings) - List existing bookings +* [createBooking](#createbooking) - Create a booking +* [getBooking](#getbooking) - Get a booking +* [deleteBooking](#deletebooking) - Delete a booking -## getUsers +## getBookings -Get all users from the database +Returns a list of all trip bookings by the authenticated user. ### Example Usage + ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.getUsers(); + const result = await sdk.bookings.getBookings({}); - // Handle the result console.log(result); } @@ -43,23 +40,22 @@ The standalone function version of this method: ```typescript import { SDKCore } from "sdk/core.js"; -import { usersGetUsers } from "sdk/funcs/usersGetUsers.js"; +import { bookingsGetBookings } from "sdk/funcs/bookingsGetBookings.js"; // Use `SDKCore` for best tree-shaking performance. // You can create one instance of it to use across an application. -const sdk = new SDKCore(); +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const res = await usersGetUsers(sdk); - - if (!res.ok) { - throw res.error; + const res = await bookingsGetBookings(sdk, {}); + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("bookingsGetBookings failed:", res.error); } - - const { value: result } = res; - - // Handle the result - console.log(result); } run(); @@ -69,39 +65,45 @@ run(); | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.GetBookingsRequest](../../models/operations/getbookingsrequest.md) | :heavy_check_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response -**Promise\<[components.User[]](../../models/.md)\>** +**Promise\<[operations.GetBookingsResponseBody](../../models/operations/getbookingsresponsebody.md)\>** ### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| errors.ErrorResponse | 500 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| -------------------------------------- | -------------------------------------- | -------------------------------------- | +| errors.GetBookingsResponseBody | 401 | application/problem+json | +| errors.GetBookingsBookingsResponseBody | 500 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | -## postUsers +## createBooking -Add user to the database +A booking is a temporary hold on a trip. It is not confirmed until payment is processed. ### Example Usage + ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.postUsers({ - name: "Alice", - age: 20, + const result = await sdk.bookings.createBooking({ + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, }); - // Handle the result console.log(result); } @@ -114,26 +116,27 @@ The standalone function version of this method: ```typescript import { SDKCore } from "sdk/core.js"; -import { usersPostUsers } from "sdk/funcs/usersPostUsers.js"; +import { bookingsCreateBooking } from "sdk/funcs/bookingsCreateBooking.js"; // Use `SDKCore` for best tree-shaking performance. // You can create one instance of it to use across an application. -const sdk = new SDKCore(); +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const res = await usersPostUsers(sdk, { - name: "Alice", - age: 20, + const res = await bookingsCreateBooking(sdk, { + tripId: "ea399ba1-6d95-433f-92d1-83f67b775594", + passengerName: "John Doe", + hasBicycle: true, + hasDog: false, }); - - if (!res.ok) { - throw res.error; + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("bookingsCreateBooking failed:", res.error); } - - const { value: result } = res; - - // Handle the result - console.log(result); } run(); @@ -143,39 +146,42 @@ run(); | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `request` | [operations.PostUsersRequestBody](../../models/operations/postusersrequestbody.md) | :heavy_check_mark: | The request object to use for the request. | +| `request` | [operations.CreateBookingBookingsRequestRequestBody](../../models/operations/createbookingbookingsrequestrequestbody.md) | :heavy_check_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response -**Promise\<[components.Id](../../models/components/id.md)\>** +**Promise\<[operations.CreateBookingResponseBody](../../models/operations/createbookingresponsebody.md)\>** ### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| errors.ErrorResponse | 500 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | +| errors.CreateBookingResponseBody | 404 | application/problem+json | +| errors.CreateBookingBookingsResponseBody | 409 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | -## getUsersById +## getBooking -Get user by id from the database +Returns the details of a specific booking. ### Example Usage + ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.getUsersById({ - id: "1", + const result = await sdk.bookings.getBooking({ + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", }); - // Handle the result console.log(result); } @@ -188,25 +194,24 @@ The standalone function version of this method: ```typescript import { SDKCore } from "sdk/core.js"; -import { usersGetUsersById } from "sdk/funcs/usersGetUsersById.js"; +import { bookingsGetBooking } from "sdk/funcs/bookingsGetBooking.js"; // Use `SDKCore` for best tree-shaking performance. // You can create one instance of it to use across an application. -const sdk = new SDKCore(); +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const res = await usersGetUsersById(sdk, { - id: "1", + const res = await bookingsGetBooking(sdk, { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", }); - - if (!res.ok) { - throw res.error; + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("bookingsGetBooking failed:", res.error); } - - const { value: result } = res; - - // Handle the result - console.log(result); } run(); @@ -216,116 +221,42 @@ run(); | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `request` | [operations.GetUsersByIdRequest](../../models/operations/getusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `request` | [operations.GetBookingRequest](../../models/operations/getbookingrequest.md) | :heavy_check_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response -**Promise\<[components.User](../../models/components/user.md)\>** +**Promise\<[operations.GetBookingResponseBody](../../models/operations/getbookingresponsebody.md)\>** ### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| errors.ErrorResponse | 404 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | +| Error Type | Status Code | Content Type | +| ----------------------------- | ----------------------------- | ----------------------------- | +| errors.GetBookingResponseBody | 404 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | -## deleteUsersById +## deleteBooking -Delete user by id from the database +Deletes a booking, cancelling the hold on the trip. ### Example Usage + ```typescript import { SDK } from "sdk"; -const sdk = new SDK(); +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const result = await sdk.users.deleteUsersById({ - id: "1", + await sdk.bookings.deleteBooking({ + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", }); - // Handle the result - console.log(result); -} - -run(); -``` - -### Standalone function - -The standalone function version of this method: - -```typescript -import { SDKCore } from "sdk/core.js"; -import { usersDeleteUsersById } from "sdk/funcs/usersDeleteUsersById.js"; - -// Use `SDKCore` for best tree-shaking performance. -// You can create one instance of it to use across an application. -const sdk = new SDKCore(); - -async function run() { - const res = await usersDeleteUsersById(sdk, { - id: "1", - }); - - if (!res.ok) { - throw res.error; - } - - const { value: result } = res; - - // Handle the result - console.log(result); -} - -run(); -``` - -### Parameters - -| Parameter | Type | Required | Description | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `request` | [operations.DeleteUsersByIdRequest](../../models/operations/deleteusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | -| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | -| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | -| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | - -### Response - -**Promise\<[components.SuccessResponse](../../models/components/successresponse.md)\>** - -### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| errors.ErrorResponse | 422 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | - -## patchUsersById - -Update user by id from the database - -### Example Usage - -```typescript -import { SDK } from "sdk"; - -const sdk = new SDK(); - -async function run() { - const result = await sdk.users.patchUsersById({ - id: "1", - requestBody: { - age: 21, - }, - }); - - // Handle the result - console.log(result); } run(); @@ -337,28 +268,24 @@ The standalone function version of this method: ```typescript import { SDKCore } from "sdk/core.js"; -import { usersPatchUsersById } from "sdk/funcs/usersPatchUsersById.js"; +import { bookingsDeleteBooking } from "sdk/funcs/bookingsDeleteBooking.js"; // Use `SDKCore` for best tree-shaking performance. // You can create one instance of it to use across an application. -const sdk = new SDKCore(); +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); async function run() { - const res = await usersPatchUsersById(sdk, { - id: "1", - requestBody: { - age: 21, - }, + const res = await bookingsDeleteBooking(sdk, { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", }); - - if (!res.ok) { - throw res.error; + if (res.ok) { + const { value: result } = res; + + } else { + console.log("bookingsDeleteBooking failed:", res.error); } - - const { value: result } = res; - - // Handle the result - console.log(result); } run(); @@ -368,18 +295,18 @@ run(); | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `request` | [operations.PatchUsersByIdRequest](../../models/operations/patchusersbyidrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `request` | [operations.DeleteBookingRequest](../../models/operations/deletebookingrequest.md) | :heavy_check_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response -**Promise\<[components.SuccessResponse](../../models/components/successresponse.md)\>** +**Promise\** ### Errors -| Error Type | Status Code | Content Type | -| -------------------- | -------------------- | -------------------- | -| errors.ErrorResponse | 422 | application/json | -| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file +| Error Type | Status Code | Content Type | +| -------------------------------- | -------------------------------- | -------------------------------- | +| errors.DeleteBookingResponseBody | 404 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/payments/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/payments/README.md new file mode 100644 index 00000000..1769d92b --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/sdks/payments/README.md @@ -0,0 +1,111 @@ +# Payments + +## Overview + +Pay for bookings using a card or bank account, and view payment status and history. + +### Available Operations + +* [createBookingPayment](#createbookingpayment) - Pay for a booking + +## createBookingPayment + +A payment attempt confirms the booking and enables ticket retrieval. + +### Example Usage + + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const result = await sdk.payments.createBookingPayment({ + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", + requestBody: { + amount: 49.99, + currency: "bgn", + promoCode: "SUMMER20", + source: { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + }, + }, + }); + + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { paymentsCreateBookingPayment } from "sdk/funcs/paymentsCreateBookingPayment.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const res = await paymentsCreateBookingPayment(sdk, { + bookingId: "1725ff48-ab45-4bb5-9d02-88745177dedb", + requestBody: { + amount: 49.99, + currency: "bgn", + promoCode: "SUMMER20", + source: { + object: "card", + name: "J. Doe", + number: "4242424242424242", + cvc: "123", + expMonth: 12, + expYear: 2025, + addressCountry: "gb", + }, + }, + }); + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("paymentsCreateBookingPayment failed:", res.error); + } +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.CreateBookingPaymentRequest](../../models/operations/createbookingpaymentrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[operations.CreateBookingPaymentResponseBody](../../models/operations/createbookingpaymentresponsebody.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| --------------------------------------- | --------------------------------------- | --------------------------------------- | +| errors.CreateBookingPaymentResponseBody | 404 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md deleted file mode 100644 index 7480e820..00000000 --- a/frameworks-elysia/sdk-typescript/docs/sdks/sdk/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# SDK - -## Overview - -Users app documentation: Development documentation - -Find out more about the Users API - - -### Available Operations diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/stations/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/stations/README.md new file mode 100644 index 00000000..16d4c5f2 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/sdks/stations/README.md @@ -0,0 +1,87 @@ +# Stations + +## Overview + +Find and filter train stations across Europe, including their location and local timezone. + +### Available Operations + +* [getStations](#getstations) - Get a list of train stations + +## getStations + +Returns a paginated and searchable list of all train stations. + +### Example Usage + + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { stationsGetStations } from "sdk/funcs/stationsGetStations.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const res = await stationsGetStations(sdk, { + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("stationsGetStations failed:", res.error); + } +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.GetStationsRequest](../../models/operations/getstationsrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[operations.GetStationsResponseBody](../../models/operations/getstationsresponsebody.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| ------------------------------ | ------------------------------ | ------------------------------ | +| errors.GetStationsResponseBody | 400 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/docs/sdks/trips/README.md b/frameworks-elysia/sdk-typescript/docs/sdks/trips/README.md new file mode 100644 index 00000000..e2ba3580 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/docs/sdks/trips/README.md @@ -0,0 +1,87 @@ +# Trips + +## Overview + +Timetables and routes for train trips between stations, including pricing and availability. + +### Available Operations + +* [getTrips](#gettrips) - Get available train trips + +## getTrips + +Returns a list of available train trips between the specified origin and destination stations on the given date. + +### Example Usage + + +```typescript +import { SDK } from "sdk"; + +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const result = await sdk.trips.getTrips({ + origin: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + destination: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + date: new Date("2024-02-01T09:00:00Z"), + }); + + console.log(result); +} + +run(); +``` + +### Standalone function + +The standalone function version of this method: + +```typescript +import { SDKCore } from "sdk/core.js"; +import { tripsGetTrips } from "sdk/funcs/tripsGetTrips.js"; + +// Use `SDKCore` for best tree-shaking performance. +// You can create one instance of it to use across an application. +const sdk = new SDKCore({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function run() { + const res = await tripsGetTrips(sdk, { + origin: "efdbb9d1-02c2-4bc3-afb7-6788d8782b1e", + destination: "b2e783e1-c824-4d63-b37a-d8d698862f1d", + date: new Date("2024-02-01T09:00:00Z"), + }); + if (res.ok) { + const { value: result } = res; + console.log(result); + } else { + console.log("tripsGetTrips failed:", res.error); + } +} + +run(); +``` + +### Parameters + +| Parameter | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `request` | [operations.GetTripsRequest](../../models/operations/gettripsrequest.md) | :heavy_check_mark: | The request object to use for the request. | +| `options` | RequestOptions | :heavy_minus_sign: | Used to set various options for making HTTP requests. | +| `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy_minus_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | +| `options.retries` | [RetryConfig](../../lib/utils/retryconfig.md) | :heavy_minus_sign: | Enables retrying HTTP requests under certain failure conditions. | + +### Response + +**Promise\<[operations.GetTripsResponseBody](../../models/operations/gettripsresponsebody.md)\>** + +### Errors + +| Error Type | Status Code | Content Type | +| --------------------------- | --------------------------- | --------------------------- | +| errors.GetTripsResponseBody | 400 | application/problem+json | +| errors.APIError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/eslint.config.mjs b/frameworks-elysia/sdk-typescript/eslint.config.mjs new file mode 100644 index 00000000..67bccfec --- /dev/null +++ b/frameworks-elysia/sdk-typescript/eslint.config.mjs @@ -0,0 +1,22 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import tseslint from "typescript-eslint"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { files: ["**/*.{js,mjs,cjs,ts}"] }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + { + rules: { + "no-constant-condition": "off", + "no-useless-escape": "off", + // Handled by typescript compiler + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-object-type": "off", + "@typescript-eslint/no-namespace": "off", + }, + }, +]; diff --git a/frameworks-elysia/sdk-typescript/examples/.env.template b/frameworks-elysia/sdk-typescript/examples/.env.template new file mode 100644 index 00000000..63defb75 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/examples/.env.template @@ -0,0 +1,14 @@ +# sdk SDK Environment Variables +# Copy this file to .env and fill in your actual values +# DO NOT commit the .env file to version control + +# Security Configuration +# The SDK supports loading security credentials from environment variables +# with the prefix: SDK_ +# +# Security environment variables: +SDK_O_AUTH2=your_oauth2_token_here + +# Debug Configuration +# Enable HTTP request/response logging for debugging +SDK_DEBUG=true diff --git a/frameworks-elysia/sdk-typescript/examples/README.md b/frameworks-elysia/sdk-typescript/examples/README.md new file mode 100644 index 00000000..fe153610 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/examples/README.md @@ -0,0 +1,31 @@ +# sdk Examples + +This directory contains example scripts demonstrating how to use the sdk SDK. + +## Prerequisites + +- Node.js (v18 or higher) +- npm + +## Setup + +1. Copy `.env.template` to `.env`: + ```bash + cp .env.template .env + ``` + +2. Edit `.env` and add your actual credentials (API keys, tokens, etc.) + +## Running the Examples + +To run an example file from the examples directory: + +```bash +npm run build && npx tsx example.ts +``` + +## Creating new examples + +Duplicate an existing example file, they won't be overwritten by the generation process. + + diff --git a/frameworks-elysia/sdk-typescript/examples/package.json b/frameworks-elysia/sdk-typescript/examples/package.json new file mode 100644 index 00000000..30f913da --- /dev/null +++ b/frameworks-elysia/sdk-typescript/examples/package.json @@ -0,0 +1,18 @@ +{ + "name": "sdk-examples", + "version": "1.0.0", + "private": true, + "scripts": { + "build:parent": "cd .. && npm i && npm run build && cd -", + "build:examples": "npm i", + "build": "npm run build:parent && npm run build:examples" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "dotenv": "^16.4.5", + "tsx": "^4.19.2" + }, + "dependencies": { + "sdk": "file:.." + } +} \ No newline at end of file diff --git a/frameworks-elysia/sdk-typescript/examples/stationsGetStations.example.ts b/frameworks-elysia/sdk-typescript/examples/stationsGetStations.example.ts new file mode 100644 index 00000000..8510dd2a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/examples/stationsGetStations.example.ts @@ -0,0 +1,30 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import dotenv from "dotenv"; +dotenv.config(); +/** + * Example usage of the sdk SDK + * + * To run this example from the examples directory: + * npm run build && npx tsx stationsGetStations.example.ts + */ + +import { SDK } from "sdk"; + +const sdk = new SDK({ + oAuth2: process.env["SDK_O_AUTH2"] ?? "", +}); + +async function main() { + const result = await sdk.stations.getStations({ + coordinates: "52.5200,13.4050", + search: "Milano Centrale", + country: "DE", + }); + + console.log(result); +} + +main().catch(console.error); diff --git a/frameworks-elysia/sdk-typescript/jsr.json b/frameworks-elysia/sdk-typescript/jsr.json index f347e0ff..288e3f4b 100644 --- a/frameworks-elysia/sdk-typescript/jsr.json +++ b/frameworks-elysia/sdk-typescript/jsr.json @@ -2,7 +2,7 @@ { "name": "sdk", - "version": "0.0.1", + "version": "0.1.0", "exports": { ".": "./src/index.ts", "./models/errors": "./src/models/errors/index.ts", diff --git a/frameworks-elysia/sdk-typescript/package.json b/frameworks-elysia/sdk-typescript/package.json index adda5bda..a0811ff6 100644 --- a/frameworks-elysia/sdk-typescript/package.json +++ b/frameworks-elysia/sdk-typescript/package.json @@ -1,29 +1,25 @@ { "name": "sdk", - "version": "0.0.1", + "version": "0.1.0", "author": "Speakeasy", "main": "./index.js", "sideEffects": false, "scripts": { - "lint": "eslint --max-warnings=0 src", + "lint": "eslint --cache --max-warnings=0 src", "build": "tsc", "prepublishOnly": "npm run build" }, "peerDependencies": { - "react": "^18 || ^19", - "react-dom": "^18 || ^19", - "zod": ">= 3" + }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^7.7.1", - "@typescript-eslint/parser": "^7.7.1", - "eslint": "^8.57.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "typescript": "^5.4.5", - "zod": "^3.23.4" + "@eslint/js": "^9.26.0", + "eslint": "^9.26.0", + "globals": "^15.14.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.26.0" }, "dependencies": { - + "zod": "^3.25.0 || ^4.0.0" } } diff --git a/frameworks-elysia/sdk-typescript/src/funcs/bookingsCreateBooking.ts b/frameworks-elysia/sdk-typescript/src/funcs/bookingsCreateBooking.ts new file mode 100644 index 00000000..36e23947 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/bookingsCreateBooking.ts @@ -0,0 +1,192 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeJSON } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Create a booking + * + * @remarks + * A booking is a temporary hold on a trip. It is not confirmed until payment is processed. + */ +export function bookingsCreateBooking( + client: SDKCore, + request: operations.CreateBookingBookingsRequestRequestBody, + options?: RequestOptions, +): APIPromise< + Result< + operations.CreateBookingResponseBody, + | errors.CreateBookingResponseBody + | errors.CreateBookingBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.CreateBookingBookingsRequestRequestBody, + options?: RequestOptions, +): Promise< + [ + Result< + operations.CreateBookingResponseBody, + | errors.CreateBookingResponseBody + | errors.CreateBookingBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => + operations.CreateBookingBookingsRequestRequestBody$outboundSchema.parse( + value, + ), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = encodeJSON("body", payload, { explode: true }); + + const path = pathToFunc("/bookings/")(); + + const headers = new Headers(compactMap({ + "Content-Type": "application/json", + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "create-booking", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 300, + maxInterval: 40000, + exponent: 1.2, + maxElapsedTime: 3000000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "POST", + baseURL: options?.serverURL, + path: path, + headers: headers, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.CreateBookingResponseBody, + | errors.CreateBookingResponseBody + | errors.CreateBookingBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(201, operations.CreateBookingResponseBody$inboundSchema), + M.jsonErr(404, errors.CreateBookingResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.jsonErr(409, errors.CreateBookingBookingsResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/bookingsDeleteBooking.ts b/frameworks-elysia/sdk-typescript/src/funcs/bookingsDeleteBooking.ts new file mode 100644 index 00000000..83819914 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/bookingsDeleteBooking.ts @@ -0,0 +1,189 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKCore } from "../core.js"; +import { encodeSimple } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Delete a booking + * + * @remarks + * Deletes a booking, cancelling the hold on the trip. + */ +export function bookingsDeleteBooking( + client: SDKCore, + request: operations.DeleteBookingRequest, + options?: RequestOptions, +): APIPromise< + Result< + void, + | errors.DeleteBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.DeleteBookingRequest, + options?: RequestOptions, +): Promise< + [ + Result< + void, + | errors.DeleteBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => operations.DeleteBookingRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = null; + + const pathParams = { + bookingId: encodeSimple("bookingId", payload.bookingId, { + explode: false, + charEncoding: "percent", + }), + }; + const path = pathToFunc("/bookings/{bookingId}")(pathParams); + + const headers = new Headers(compactMap({ + Accept: "application/problem+json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "delete-booking", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "DELETE", + baseURL: options?.serverURL, + path: path, + headers: headers, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + void, + | errors.DeleteBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.nil(204, z.void()), + M.jsonErr(404, errors.DeleteBookingResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBooking.ts b/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBooking.ts new file mode 100644 index 00000000..ba7e017f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBooking.ts @@ -0,0 +1,188 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeSimple } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Get a booking + * + * @remarks + * Returns the details of a specific booking. + */ +export function bookingsGetBooking( + client: SDKCore, + request: operations.GetBookingRequest, + options?: RequestOptions, +): APIPromise< + Result< + operations.GetBookingResponseBody, + | errors.GetBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.GetBookingRequest, + options?: RequestOptions, +): Promise< + [ + Result< + operations.GetBookingResponseBody, + | errors.GetBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => operations.GetBookingRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = null; + + const pathParams = { + bookingId: encodeSimple("bookingId", payload.bookingId, { + explode: false, + charEncoding: "percent", + }), + }; + const path = pathToFunc("/bookings/{bookingId}")(pathParams); + + const headers = new Headers(compactMap({ + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "get-booking", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "GET", + baseURL: options?.serverURL, + path: path, + headers: headers, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.GetBookingResponseBody, + | errors.GetBookingResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(200, operations.GetBookingResponseBody$inboundSchema), + M.jsonErr(404, errors.GetBookingResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBookings.ts b/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBookings.ts new file mode 100644 index 00000000..35af58c3 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/bookingsGetBookings.ts @@ -0,0 +1,194 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeFormQuery } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * List existing bookings + * + * @remarks + * Returns a list of all trip bookings by the authenticated user. + */ +export function bookingsGetBookings( + client: SDKCore, + request: operations.GetBookingsRequest, + options?: RequestOptions, +): APIPromise< + Result< + operations.GetBookingsResponseBody, + | errors.GetBookingsResponseBody + | errors.GetBookingsBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.GetBookingsRequest, + options?: RequestOptions, +): Promise< + [ + Result< + operations.GetBookingsResponseBody, + | errors.GetBookingsResponseBody + | errors.GetBookingsBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => operations.GetBookingsRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = null; + + const path = pathToFunc("/bookings/")(); + + const query = encodeFormQuery({ + "limit": payload.limit, + "page": payload.page, + }); + + const headers = new Headers(compactMap({ + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "get-bookings", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "GET", + baseURL: options?.serverURL, + path: path, + headers: headers, + query: query, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.GetBookingsResponseBody, + | errors.GetBookingsResponseBody + | errors.GetBookingsBookingsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(200, operations.GetBookingsResponseBody$inboundSchema), + M.jsonErr(401, errors.GetBookingsResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.jsonErr(500, errors.GetBookingsBookingsResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/paymentsCreateBookingPayment.ts b/frameworks-elysia/sdk-typescript/src/funcs/paymentsCreateBookingPayment.ts new file mode 100644 index 00000000..56b62fc6 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/paymentsCreateBookingPayment.ts @@ -0,0 +1,190 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeJSON, encodeSimple } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Pay for a booking + * + * @remarks + * A payment attempt confirms the booking and enables ticket retrieval. + */ +export function paymentsCreateBookingPayment( + client: SDKCore, + request: operations.CreateBookingPaymentRequest, + options?: RequestOptions, +): APIPromise< + Result< + operations.CreateBookingPaymentResponseBody, + | errors.CreateBookingPaymentResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.CreateBookingPaymentRequest, + options?: RequestOptions, +): Promise< + [ + Result< + operations.CreateBookingPaymentResponseBody, + | errors.CreateBookingPaymentResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => + operations.CreateBookingPaymentRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = encodeJSON("body", payload.RequestBody, { explode: true }); + + const pathParams = { + bookingId: encodeSimple("bookingId", payload.bookingId, { + explode: false, + charEncoding: "percent", + }), + }; + const path = pathToFunc("/bookings/{bookingId}/payment")(pathParams); + + const headers = new Headers(compactMap({ + "Content-Type": "application/json", + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "create-booking-payment", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "POST", + baseURL: options?.serverURL, + path: path, + headers: headers, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.CreateBookingPaymentResponseBody, + | errors.CreateBookingPaymentResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(200, operations.CreateBookingPaymentResponseBody$inboundSchema), + M.jsonErr(404, errors.CreateBookingPaymentResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/stationsGetStations.ts b/frameworks-elysia/sdk-typescript/src/funcs/stationsGetStations.ts new file mode 100644 index 00000000..21ac45d8 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/stationsGetStations.ts @@ -0,0 +1,191 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeFormQuery } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Get a list of train stations + * + * @remarks + * Returns a paginated and searchable list of all train stations. + */ +export function stationsGetStations( + client: SDKCore, + request: operations.GetStationsRequest, + options?: RequestOptions, +): APIPromise< + Result< + operations.GetStationsResponseBody, + | errors.GetStationsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.GetStationsRequest, + options?: RequestOptions, +): Promise< + [ + Result< + operations.GetStationsResponseBody, + | errors.GetStationsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => operations.GetStationsRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = null; + + const path = pathToFunc("/stations/")(); + + const query = encodeFormQuery({ + "coordinates": payload.coordinates, + "country": payload.country, + "limit": payload.limit, + "page": payload.page, + "search": payload.search, + }); + + const headers = new Headers(compactMap({ + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "get-stations", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "GET", + baseURL: options?.serverURL, + path: path, + headers: headers, + query: query, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.GetStationsResponseBody, + | errors.GetStationsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(200, operations.GetStationsResponseBody$inboundSchema), + M.jsonErr(400, errors.GetStationsResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/tripsGetTrips.ts b/frameworks-elysia/sdk-typescript/src/funcs/tripsGetTrips.ts new file mode 100644 index 00000000..e31946ea --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/funcs/tripsGetTrips.ts @@ -0,0 +1,193 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { SDKCore } from "../core.js"; +import { encodeFormQuery } from "../lib/encodings.js"; +import { matchStatusCode } from "../lib/http.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { APICall, APIPromise } from "../types/async.js"; +import { Result } from "../types/fp.js"; + +/** + * Get available train trips + * + * @remarks + * Returns a list of available train trips between the specified origin and destination stations on the given date. + */ +export function tripsGetTrips( + client: SDKCore, + request: operations.GetTripsRequest, + options?: RequestOptions, +): APIPromise< + Result< + operations.GetTripsResponseBody, + | errors.GetTripsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + > +> { + return new APIPromise($do( + client, + request, + options, + )); +} + +async function $do( + client: SDKCore, + request: operations.GetTripsRequest, + options?: RequestOptions, +): Promise< + [ + Result< + operations.GetTripsResponseBody, + | errors.GetTripsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >, + APICall, + ] +> { + const parsed = safeParse( + request, + (value) => operations.GetTripsRequest$outboundSchema.parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return [parsed, { status: "invalid" }]; + } + const payload = parsed.value; + const body = null; + + const path = pathToFunc("/trips/")(); + + const query = encodeFormQuery({ + "bicycles": payload.bicycles, + "date": payload.date, + "destination": payload.destination, + "dogs": payload.dogs, + "limit": payload.limit, + "origin": payload.origin, + "page": payload.page, + }); + + const headers = new Headers(compactMap({ + Accept: "application/json", + })); + + const secConfig = await extractSecurity(client._options.oAuth2); + const securityInput = secConfig == null ? {} : { oAuth2: secConfig }; + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + options: client._options, + baseURL: options?.serverURL ?? client._baseURL ?? "", + operationID: "get-trips", + oAuth2Scopes: null, + + resolvedSecurity: requestSecurity, + + securitySource: client._options.oAuth2, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 500, + maxInterval: 60000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "GET", + baseURL: options?.serverURL, + path: path, + headers: headers, + query: query, + body: body, + userAgent: client._options.userAgent, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return [requestRes, { status: "invalid" }]; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + isErrorStatusCode: (statusCode: number) => + matchStatusCode({ status: statusCode } as Response, ["4XX", "5XX"]), + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return [doResult, { status: "request-error", request: req }]; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.GetTripsResponseBody, + | errors.GetTripsResponseBody + | SDKError + | ResponseValidationError + | ConnectionError + | RequestAbortedError + | RequestTimeoutError + | InvalidRequestError + | UnexpectedClientError + | SDKValidationError + >( + M.json(200, operations.GetTripsResponseBody$inboundSchema), + M.jsonErr(400, errors.GetTripsResponseBody$inboundSchema, { + ctype: "application/problem+json", + }), + M.fail("4XX"), + M.fail("5XX"), + )(response, req, { extraFields: responseFields }); + if (!result.ok) { + return [result, { status: "complete", request: req, response }]; + } + + return [result, { status: "complete", request: req, response }]; +} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts deleted file mode 100644 index 031eee76..00000000 --- a/frameworks-elysia/sdk-typescript/src/funcs/usersDeleteUsersById.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import { SDKCore } from "../core.js"; -import { encodeSimple } from "../lib/encodings.js"; -import * as M from "../lib/matchers.js"; -import { safeParse } from "../lib/schemas.js"; -import { RequestOptions } from "../lib/sdks.js"; -import { pathToFunc } from "../lib/url.js"; -import * as components from "../models/components/index.js"; -import { APIError } from "../models/errors/apierror.js"; -import { - ConnectionError, - InvalidRequestError, - RequestAbortedError, - RequestTimeoutError, - UnexpectedClientError, -} from "../models/errors/httpclienterrors.js"; -import * as errors from "../models/errors/index.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import * as operations from "../models/operations/index.js"; -import { Result } from "../types/fp.js"; - -/** - * Delete user - * - * @remarks - * Delete user by id from the database - */ -export async function usersDeleteUsersById( - client: SDKCore, - request: operations.DeleteUsersByIdRequest, - options?: RequestOptions, -): Promise< - Result< - components.SuccessResponse, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - > -> { - const parsed = safeParse( - request, - (value) => operations.DeleteUsersByIdRequest$outboundSchema.parse(value), - "Input validation failed", - ); - if (!parsed.ok) { - return parsed; - } - const payload = parsed.value; - const body = null; - - const pathParams = { - id: encodeSimple("id", payload.id, { - explode: false, - charEncoding: "percent", - }), - }; - - const path = pathToFunc("/users/{id}")(pathParams); - - const headers = new Headers({ - Accept: "application/json", - }); - - const context = { - operationID: "deleteUsersById", - oAuth2Scopes: [], - - resolvedSecurity: null, - - securitySource: null, - retryConfig: options?.retries - || client._options.retryConfig - || { - strategy: "backoff", - backoff: { - initialInterval: 500, - maxInterval: 60000, - exponent: 1.5, - maxElapsedTime: 3600000, - }, - retryConnectionErrors: true, - } - || { strategy: "none" }, - retryCodes: options?.retryCodes || ["5XX"], - }; - - const requestRes = client._createRequest(context, { - method: "DELETE", - path: path, - headers: headers, - body: body, - timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, - }, options); - if (!requestRes.ok) { - return requestRes; - } - const req = requestRes.value; - - const doResult = await client._do(req, { - context, - errorCodes: ["422", "4XX", "5XX"], - retryConfig: context.retryConfig, - retryCodes: context.retryCodes, - }); - if (!doResult.ok) { - return doResult; - } - const response = doResult.value; - - const responseFields = { - HttpMeta: { Response: response, Request: req }, - }; - - const [result] = await M.match< - components.SuccessResponse, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - >( - M.json(200, components.SuccessResponse$inboundSchema), - M.jsonErr(422, errors.ErrorResponse$inboundSchema), - M.fail(["4XX", "5XX"]), - )(response, { extraFields: responseFields }); - if (!result.ok) { - return result; - } - - return result; -} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts deleted file mode 100644 index e08f2964..00000000 --- a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsers.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { SDKCore } from "../core.js"; -import * as M from "../lib/matchers.js"; -import { RequestOptions } from "../lib/sdks.js"; -import { pathToFunc } from "../lib/url.js"; -import * as components from "../models/components/index.js"; -import { APIError } from "../models/errors/apierror.js"; -import { - ConnectionError, - InvalidRequestError, - RequestAbortedError, - RequestTimeoutError, - UnexpectedClientError, -} from "../models/errors/httpclienterrors.js"; -import * as errors from "../models/errors/index.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import { Result } from "../types/fp.js"; - -/** - * Get all users - * - * @remarks - * Get all users from the database - */ -export async function usersGetUsers( - client: SDKCore, - options?: RequestOptions, -): Promise< - Result< - Array, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - > -> { - const path = pathToFunc("/users/")(); - - const headers = new Headers({ - Accept: "application/json", - }); - - const context = { - operationID: "getUsers", - oAuth2Scopes: [], - - resolvedSecurity: null, - - securitySource: null, - retryConfig: options?.retries - || client._options.retryConfig - || { - strategy: "backoff", - backoff: { - initialInterval: 500, - maxInterval: 60000, - exponent: 1.5, - maxElapsedTime: 3600000, - }, - retryConnectionErrors: true, - } - || { strategy: "none" }, - retryCodes: options?.retryCodes || ["5XX"], - }; - - const requestRes = client._createRequest(context, { - method: "GET", - path: path, - headers: headers, - timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, - }, options); - if (!requestRes.ok) { - return requestRes; - } - const req = requestRes.value; - - const doResult = await client._do(req, { - context, - errorCodes: ["4XX", "500", "5XX"], - retryConfig: context.retryConfig, - retryCodes: context.retryCodes, - }); - if (!doResult.ok) { - return doResult; - } - const response = doResult.value; - - const responseFields = { - HttpMeta: { Response: response, Request: req }, - }; - - const [result] = await M.match< - Array, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - >( - M.json(200, z.array(components.User$inboundSchema)), - M.jsonErr(500, errors.ErrorResponse$inboundSchema), - M.fail(["4XX", "5XX"]), - )(response, { extraFields: responseFields }); - if (!result.ok) { - return result; - } - - return result; -} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts deleted file mode 100644 index 500e7997..00000000 --- a/frameworks-elysia/sdk-typescript/src/funcs/usersGetUsersById.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import { SDKCore } from "../core.js"; -import { encodeSimple } from "../lib/encodings.js"; -import * as M from "../lib/matchers.js"; -import { safeParse } from "../lib/schemas.js"; -import { RequestOptions } from "../lib/sdks.js"; -import { pathToFunc } from "../lib/url.js"; -import * as components from "../models/components/index.js"; -import { APIError } from "../models/errors/apierror.js"; -import { - ConnectionError, - InvalidRequestError, - RequestAbortedError, - RequestTimeoutError, - UnexpectedClientError, -} from "../models/errors/httpclienterrors.js"; -import * as errors from "../models/errors/index.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import * as operations from "../models/operations/index.js"; -import { Result } from "../types/fp.js"; - -/** - * Get user - * - * @remarks - * Get user by id from the database - */ -export async function usersGetUsersById( - client: SDKCore, - request: operations.GetUsersByIdRequest, - options?: RequestOptions, -): Promise< - Result< - components.User, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - > -> { - const parsed = safeParse( - request, - (value) => operations.GetUsersByIdRequest$outboundSchema.parse(value), - "Input validation failed", - ); - if (!parsed.ok) { - return parsed; - } - const payload = parsed.value; - const body = null; - - const pathParams = { - id: encodeSimple("id", payload.id, { - explode: false, - charEncoding: "percent", - }), - }; - - const path = pathToFunc("/users/{id}")(pathParams); - - const headers = new Headers({ - Accept: "application/json", - }); - - const context = { - operationID: "getUsersById", - oAuth2Scopes: [], - - resolvedSecurity: null, - - securitySource: null, - retryConfig: options?.retries - || client._options.retryConfig - || { - strategy: "backoff", - backoff: { - initialInterval: 500, - maxInterval: 60000, - exponent: 1.5, - maxElapsedTime: 3600000, - }, - retryConnectionErrors: true, - } - || { strategy: "none" }, - retryCodes: options?.retryCodes || ["5XX"], - }; - - const requestRes = client._createRequest(context, { - method: "GET", - path: path, - headers: headers, - body: body, - timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, - }, options); - if (!requestRes.ok) { - return requestRes; - } - const req = requestRes.value; - - const doResult = await client._do(req, { - context, - errorCodes: ["404", "4XX", "5XX"], - retryConfig: context.retryConfig, - retryCodes: context.retryCodes, - }); - if (!doResult.ok) { - return doResult; - } - const response = doResult.value; - - const responseFields = { - HttpMeta: { Response: response, Request: req }, - }; - - const [result] = await M.match< - components.User, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - >( - M.json(200, components.User$inboundSchema), - M.jsonErr(404, errors.ErrorResponse$inboundSchema), - M.fail(["4XX", "5XX"]), - )(response, { extraFields: responseFields }); - if (!result.ok) { - return result; - } - - return result; -} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts deleted file mode 100644 index 9e83f667..00000000 --- a/frameworks-elysia/sdk-typescript/src/funcs/usersPatchUsersById.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import { SDKCore } from "../core.js"; -import { encodeJSON, encodeSimple } from "../lib/encodings.js"; -import * as M from "../lib/matchers.js"; -import { safeParse } from "../lib/schemas.js"; -import { RequestOptions } from "../lib/sdks.js"; -import { pathToFunc } from "../lib/url.js"; -import * as components from "../models/components/index.js"; -import { APIError } from "../models/errors/apierror.js"; -import { - ConnectionError, - InvalidRequestError, - RequestAbortedError, - RequestTimeoutError, - UnexpectedClientError, -} from "../models/errors/httpclienterrors.js"; -import * as errors from "../models/errors/index.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import * as operations from "../models/operations/index.js"; -import { Result } from "../types/fp.js"; - -/** - * Update user - * - * @remarks - * Update user by id from the database - */ -export async function usersPatchUsersById( - client: SDKCore, - request: operations.PatchUsersByIdRequest, - options?: RequestOptions, -): Promise< - Result< - components.SuccessResponse, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - > -> { - const parsed = safeParse( - request, - (value) => operations.PatchUsersByIdRequest$outboundSchema.parse(value), - "Input validation failed", - ); - if (!parsed.ok) { - return parsed; - } - const payload = parsed.value; - const body = encodeJSON("body", payload.RequestBody, { explode: true }); - - const pathParams = { - id: encodeSimple("id", payload.id, { - explode: false, - charEncoding: "percent", - }), - }; - - const path = pathToFunc("/users/{id}")(pathParams); - - const headers = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - }); - - const context = { - operationID: "patchUsersById", - oAuth2Scopes: [], - - resolvedSecurity: null, - - securitySource: null, - retryConfig: options?.retries - || client._options.retryConfig - || { - strategy: "backoff", - backoff: { - initialInterval: 500, - maxInterval: 60000, - exponent: 1.5, - maxElapsedTime: 3600000, - }, - retryConnectionErrors: true, - } - || { strategy: "none" }, - retryCodes: options?.retryCodes || ["5XX"], - }; - - const requestRes = client._createRequest(context, { - method: "PATCH", - path: path, - headers: headers, - body: body, - timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, - }, options); - if (!requestRes.ok) { - return requestRes; - } - const req = requestRes.value; - - const doResult = await client._do(req, { - context, - errorCodes: ["422", "4XX", "5XX"], - retryConfig: context.retryConfig, - retryCodes: context.retryCodes, - }); - if (!doResult.ok) { - return doResult; - } - const response = doResult.value; - - const responseFields = { - HttpMeta: { Response: response, Request: req }, - }; - - const [result] = await M.match< - components.SuccessResponse, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - >( - M.json(200, components.SuccessResponse$inboundSchema), - M.jsonErr(422, errors.ErrorResponse$inboundSchema), - M.fail(["4XX", "5XX"]), - )(response, { extraFields: responseFields }); - if (!result.ok) { - return result; - } - - return result; -} diff --git a/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts b/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts deleted file mode 100644 index c04ae84f..00000000 --- a/frameworks-elysia/sdk-typescript/src/funcs/usersPostUsers.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import { SDKCore } from "../core.js"; -import { encodeJSON } from "../lib/encodings.js"; -import * as M from "../lib/matchers.js"; -import { safeParse } from "../lib/schemas.js"; -import { RequestOptions } from "../lib/sdks.js"; -import { pathToFunc } from "../lib/url.js"; -import * as components from "../models/components/index.js"; -import { APIError } from "../models/errors/apierror.js"; -import { - ConnectionError, - InvalidRequestError, - RequestAbortedError, - RequestTimeoutError, - UnexpectedClientError, -} from "../models/errors/httpclienterrors.js"; -import * as errors from "../models/errors/index.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import * as operations from "../models/operations/index.js"; -import { Result } from "../types/fp.js"; - -/** - * Create user - * - * @remarks - * Add user to the database - */ -export async function usersPostUsers( - client: SDKCore, - request: operations.PostUsersRequestBody, - options?: RequestOptions, -): Promise< - Result< - components.Id, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - > -> { - const parsed = safeParse( - request, - (value) => operations.PostUsersRequestBody$outboundSchema.parse(value), - "Input validation failed", - ); - if (!parsed.ok) { - return parsed; - } - const payload = parsed.value; - const body = encodeJSON("body", payload, { explode: true }); - - const path = pathToFunc("/users/")(); - - const headers = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - }); - - const context = { - operationID: "postUsers", - oAuth2Scopes: [], - - resolvedSecurity: null, - - securitySource: null, - retryConfig: options?.retries - || client._options.retryConfig - || { - strategy: "backoff", - backoff: { - initialInterval: 300, - maxInterval: 40000, - exponent: 1.2, - maxElapsedTime: 3000000, - }, - retryConnectionErrors: true, - } - || { strategy: "none" }, - retryCodes: options?.retryCodes || ["5XX"], - }; - - const requestRes = client._createRequest(context, { - method: "POST", - path: path, - headers: headers, - body: body, - timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, - }, options); - if (!requestRes.ok) { - return requestRes; - } - const req = requestRes.value; - - const doResult = await client._do(req, { - context, - errorCodes: ["4XX", "500", "5XX"], - retryConfig: context.retryConfig, - retryCodes: context.retryCodes, - }); - if (!doResult.ok) { - return doResult; - } - const response = doResult.value; - - const responseFields = { - HttpMeta: { Response: response, Request: req }, - }; - - const [result] = await M.match< - components.Id, - | errors.ErrorResponse - | APIError - | SDKValidationError - | UnexpectedClientError - | InvalidRequestError - | RequestAbortedError - | RequestTimeoutError - | ConnectionError - >( - M.json(200, components.Id$inboundSchema), - M.jsonErr(500, errors.ErrorResponse$inboundSchema), - M.fail(["4XX", "5XX"]), - )(response, { extraFields: responseFields }); - if (!result.ok) { - return result; - } - - return result; -} diff --git a/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts b/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts index d1b3396f..fc9b13b2 100644 --- a/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts +++ b/frameworks-elysia/sdk-typescript/src/hooks/hooks.ts @@ -12,13 +12,12 @@ import { BeforeCreateRequestHook, BeforeRequestContext, BeforeRequestHook, + Hook, Hooks, SDKInitHook, SDKInitOptions, } from "./types.js"; -import { initHooks } from "./registration.js"; - export class SDKHooks implements Hooks { sdkInitHooks: SDKInitHook[] = []; beforeCreateRequestHooks: BeforeCreateRequestHook[] = []; @@ -27,7 +26,25 @@ export class SDKHooks implements Hooks { afterErrorHooks: AfterErrorHook[] = []; constructor() { - initHooks(this); + const presetHooks: Array = []; + + for (const hook of presetHooks) { + if ("sdkInit" in hook) { + this.registerSDKInitHook(hook); + } + if ("beforeCreateRequest" in hook) { + this.registerBeforeCreateRequestHook(hook); + } + if ("beforeRequest" in hook) { + this.registerBeforeRequestHook(hook); + } + if ("afterSuccess" in hook) { + this.registerAfterSuccessHook(hook); + } + if ("afterError" in hook) { + this.registerAfterErrorHook(hook); + } + } } registerSDKInitHook(hook: SDKInitHook) { diff --git a/frameworks-elysia/sdk-typescript/src/hooks/oauth2scopes.ts b/frameworks-elysia/sdk-typescript/src/hooks/oauth2scopes.ts new file mode 100644 index 00000000..f9184cb4 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/hooks/oauth2scopes.ts @@ -0,0 +1,19 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/** + * Available scopes for the OAuth2 OAuth 2.0 scheme (authorizationCode flow). + * + * @remarks + * OAuth 2.0 authorization code flow. + */ +export type OAuth2Scope = + /** + * Read access + */ + | "read" + /** + * Write access + */ + | "write"; diff --git a/frameworks-elysia/sdk-typescript/src/hooks/types.ts b/frameworks-elysia/sdk-typescript/src/hooks/types.ts index df5237dc..8bfe4fe8 100644 --- a/frameworks-elysia/sdk-typescript/src/hooks/types.ts +++ b/frameworks-elysia/sdk-typescript/src/hooks/types.ts @@ -2,16 +2,19 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ +import { SDKOptions } from "../lib/config.js"; import { HTTPClient, RequestInput } from "../lib/http.js"; import { RetryConfig } from "../lib/retries.js"; import { SecurityState } from "../lib/security.js"; export type HookContext = { + baseURL: string | URL; operationID: string; - oAuth2Scopes?: string[]; + oAuth2Scopes: string[] | null; securitySource?: any | (() => Promise); retryConfig: RetryConfig; resolvedSecurity: SecurityState | null; + options: SDKOptions; }; export type Awaitable = T | Promise; @@ -100,3 +103,10 @@ export interface Hooks { /** Registers a hook to be used by the SDK for the after error event. */ registerAfterErrorHook(hook: AfterErrorHook): void; } + +export type Hook = + | SDKInitHook + | BeforeCreateRequestHook + | BeforeRequestHook + | AfterSuccessHook + | AfterErrorHook; diff --git a/frameworks-elysia/sdk-typescript/src/index.ts b/frameworks-elysia/sdk-typescript/src/index.ts index 5ddc765e..dbcba164 100644 --- a/frameworks-elysia/sdk-typescript/src/index.ts +++ b/frameworks-elysia/sdk-typescript/src/index.ts @@ -4,4 +4,6 @@ export * from "./lib/config.js"; export * as files from "./lib/files.js"; +export { HTTPClient } from "./lib/http.js"; +export type { Fetcher, HTTPClientOptions } from "./lib/http.js"; export * from "./sdk/sdk.js"; diff --git a/frameworks-elysia/sdk-typescript/src/lib/base64.ts b/frameworks-elysia/sdk-typescript/src/lib/base64.ts index c2d5b389..0aebd8b0 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/base64.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/base64.ts @@ -2,7 +2,7 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import * as z from "zod"; +import * as z from "zod/v3"; export function bytesToBase64(u8arr: Uint8Array): string { return btoa(String.fromCodePoint(...u8arr)); diff --git a/frameworks-elysia/sdk-typescript/src/lib/config.ts b/frameworks-elysia/sdk-typescript/src/lib/config.ts index 8c65a191..1a45685b 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/config.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/config.ts @@ -11,22 +11,32 @@ import { Params, pathToFunc } from "./url.js"; * Contains the list of servers available to the SDK */ export const ServerList = [ + /** + * Production + */ + "https://api.example.com", /** * Development server */ - "http://localhost:3000/", + "http://localhost:3000", ] as const; export type SDKOptions = { + oAuth2?: string | (() => Promise) | undefined; + httpClient?: HTTPClient; /** * Allows overriding the default server used by the SDK */ - serverIdx?: number; + serverIdx?: number | undefined; /** * Allows overriding the default server URL used by the SDK */ - serverURL?: string; + serverURL?: string | undefined; + /** + * Allows overriding the default user agent used by the SDK + */ + userAgent?: string | undefined; /** * Allows overriding the default retry config used by the SDK */ @@ -54,8 +64,8 @@ export function serverURLFromOptions(options: SDKOptions): URL | null { export const SDK_METADATA = { language: "typescript", - openapiDocVersion: "1.0.50", - sdkVersion: "0.0.1", - genVersion: "2.472.1", - userAgent: "speakeasy-sdk/typescript 0.0.1 2.472.1 1.0.50 sdk", + openapiDocVersion: "2.0.0", + sdkVersion: "0.1.0", + genVersion: "2.893.0", + userAgent: "speakeasy-sdk/typescript 0.1.0 2.893.0 2.0.0 sdk", } as const; diff --git a/frameworks-elysia/sdk-typescript/src/lib/encodings.ts b/frameworks-elysia/sdk-typescript/src/lib/encodings.ts index 44fa7284..2791d25b 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/encodings.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/encodings.ts @@ -16,12 +16,16 @@ export function encodeMatrix( key: string, value: unknown, options?: { explode?: boolean; charEncoding?: "percent" | "none" }, -): string { +): string | undefined { let out = ""; const pairs: [string, unknown][] = options?.explode ? explode(key, value) : [[key, value]]; + if (pairs.every(([_, v]) => v == null)) { + return; + } + const encodeString = (v: string) => { return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; }; @@ -29,21 +33,25 @@ export function encodeMatrix( pairs.forEach(([pk, pv]) => { let tmp = ""; - let encValue = ""; + let encValue: string | null | undefined = null; - if (pv === undefined) { + if (pv == null) { return; } else if (Array.isArray(pv)) { - encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join(","); + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`)?.join(","); } else if (isPlainObject(pv)) { - encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + const mapped = mapDefinedEntries(Object.entries(pv), ([k, v]) => { return `,${encodeString(k)},${encodeValue(v)}`; - }).join(""); - encValue = encValue.slice(1); + }); + encValue = mapped?.join("").slice(1); } else { encValue = `${encodeValue(pv)}`; } + if (encValue == null) { + return; + } + const keyPrefix = encodeString(pk); tmp = `${keyPrefix}=${encValue}`; // trim trailing '=' if value was empty @@ -66,36 +74,41 @@ export function encodeLabel( key: string, value: unknown, options?: { explode?: boolean; charEncoding?: "percent" | "none" }, -): string { +): string | undefined { let out = ""; const pairs: [string, unknown][] = options?.explode ? explode(key, value) : [[key, value]]; + if (pairs.every(([_, v]) => v == null)) { + return; + } + const encodeString = (v: string) => { return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; }; const encodeValue = (v: unknown) => encodeString(serializeValue(v)); pairs.forEach(([pk, pv]) => { - let encValue = ""; + let encValue: string | null | undefined = ""; - if (pv === undefined) { + if (pv == null) { return; } else if (Array.isArray(pv)) { - encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join("."); + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`)?.join("."); } else if (isPlainObject(pv)) { - encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + const mapped = mapDefinedEntries(Object.entries(pv), ([k, v]) => { return `.${encodeString(k)}.${encodeValue(v)}`; - }).join(""); - encValue = encValue.slice(1); + }); + encValue = mapped?.join("").slice(1); } else { - const k = - options?.explode && isPlainObject(value) ? `${encodeString(pk)}=` : ""; + const k = options?.explode && isPlainObject(value) + ? `${encodeString(pk)}=` + : ""; encValue = `${k}${encodeValue(pv)}`; } - out += `.${encValue}`; + out += encValue == null ? "" : `.${encValue}`; }); return out; @@ -105,7 +118,7 @@ type FormEncoder = ( key: string, value: unknown, options?: { explode?: boolean; charEncoding?: "percent" | "none" }, -) => string; +) => string | undefined; function formEncoder(sep: string): FormEncoder { return ( @@ -118,6 +131,10 @@ function formEncoder(sep: string): FormEncoder { ? explode(key, value) : [[key, value]]; + if (pairs.every(([_, v]) => v == null)) { + return; + } + const encodeString = (v: string) => { return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; }; @@ -128,20 +145,24 @@ function formEncoder(sep: string): FormEncoder { pairs.forEach(([pk, pv]) => { let tmp = ""; - let encValue = ""; + let encValue: string | null | undefined = null; - if (pv === undefined) { + if (pv == null) { return; } else if (Array.isArray(pv)) { - encValue = mapDefined(pv, (v) => `${encodeValue(v)}`).join(encodedSep); + encValue = mapDefined(pv, (v) => `${encodeValue(v)}`)?.join(encodedSep); } else if (isPlainObject(pv)) { encValue = mapDefinedEntries(Object.entries(pv), ([k, v]) => { return `${encodeString(k)}${encodedSep}${encodeValue(v)}`; - }).join(encodedSep); + })?.join(encodedSep); } else { encValue = `${encodeValue(pv)}`; } + if (encValue == null) { + return; + } + tmp = `${encodeString(pk)}=${encValue}`; // If we end up with the nothing then skip forward @@ -180,7 +201,7 @@ export function encodeBodyForm( let tmp = ""; let encValue = ""; - if (pv === undefined) { + if (pv == null) { return; } else if (Array.isArray(pv)) { encValue = JSON.stringify(pv, jsonReplacer); @@ -207,14 +228,14 @@ export function encodeDeepObject( key: string, value: unknown, options?: { charEncoding?: "percent" | "none" }, -): string { +): string | undefined { if (value == null) { - return ""; + return; } if (!isPlainObject(value)) { throw new EncodingError( - `Value of parameter '${key}' which uses deepObject encoding must be an object`, + `Value of parameter '${key}' which uses deepObject encoding must be an object or null`, ); } @@ -225,9 +246,9 @@ export function encodeDeepObjectObject( key: string, value: unknown, options?: { charEncoding?: "percent" | "none" }, -): string { +): string | undefined { if (value == null) { - return ""; + return; } let out = ""; @@ -241,7 +262,7 @@ export function encodeDeepObjectObject( } Object.entries(value).forEach(([ck, cv]) => { - if (cv === undefined) { + if (cv == null) { return; } @@ -250,19 +271,17 @@ export function encodeDeepObjectObject( if (isPlainObject(cv)) { const objOut = encodeDeepObjectObject(pk, cv, options); - out += `&${objOut}`; + out += objOut == null ? "" : `&${objOut}`; return; } const pairs: unknown[] = Array.isArray(cv) ? cv : [cv]; - let encoded = ""; - - encoded = mapDefined(pairs, (v) => { + const encoded = mapDefined(pairs, (v) => { return `${encodeString(pk)}=${encodeString(serializeValue(v))}`; - }).join("&"); + })?.join("&"); - out += `&${encoded}`; + out += encoded == null ? "" : `&${encoded}`; }); return out.slice(1); @@ -272,9 +291,9 @@ export function encodeJSON( key: string, value: unknown, options?: { explode?: boolean; charEncoding?: "percent" | "none" }, -): string { +): string | undefined { if (typeof value === "undefined") { - return ""; + return; } const encodeString = (v: string) => { @@ -290,40 +309,39 @@ export const encodeSimple = ( key: string, value: unknown, options?: { explode?: boolean; charEncoding?: "percent" | "none" }, -): string => { +): string | undefined => { let out = ""; const pairs: [string, unknown][] = options?.explode ? explode(key, value) : [[key, value]]; + if (pairs.every(([_, v]) => v == null)) { + return; + } + const encodeString = (v: string) => { return options?.charEncoding === "percent" ? encodeURIComponent(v) : v; }; const encodeValue = (v: unknown) => encodeString(serializeValue(v)); pairs.forEach(([pk, pv]) => { - let tmp = ""; + let tmp: string | null | undefined = ""; - if (pv === undefined) { + if (pv == null) { return; } else if (Array.isArray(pv)) { - tmp = mapDefined(pv, (v) => `${encodeValue(v)}`).join(","); + tmp = mapDefined(pv, (v) => `${encodeValue(v)}`)?.join(","); } else if (isPlainObject(pv)) { - tmp = mapDefinedEntries(Object.entries(pv), ([k, v]) => { + const mapped = mapDefinedEntries(Object.entries(pv), ([k, v]) => { return `,${encodeString(k)},${encodeValue(v)}`; - }).join(""); - tmp = tmp.slice(1); + }); + tmp = mapped?.join("").slice(1); } else { const k = options?.explode && isPlainObject(value) ? `${pk}=` : ""; tmp = `${k}${encodeValue(pv)}`; } - // If we end up with the nothing then skip forward - if (!tmp) { - return; - } - - out += `,${tmp}`; + out += tmp ? `,${tmp}` : ""; }); return out.slice(1); @@ -341,9 +359,7 @@ function explode(key: string, value: unknown): [string, unknown][] { } function serializeValue(value: unknown): string { - if (value === null) { - return "null"; - } else if (typeof value === "undefined") { + if (value == null) { return ""; } else if (value instanceof Date) { return value.toISOString(); @@ -364,14 +380,14 @@ function jsonReplacer(_: string, value: unknown): unknown { } } -function mapDefined(inp: T[], mapper: (v: T) => R): R[] { - return inp.reduce((acc, v) => { - if (v === undefined) { +function mapDefined(inp: T[], mapper: (v: T) => R): R[] | null { + const res = inp.reduce((acc, v) => { + if (v == null) { return acc; } const m = mapper(v); - if (m === undefined) { + if (m == null) { return acc; } @@ -379,43 +395,46 @@ function mapDefined(inp: T[], mapper: (v: T) => R): R[] { return acc; }, []); + + return res.length ? res : null; } function mapDefinedEntries( inp: Iterable<[K, V]>, mapper: (v: [K, V]) => R, -): R[] { +): R[] | null { const acc: R[] = []; for (const [k, v] of inp) { - if (v === undefined) { + if (v == null) { continue; } const m = mapper([k, v]); - if (m === undefined) { + if (m == null) { continue; } acc.push(m); } - return acc; + return acc.length ? acc : null; } -export function queryJoin(...args: string[]): string { +export function queryJoin(...args: (string | undefined)[]): string { return args.filter(Boolean).join("&"); } type QueryEncoderOptions = { explode?: boolean; charEncoding?: "percent" | "none"; + allowEmptyValue?: string[]; }; type QueryEncoder = ( key: string, value: unknown, options?: QueryEncoderOptions, -) => string; +) => string | undefined; type BulkQueryEncoder = ( values: Record, @@ -423,7 +442,7 @@ type BulkQueryEncoder = ( ) => string; export function queryEncoder(f: QueryEncoder): BulkQueryEncoder { - const bulkEncode = function ( + const bulkEncode = function( values: Record, options?: QueryEncoderOptions, ): string { @@ -433,7 +452,19 @@ export function queryEncoder(f: QueryEncoder): BulkQueryEncoder { charEncoding: options?.charEncoding ?? "percent", }; + const allowEmptySet = new Set(options?.allowEmptyValue ?? []); + const encoded = Object.entries(values).map(([key, value]) => { + if (allowEmptySet.has(key)) { + if ( + value === undefined + || value === null + || value === "" + || (Array.isArray(value) && value.length === 0) + ) { + return `${encodeURIComponent(key)}=`; + } + } return f(key, value, opts); }); return queryJoin(...encoded); @@ -447,3 +478,48 @@ export const encodeFormQuery = queryEncoder(encodeForm); export const encodeSpaceDelimitedQuery = queryEncoder(encodeSpaceDelimited); export const encodePipeDelimitedQuery = queryEncoder(encodePipeDelimited); export const encodeDeepObjectQuery = queryEncoder(encodeDeepObject); + +function isBlobLike(val: unknown): val is Blob { + if (val instanceof Blob) { + return true; + } + + if (typeof val !== "object" || val == null || !(Symbol.toStringTag in val)) { + return false; + } + + const tag = val[Symbol.toStringTag]; + if (tag !== "Blob" && tag !== "File") { + return false; + } + + return "stream" in val && typeof val.stream === "function"; +} + +export function appendForm( + fd: FormData, + key: string, + value: unknown, + fileName?: string, +): void { + if (value == null) { + return; + } else if (isBlobLike(value)) { + if (fileName) { + fd.append(key, value as Blob, fileName); + } else { + fd.append(key, value as Blob); + } + } else { + fd.append(key, String(value)); + } +} + +export async function normalizeBlob( + value: Pick, +): Promise { + if (value instanceof Blob) { + return value; + } + return new Blob([await value.arrayBuffer()], { type: value.type }); +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/env.ts b/frameworks-elysia/sdk-typescript/src/lib/env.ts index c94701ff..83cc953a 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/env.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/env.ts @@ -2,18 +2,33 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ +import * as z from "zod/v3"; import { dlv } from "./dlv.js"; -import * as z from "zod"; - export interface Env { + SDK_O_AUTH2?: string | undefined; + SDK_DEBUG?: boolean | undefined; } export const envSchema: z.ZodType = z.object({ + SDK_O_AUTH2: z.string().optional(), + SDK_DEBUG: z.coerce.boolean().optional(), }); +/** + * Checks for the existence of the Deno global object to determine the environment. + * @returns {boolean} True if the runtime is Deno, false otherwise. + */ +function isDeno() { + if ("Deno" in globalThis) { + return true; + } + + return false; +} + let envMemo: Env | undefined = undefined; /** * Reads and validates environment variables. @@ -23,9 +38,14 @@ export function env(): Env { return envMemo; } - envMemo = envSchema.parse( - dlv(globalThis, "process.env") ?? dlv(globalThis, "Deno.env") ?? {}, - ); + let envObject: Record = {}; + if (isDeno()) { + envObject = (globalThis as any).Deno?.env?.toObject?.() ?? {}; + } else { + envObject = dlv(globalThis, "process.env") ?? {}; + } + + envMemo = envSchema.parse(envObject); return envMemo; } diff --git a/frameworks-elysia/sdk-typescript/src/lib/files.ts b/frameworks-elysia/sdk-typescript/src/lib/files.ts index 19e08041..6ca6b37d 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/files.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/files.ts @@ -36,5 +36,69 @@ export async function readableStreamToArrayBuffer( offset += chunk.length; } - return concatenatedChunks.buffer; + return concatenatedChunks.buffer as ArrayBuffer; +} + +/** + * Determines the MIME content type based on a file's extension. + * Returns null if the extension is not recognized. + */ +export function getContentTypeFromFileName(fileName: string): string | null { + if (!fileName) return null; + + const ext = fileName.toLowerCase().split(".").pop(); + if (!ext) return null; + + const mimeTypes: Record = { + json: "application/json", + xml: "application/xml", + html: "text/html", + htm: "text/html", + txt: "text/plain", + csv: "text/csv", + pdf: "application/pdf", + png: "image/png", + jpg: "image/jpeg", + jpeg: "image/jpeg", + gif: "image/gif", + svg: "image/svg+xml", + js: "application/javascript", + css: "text/css", + zip: "application/zip", + tar: "application/x-tar", + gz: "application/gzip", + mp4: "video/mp4", + mp3: "audio/mpeg", + wav: "audio/wav", + webp: "image/webp", + ico: "image/x-icon", + woff: "font/woff", + woff2: "font/woff2", + ttf: "font/ttf", + otf: "font/otf", + }; + + return mimeTypes[ext] || null; +} + +/** + * Creates a Blob from file content with the given MIME type. + * + * Node.js Buffers are Uint8Array subclasses that may share a pooled + * ArrayBuffer (byteOffset > 0, byteLength < buffer.byteLength). Passing + * such a Buffer directly to `new Blob([buf])` can include the entire + * underlying pool on some runtimes, producing a Blob with extra bytes + * that corrupts multipart uploads. + * + * Copying into a standalone Uint8Array ensures the Blob receives only the + * intended bytes regardless of runtime behaviour. + */ +export function bytesToBlob( + content: Uint8Array | ArrayBuffer | Blob | string, + contentType: string, +): Blob { + if (content instanceof Uint8Array) { + return new Blob([new Uint8Array(content)], { type: contentType }); + } + return new Blob([content as BlobPart], { type: contentType }); } diff --git a/frameworks-elysia/sdk-typescript/src/lib/matchers.ts b/frameworks-elysia/sdk-typescript/src/lib/matchers.ts index 65858ac9..b7ef1986 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/matchers.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/matchers.ts @@ -3,13 +3,13 @@ */ import { APIError } from "../models/errors/apierror.js"; -import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; -import { Result } from "../types/fp.js"; +import { ResponseValidationError } from "../models/errors/responsevalidationerror.js"; +import { ERR, OK, Result } from "../types/fp.js"; import { matchResponse, matchStatusCode, StatusCodePredicate } from "./http.js"; import { isPlainObject } from "./is-plain-object.js"; -import { safeParse } from "./schemas.js"; export type Encoding = + | "jsonl" | "json" | "text" | "bytes" @@ -19,6 +19,7 @@ export type Encoding = | "fail"; const DEFAULT_CONTENT_TYPES: Record = { + jsonl: "application/jsonl", json: "application/json", text: "text/plain", bytes: "application/octet-stream", @@ -72,6 +73,21 @@ export function json( return { ...options, enc: "json", codes, schema }; } +export function jsonl( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ValueMatcher { + return { ...options, enc: "jsonl", codes, schema }; +} + +export function jsonlErr( + codes: StatusCodePredicate, + schema: Schema, + options?: MatchOptions, +): ErrorMatcher { + return { ...options, err: true, enc: "jsonl", codes, schema }; +} export function textErr( codes: StatusCodePredicate, schema: Schema, @@ -159,17 +175,19 @@ export type MatchedError = Matchers extends Matcher[] : never; export type MatchFunc = ( response: Response, + request: Request, options?: { resultKey?: string; extraFields?: Record }, ) => Promise<[result: Result, raw: unknown]>; export function match( ...matchers: Array> -): MatchFunc { +): MatchFunc { return async function matchFunc( response: Response, + request: Request, options?: { resultKey?: string; extraFields?: Record }, ): Promise< - [result: Result, raw: unknown] + [result: Result, raw: unknown] > { let raw: unknown; let matcher: Matcher | undefined; @@ -188,21 +206,25 @@ export function match( } if (!matcher) { - const responseBody = await response.text(); return [{ ok: false, - error: new APIError( - "Unexpected API response status or content-type", + error: new APIError("Unexpected Status or Content-Type", { response, - responseBody, - ), - }, responseBody]; + request, + body: await response.text().catch(() => ""), + }), + }, raw]; } const encoding = matcher.enc; + let body = ""; switch (encoding) { case "json": - raw = await response.json(); + body = await response.text(); + raw = JSON.parse(body); + break; + case "jsonl": + raw = response.body; break; case "bytes": raw = new Uint8Array(await response.arrayBuffer()); @@ -211,30 +233,30 @@ export function match( raw = response.body; break; case "text": - raw = await response.text(); + body = await response.text(); + raw = body; break; case "sse": raw = response.body; break; case "nil": - raw = await discardResponseBody(response); + body = await response.text(); + raw = undefined; break; case "fail": - raw = await response.text(); + body = await response.text(); + raw = body; break; default: - encoding satisfies never; - throw new Error(`Unsupported response type: ${encoding}`); + throw new Error( + `Unsupported response type: ${encoding satisfies never}`, + ); } if (matcher.enc === "fail") { return [{ ok: false, - error: new APIError( - "API error occurred", - response, - typeof raw === "string" ? raw : "", - ), + error: new APIError("API error occurred", { request, response, body }), }, raw]; } @@ -246,6 +268,9 @@ export function match( ...options?.extraFields, ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null), ...(isPlainObject(raw) ? raw : null), + request$: request, + response$: response, + body$: body, }; } else if (resultKey) { data = { @@ -264,18 +289,20 @@ export function match( } if ("err" in matcher) { - const result = safeParse( + const result = safeParseResponse( data, (v: unknown) => matcher.schema.parse(v), "Response validation failed", + { request, response, body }, ); return [result.ok ? { ok: false, error: result.value } : result, raw]; } else { return [ - safeParse( + safeParseResponse( data, (v: unknown) => matcher.schema.parse(v), "Response validation failed", + { request, response, body }, ), raw, ]; @@ -298,25 +325,22 @@ export function unpackHeaders(headers: Headers): Record { return out; } -/** - * Discards the response body to free up resources. - * - * To learn why this is need, see the undici docs: - * https://undici.nodejs.org/#/?id=garbage-collection - */ -export async function discardResponseBody(res: Response) { - const reader = res.body?.getReader(); - if (reader == null) { - return; - } - +function safeParseResponse( + rawValue: Inp, + fn: (value: Inp) => Out, + errorMessage: string, + httpMeta: { response: Response; request: Request; body: string }, +): Result { try { - let done = false; - while (!done) { - const res = await reader.read(); - done = res.done; - } - } finally { - reader.releaseLock(); + return OK(fn(rawValue)); + } catch (err) { + return ERR( + new ResponseValidationError(errorMessage, { + cause: err, + rawValue, + rawMessage: errorMessage, + ...httpMeta, + }), + ); } } diff --git a/frameworks-elysia/sdk-typescript/src/lib/primitives.ts b/frameworks-elysia/sdk-typescript/src/lib/primitives.ts index 1dc4ee43..d21f1dc4 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/primitives.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/primitives.ts @@ -120,3 +120,31 @@ export function abortSignalAny(signals: AbortSignal[]): AbortSignal { return result; } + +export function compactMap( + values: Record, +): Record { + const out: Record = {}; + + for (const [k, v] of Object.entries(values)) { + if (typeof v !== "undefined") { + out[k] = v; + } + } + + return out; +} + +export function allRequired>( + v: V, +): + | { + [K in keyof V]: NonNullable; + } + | undefined { + if (Object.values(v).every((x) => x == null)) { + return void 0; + } + + return v as ReturnType>; +} diff --git a/frameworks-elysia/sdk-typescript/src/lib/retries.ts b/frameworks-elysia/sdk-typescript/src/lib/retries.ts index 93ebc8de..e3ce9aba 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/retries.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/retries.ts @@ -158,7 +158,6 @@ async function retryBackoff( const start = Date.now(); let x = 0; - // eslint-disable-next-line no-constant-condition while (true) { try { const res = await fn(); diff --git a/frameworks-elysia/sdk-typescript/src/lib/schemas.ts b/frameworks-elysia/sdk-typescript/src/lib/schemas.ts index f3856dcb..47edb972 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/schemas.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/schemas.ts @@ -9,7 +9,7 @@ import { ZodObject, ZodRawShape, ZodTypeAny, -} from "zod"; +} from "zod/v3"; import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; import { ERR, OK, Result } from "../types/fp.js"; @@ -57,6 +57,7 @@ export function collectExtraKeys< >( obj: ZodObject, extrasKey: K, + optional: boolean, ): ZodEffects< typeof obj, & output> @@ -81,6 +82,10 @@ export function collectExtraKeys< delete val[key]; } + if (optional && Object.keys(extras).length === 0) { + return val; + } + return { ...val, [extrasKey]: extras }; }); } diff --git a/frameworks-elysia/sdk-typescript/src/lib/sdks.ts b/frameworks-elysia/sdk-typescript/src/lib/sdks.ts index 3c27b591..212ccb74 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/sdks.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/sdks.ts @@ -22,7 +22,6 @@ import { isConnectionError, isTimeoutError, matchContentType, - matchStatusCode, } from "./http.js"; import { Logger } from "./logger.js"; import { retry, RetryConfig } from "./retries.js"; @@ -43,22 +42,29 @@ export type RequestOptions = { */ retryCodes?: string[]; /** + * Overrides the base server URL that will be used by an operation. + */ + serverURL?: string | URL; + /** + * @deprecated `fetchOptions` has been flattened into `RequestOptions`. + * * Sets various request options on the `fetch` call made by an SDK method. * * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options|Request} */ fetchOptions?: Omit; -}; +} & Omit; type RequestConfig = { method: string; path: string; - baseURL?: string | URL; + baseURL?: string | URL | undefined; query?: string; body?: RequestInit["body"]; headers?: HeadersInit; security?: SecurityState | null; uaHeader?: string; + userAgent?: string | undefined; timeoutMs?: number; }; @@ -75,7 +81,7 @@ export class ClientSDK { readonly #httpClient: HTTPClient; readonly #hooks: SDKHooks; readonly #logger?: Logger | undefined; - protected readonly _baseURL: URL | null; + public readonly _baseURL: URL | null; public readonly _options: SDKOptions & { hooks?: SDKHooks }; constructor(options: SDKOptions = {}) { @@ -90,19 +96,21 @@ export class ClientSDK { } else { this.#hooks = new SDKHooks(); } - this._options = { ...options, hooks: this.#hooks }; - const url = serverURLFromOptions(options); if (url) { url.pathname = url.pathname.replace(/\/+$/, "") + "/"; } + const { baseURL, client } = this.#hooks.sdkInit({ baseURL: url, client: options.httpClient || new HTTPClient(), }); this._baseURL = baseURL; this.#httpClient = client; - this.#logger = options.debugLogger; + + this._options = { ...options, hooks: this.#hooks }; + + this.#logger = this._options.debugLogger; if (!this.#logger && env().SDK_DEBUG) { this.#logger = console; } @@ -119,18 +127,24 @@ export class ClientSDK { if (!base) { return ERR(new InvalidRequestError("No base URL provided for operation")); } - const reqURL = new URL(base); - const inputURL = new URL(path, reqURL); - + const baseURL = new URL(base); + let reqURL: URL; if (path) { - reqURL.pathname += inputURL.pathname.replace(/^\/+/, ""); + baseURL.pathname = baseURL.pathname.replace(/\/+$/, "") + "/"; + reqURL = new URL(path, baseURL); + } else { + reqURL = baseURL; } + reqURL.hash = ""; let finalQuery = query || ""; const secQuery: string[] = []; for (const [k, v] of Object.entries(security?.queryParams || {})) { - secQuery.push(encodeForm(k, v, { charEncoding: "percent" })); + const q = encodeForm(k, v, { charEncoding: "percent" }); + if (typeof q !== "undefined") { + secQuery.push(q); + } } if (secQuery.length) { finalQuery += `&${secQuery.join("&")}`; @@ -164,7 +178,9 @@ export class ClientSDK { cookie = cookie.startsWith("; ") ? cookie.slice(2) : cookie; headers.set("cookie", cookie); - const userHeaders = new Headers(options?.fetchOptions?.headers); + const userHeaders = new Headers( + options?.headers ?? options?.fetchOptions?.headers, + ); for (const [k, v] of userHeaders) { headers.set(k, v); } @@ -172,29 +188,23 @@ export class ClientSDK { // Only set user agent header in non-browser-like environments since CORS // policy disallows setting it in browsers e.g. Chrome throws an error. if (!isBrowserLike) { - headers.set(conf.uaHeader ?? "user-agent", SDK_METADATA.userAgent); + headers.set( + conf.uaHeader ?? "user-agent", + conf.userAgent ?? SDK_METADATA.userAgent, + ); } - let fetchOptions = options?.fetchOptions; + const fetchOptions: Omit = { + ...options?.fetchOptions, + ...options, + }; if (!fetchOptions?.signal && conf.timeoutMs && conf.timeoutMs > 0) { const timeoutSignal = AbortSignal.timeout(conf.timeoutMs); - if (!fetchOptions) { - fetchOptions = { signal: timeoutSignal }; - } else { - fetchOptions.signal = timeoutSignal; - } + fetchOptions.signal = timeoutSignal; } if (conf.body instanceof ReadableStream) { - if (!fetchOptions) { - fetchOptions = { - // @ts-expect-error see https://github.com/node-fetch/node-fetch/issues/1769 - duplex: "half", - }; - } else { - // @ts-expect-error see https://github.com/node-fetch/node-fetch/issues/1769 - fetchOptions.duplex = "half"; - } + Object.assign(fetchOptions, { duplex: "half" }); } let input; @@ -223,7 +233,7 @@ export class ClientSDK { request: Request, options: { context: HookContext; - errorCodes: number | string | (number | string)[]; + isErrorStatusCode: (statusCode: number) => boolean; retryConfig: RetryConfig; retryCodes: string[]; }, @@ -236,7 +246,7 @@ export class ClientSDK { | UnexpectedClientError > > { - const { context, errorCodes } = options; + const { context, isErrorStatusCode } = options; return retry( async () => { @@ -248,7 +258,7 @@ export class ClientSDK { let response = await this.#httpClient.request(req); try { - if (matchStatusCode(response, errorCodes)) { + if (isErrorStatusCode(response.status)) { const result = await this.#hooks.afterError( context, response, @@ -299,7 +309,9 @@ export class ClientSDK { } } -const jsonLikeContentTypeRE = /^application\/(?:.{0,100}\+)?json/; +const jsonLikeContentTypeRE = /^(application|text)\/([^+]+\+)*json.*/; +const jsonlLikeContentTypeRE = + /^(application|text)\/([^+]+\+)*(jsonl|x-ndjson)\b.*/; async function logRequest(logger: Logger | undefined, req: Request) { if (!logger) { return; @@ -365,9 +377,11 @@ async function logResponse( logger.group("Body:"); switch (true) { case matchContentType(res, "application/json") - || jsonLikeContentTypeRE.test(ct): + || jsonLikeContentTypeRE.test(ct) && !jsonlLikeContentTypeRE.test(ct): logger.log(await res.clone().json()); break; + case matchContentType(res, "application/jsonl") + || jsonlLikeContentTypeRE.test(ct): case matchContentType(res, "text/event-stream"): logger.log(`<${contentType}>`); break; diff --git a/frameworks-elysia/sdk-typescript/src/lib/security.ts b/frameworks-elysia/sdk-typescript/src/lib/security.ts index 321e02fe..36d6d87d 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/security.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/security.ts @@ -2,10 +2,13 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ +import * as components from "../models/components/index.js"; +import { env } from "./env.js"; + type OAuth2PasswordFlow = { username: string; - password?: string | undefined; - clientID: string; + password: string; + clientID?: string | undefined; clientSecret?: string | undefined; tokenURL: string; }; @@ -81,9 +84,14 @@ type SecurityInputOAuth2 = { type SecurityInputOAuth2ClientCredentials = { type: "oauth2:client_credentials"; value: - | { clientID?: string | undefined; clientSecret?: string | undefined } + | { + clientID?: string | undefined; + clientSecret?: string | undefined; + } | null + | string | undefined; + fieldName?: string; }; type SecurityInputOAuth2PasswordCredentials = { @@ -92,13 +100,13 @@ type SecurityInputOAuth2PasswordCredentials = { | string | null | undefined; - fieldName: string; + fieldName?: string; }; type SecurityInputCustom = { type: "http:custom"; value: any | null | undefined; - fieldName: string; + fieldName?: string; }; export type SecurityInput = @@ -115,7 +123,7 @@ export function resolveSecurity( ...options: SecurityInput[][] ): SecurityState | null { const state: SecurityState = { - basic: { username: "", password: "" }, + basic: {}, headers: {}, queryParams: {}, cookies: {}, @@ -135,6 +143,9 @@ export function resolveSecurity( typeof o.value === "string" && !!o.value ); } else if (o.type === "oauth2:client_credentials") { + if (typeof o.value == "string") { + return !!o.value; + } return o.value.clientID != null || o.value.clientSecret != null; } else if (typeof o.value === "string") { return !!o.value; @@ -187,8 +198,7 @@ export function resolveSecurity( applyBearer(state, spec); break; default: - spec satisfies never; - throw SecurityError.unrecognizedType(type); + throw SecurityError.unrecognizedType((spec satisfies never, type)); } }); @@ -223,5 +233,43 @@ function applyBearer( value = `Bearer ${value}`; } - state.headers[spec.fieldName] = value; + if (spec.fieldName !== undefined) { + state.headers[spec.fieldName] = value; + } +} + +export function resolveGlobalSecurity( + security: Partial | null | undefined, + allowedFields?: number[], +): SecurityState | null { + let inputs: SecurityInput[][] = [ + [ + { + fieldName: "Authorization", + type: "oauth2", + value: security?.oAuth2 ?? env().SDK_O_AUTH2, + }, + ], + ]; + + if (allowedFields) { + inputs = allowedFields.map((i) => { + if (i < 0 || i >= inputs.length) { + throw new RangeError(`invalid allowedFields index ${i}`); + } + return inputs[i]!; + }); + } + + return resolveSecurity(...inputs); +} + +export async function extractSecurity< + T extends string | Record, +>(sec: T | (() => Promise) | undefined): Promise { + if (sec == null) { + return; + } + + return typeof sec === "function" ? sec() : sec; } diff --git a/frameworks-elysia/sdk-typescript/src/lib/url.ts b/frameworks-elysia/sdk-typescript/src/lib/url.ts index 6bc6356e..79e7ce66 100644 --- a/frameworks-elysia/sdk-typescript/src/lib/url.ts +++ b/frameworks-elysia/sdk-typescript/src/lib/url.ts @@ -10,24 +10,26 @@ export function pathToFunc( pathPattern: string, options?: { charEncoding?: "percent" | "none" }, ): (params?: Params) => string { - const paramRE = /\{([a-zA-Z0-9_]+?)\}/g; + const paramRE = /\{([a-zA-Z0-9_][a-zA-Z0-9_-]*?)\}/g; return function buildURLPath(params: Record = {}): string { - return pathPattern.replace(paramRE, function (_, placeholder) { - if (!hasOwn.call(params, placeholder)) { - throw new Error(`Parameter '${placeholder}' is required`); - } + return pathPattern + .replace(paramRE, function (_, placeholder) { + if (!hasOwn.call(params, placeholder)) { + throw new Error(`Parameter '${placeholder}' is required`); + } - const value = params[placeholder]; - if (typeof value !== "string" && typeof value !== "number") { - throw new Error( - `Parameter '${placeholder}' must be a string or number`, - ); - } + const value = params[placeholder]; + if (typeof value !== "string" && typeof value !== "number") { + throw new Error( + `Parameter '${placeholder}' must be a string or number`, + ); + } - return options?.charEncoding === "percent" - ? encodeURIComponent(`${value}`) - : `${value}`; - }); + return options?.charEncoding === "percent" + ? encodeURIComponent(`${value}`) + : `${value}`; + }) + .replace(/^\/+/, ""); }; } diff --git a/frameworks-elysia/sdk-typescript/src/models/components/id.ts b/frameworks-elysia/sdk-typescript/src/models/components/id.ts deleted file mode 100644 index 53670909..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/components/id.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type Id = { - id: string; -}; - -/** @internal */ -export const Id$inboundSchema: z.ZodType = z.object({ - id: z.string(), -}); - -/** @internal */ -export type Id$Outbound = { - id: string; -}; - -/** @internal */ -export const Id$outboundSchema: z.ZodType = z - .object({ - id: z.string(), - }); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace Id$ { - /** @deprecated use `Id$inboundSchema` instead. */ - export const inboundSchema = Id$inboundSchema; - /** @deprecated use `Id$outboundSchema` instead. */ - export const outboundSchema = Id$outboundSchema; - /** @deprecated use `Id$Outbound` instead. */ - export type Outbound = Id$Outbound; -} - -export function idToJSON(id: Id): string { - return JSON.stringify(Id$outboundSchema.parse(id)); -} - -export function idFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => Id$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'Id' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/index.ts b/frameworks-elysia/sdk-typescript/src/models/components/index.ts index e3ff5bee..2edb51c4 100644 --- a/frameworks-elysia/sdk-typescript/src/models/components/index.ts +++ b/frameworks-elysia/sdk-typescript/src/models/components/index.ts @@ -2,6 +2,4 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -export * from "./id.js"; -export * from "./successresponse.js"; -export * from "./user.js"; +export * from "./security.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/components/security.ts b/frameworks-elysia/sdk-typescript/src/models/components/security.ts new file mode 100644 index 00000000..c0becc2f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/components/security.ts @@ -0,0 +1,32 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; + +export type Security = { + oAuth2?: string | undefined; +}; + +/** @internal */ +export type Security$Outbound = { + OAuth2?: string | undefined; +}; + +/** @internal */ +export const Security$outboundSchema: z.ZodType< + Security$Outbound, + z.ZodTypeDef, + Security +> = z.object({ + oAuth2: z.string().optional(), +}).transform((v) => { + return remap$(v, { + oAuth2: "OAuth2", + }); +}); + +export function securityToJSON(security: Security): string { + return JSON.stringify(Security$outboundSchema.parse(security)); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts b/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts deleted file mode 100644 index 147c8885..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/components/successresponse.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type SuccessResponse = { - success: boolean; -}; - -/** @internal */ -export const SuccessResponse$inboundSchema: z.ZodType< - SuccessResponse, - z.ZodTypeDef, - unknown -> = z.object({ - success: z.boolean(), -}); - -/** @internal */ -export type SuccessResponse$Outbound = { - success: boolean; -}; - -/** @internal */ -export const SuccessResponse$outboundSchema: z.ZodType< - SuccessResponse$Outbound, - z.ZodTypeDef, - SuccessResponse -> = z.object({ - success: z.boolean(), -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace SuccessResponse$ { - /** @deprecated use `SuccessResponse$inboundSchema` instead. */ - export const inboundSchema = SuccessResponse$inboundSchema; - /** @deprecated use `SuccessResponse$outboundSchema` instead. */ - export const outboundSchema = SuccessResponse$outboundSchema; - /** @deprecated use `SuccessResponse$Outbound` instead. */ - export type Outbound = SuccessResponse$Outbound; -} - -export function successResponseToJSON( - successResponse: SuccessResponse, -): string { - return JSON.stringify(SuccessResponse$outboundSchema.parse(successResponse)); -} - -export function successResponseFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => SuccessResponse$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'SuccessResponse' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/components/user.ts b/frameworks-elysia/sdk-typescript/src/models/components/user.ts deleted file mode 100644 index 162163b2..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/components/user.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type User = { - id: string; - name: string; - age: number; -}; - -/** @internal */ -export const User$inboundSchema: z.ZodType = z - .object({ - id: z.string(), - name: z.string(), - age: z.number(), - }); - -/** @internal */ -export type User$Outbound = { - id: string; - name: string; - age: number; -}; - -/** @internal */ -export const User$outboundSchema: z.ZodType = - z.object({ - id: z.string(), - name: z.string(), - age: z.number(), - }); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace User$ { - /** @deprecated use `User$inboundSchema` instead. */ - export const inboundSchema = User$inboundSchema; - /** @deprecated use `User$outboundSchema` instead. */ - export const outboundSchema = User$outboundSchema; - /** @deprecated use `User$Outbound` instead. */ - export type Outbound = User$Outbound; -} - -export function userToJSON(user: User): string { - return JSON.stringify(User$outboundSchema.parse(user)); -} - -export function userFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => User$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'User' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts index 3a04a1c3..d514b64b 100644 --- a/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts +++ b/frameworks-elysia/sdk-typescript/src/models/errors/apierror.ts @@ -2,26 +2,39 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -export class APIError extends Error { - public readonly statusCode: number; - public readonly contentType: string; +import { SDKError } from "./sdkerror.js"; +/** The fallback error class if no more specific error class is matched */ +export class APIError extends SDKError { constructor( message: string, - public readonly rawResponse: Response, - public readonly body: string = "", + httpMeta: { + response: Response; + request: Request; + body: string; + }, ) { - const statusCode = rawResponse.status; - const contentType = rawResponse.headers.get("content-type") || ""; - const bodyString = body.length > 0 ? `\n${body}` : ""; - - super( - `${message}: Status ${statusCode} Content-Type ${contentType} Body ${bodyString}`, - ); - - this.statusCode = statusCode; - this.contentType = contentType; - + if (message) { + message += `: `; + } + message += `Status ${httpMeta.response.status}`; + const contentType = httpMeta.response.headers.get("content-type") || `""`; + if (contentType !== "application/json") { + message += ` Content-Type ${ + contentType.includes(" ") ? `"${contentType}"` : contentType + }`; + } + const body = httpMeta.body || `""`; + message += body.length > 100 ? "\n" : ". "; + let bodyDisplay = body; + if (body.length > 10000) { + const truncated = body.substring(0, 10000); + const remaining = body.length - 10000; + bodyDisplay = `${truncated}...and ${remaining} more chars`; + } + message += `Body: ${bodyDisplay}`; + message = message.trim(); + super(message, httpMeta); this.name = "APIError"; } } diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/createbooking.ts b/frameworks-elysia/sdk-typescript/src/models/errors/createbooking.ts new file mode 100644 index 00000000..6db97db6 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/createbooking.ts @@ -0,0 +1,130 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Conflict + */ +export type CreateBookingBookingsResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Conflict + */ +export class CreateBookingBookingsResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: CreateBookingBookingsResponseBodyData; + + constructor( + err: CreateBookingBookingsResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "CreateBookingBookingsResponseBody"; + } +} + +/** + * Not Found + */ +export type CreateBookingResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Not Found + */ +export class CreateBookingResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: CreateBookingResponseBodyData; + + constructor( + err: CreateBookingResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "CreateBookingResponseBody"; + } +} + +/** @internal */ +export const CreateBookingBookingsResponseBody$inboundSchema: z.ZodType< + CreateBookingBookingsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new CreateBookingBookingsResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); + +/** @internal */ +export const CreateBookingResponseBody$inboundSchema: z.ZodType< + CreateBookingResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new CreateBookingResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/createbookingpayment.ts b/frameworks-elysia/sdk-typescript/src/models/errors/createbookingpayment.ts new file mode 100644 index 00000000..40810b7e --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/createbookingpayment.ts @@ -0,0 +1,68 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Not Found + */ +export type CreateBookingPaymentResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Not Found + */ +export class CreateBookingPaymentResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: CreateBookingPaymentResponseBodyData; + + constructor( + err: CreateBookingPaymentResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "CreateBookingPaymentResponseBody"; + } +} + +/** @internal */ +export const CreateBookingPaymentResponseBody$inboundSchema: z.ZodType< + CreateBookingPaymentResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new CreateBookingPaymentResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/deletebooking.ts b/frameworks-elysia/sdk-typescript/src/models/errors/deletebooking.ts new file mode 100644 index 00000000..5cac079a --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/deletebooking.ts @@ -0,0 +1,68 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Not Found + */ +export type DeleteBookingResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Not Found + */ +export class DeleteBookingResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: DeleteBookingResponseBodyData; + + constructor( + err: DeleteBookingResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "DeleteBookingResponseBody"; + } +} + +/** @internal */ +export const DeleteBookingResponseBody$inboundSchema: z.ZodType< + DeleteBookingResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new DeleteBookingResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts b/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts deleted file mode 100644 index 077926df..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/errors/errorresponse.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; - -export type ErrorResponseData = { - status: number; - message: string; -}; - -export class ErrorResponse extends Error { - status: number; - - /** The original data that was passed to this error instance. */ - data$: ErrorResponseData; - - constructor(err: ErrorResponseData) { - const message = "message" in err && typeof err.message === "string" - ? err.message - : `API error occurred: ${JSON.stringify(err)}`; - super(message); - this.data$ = err; - - this.status = err.status; - - this.name = "ErrorResponse"; - } -} - -/** @internal */ -export const ErrorResponse$inboundSchema: z.ZodType< - ErrorResponse, - z.ZodTypeDef, - unknown -> = z.object({ - status: z.number(), - message: z.string(), -}) - .transform((v) => { - return new ErrorResponse(v); - }); - -/** @internal */ -export type ErrorResponse$Outbound = { - status: number; - message: string; -}; - -/** @internal */ -export const ErrorResponse$outboundSchema: z.ZodType< - ErrorResponse$Outbound, - z.ZodTypeDef, - ErrorResponse -> = z.instanceof(ErrorResponse) - .transform(v => v.data$) - .pipe(z.object({ - status: z.number(), - message: z.string(), - })); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace ErrorResponse$ { - /** @deprecated use `ErrorResponse$inboundSchema` instead. */ - export const inboundSchema = ErrorResponse$inboundSchema; - /** @deprecated use `ErrorResponse$outboundSchema` instead. */ - export const outboundSchema = ErrorResponse$outboundSchema; - /** @deprecated use `ErrorResponse$Outbound` instead. */ - export type Outbound = ErrorResponse$Outbound; -} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/getbooking.ts b/frameworks-elysia/sdk-typescript/src/models/errors/getbooking.ts new file mode 100644 index 00000000..96611bb7 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/getbooking.ts @@ -0,0 +1,68 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Not Found + */ +export type GetBookingResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Not Found + */ +export class GetBookingResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: GetBookingResponseBodyData; + + constructor( + err: GetBookingResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "GetBookingResponseBody"; + } +} + +/** @internal */ +export const GetBookingResponseBody$inboundSchema: z.ZodType< + GetBookingResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new GetBookingResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/getbookings.ts b/frameworks-elysia/sdk-typescript/src/models/errors/getbookings.ts new file mode 100644 index 00000000..714010fd --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/getbookings.ts @@ -0,0 +1,130 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Internal Server Error + */ +export type GetBookingsBookingsResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Internal Server Error + */ +export class GetBookingsBookingsResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: GetBookingsBookingsResponseBodyData; + + constructor( + err: GetBookingsBookingsResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "GetBookingsBookingsResponseBody"; + } +} + +/** + * Unauthorized + */ +export type GetBookingsResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Unauthorized + */ +export class GetBookingsResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: GetBookingsResponseBodyData; + + constructor( + err: GetBookingsResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "GetBookingsResponseBody"; + } +} + +/** @internal */ +export const GetBookingsBookingsResponseBody$inboundSchema: z.ZodType< + GetBookingsBookingsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new GetBookingsBookingsResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); + +/** @internal */ +export const GetBookingsResponseBody$inboundSchema: z.ZodType< + GetBookingsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new GetBookingsResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/getstations.ts b/frameworks-elysia/sdk-typescript/src/models/errors/getstations.ts new file mode 100644 index 00000000..3fff16e2 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/getstations.ts @@ -0,0 +1,68 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Bad Request + */ +export type GetStationsResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Bad Request + */ +export class GetStationsResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: GetStationsResponseBodyData; + + constructor( + err: GetStationsResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "GetStationsResponseBody"; + } +} + +/** @internal */ +export const GetStationsResponseBody$inboundSchema: z.ZodType< + GetStationsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new GetStationsResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/gettrips.ts b/frameworks-elysia/sdk-typescript/src/models/errors/gettrips.ts new file mode 100644 index 00000000..aaa233a4 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/gettrips.ts @@ -0,0 +1,68 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; + +/** + * Bad Request + */ +export type GetTripsResponseBodyData = { + type: string; + title: string; + status: number; + detail: string; +}; + +/** + * Bad Request + */ +export class GetTripsResponseBody extends SDKError { + type: string; + title: string; + status: number; + detail: string; + + /** The original data that was passed to this error instance. */ + data$: GetTripsResponseBodyData; + + constructor( + err: GetTripsResponseBodyData, + httpMeta: { response: Response; request: Request; body: string }, + ) { + const message = "message" in err && typeof err.message === "string" + ? err.message + : `API error occurred: ${JSON.stringify(err)}`; + super(message, httpMeta); + this.data$ = err; + this.type = err.type; + this.title = err.title; + this.status = err.status; + this.detail = err.detail; + + this.name = "GetTripsResponseBody"; + } +} + +/** @internal */ +export const GetTripsResponseBody$inboundSchema: z.ZodType< + GetTripsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + type: z.string(), + title: z.string(), + status: z.number(), + detail: z.string(), + request$: z.instanceof(Request), + response$: z.instanceof(Response), + body$: z.string(), +}) + .transform((v) => { + return new GetTripsResponseBody(v, { + request: v.request$, + response: v.response$, + body: v.body$, + }); + }); diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/index.ts b/frameworks-elysia/sdk-typescript/src/models/errors/index.ts index 17185050..5147c3c2 100644 --- a/frameworks-elysia/sdk-typescript/src/models/errors/index.ts +++ b/frameworks-elysia/sdk-typescript/src/models/errors/index.ts @@ -3,6 +3,14 @@ */ export * from "./apierror.js"; -export * from "./errorresponse.js"; +export * from "./createbooking.js"; +export * from "./createbookingpayment.js"; +export * from "./deletebooking.js"; +export * from "./getbooking.js"; +export * from "./getbookings.js"; +export * from "./getstations.js"; +export * from "./gettrips.js"; export * from "./httpclienterrors.js"; +export * from "./responsevalidationerror.js"; +export * from "./sdkerror.js"; export * from "./sdkvalidationerror.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/responsevalidationerror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/responsevalidationerror.ts new file mode 100644 index 00000000..d6620ee0 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/responsevalidationerror.ts @@ -0,0 +1,50 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { SDKError } from "./sdkerror.js"; +import { formatZodError } from "./sdkvalidationerror.js"; + +export class ResponseValidationError extends SDKError { + /** + * The raw value that failed validation. + */ + public readonly rawValue: unknown; + + /** + * The raw message that failed validation. + */ + public readonly rawMessage: unknown; + + constructor( + message: string, + extra: { + response: Response; + request: Request; + body: string; + cause: unknown; + rawValue: unknown; + rawMessage: unknown; + }, + ) { + super(message, extra); + this.name = "ResponseValidationError"; + this.cause = extra.cause; + this.rawValue = extra.rawValue; + this.rawMessage = extra.rawMessage; + } + + /** + * Return a pretty-formatted error message if the underlying validation error + * is a ZodError or some other recognized error type, otherwise return the + * default error message. + */ + public pretty(): string { + if (this.cause instanceof z.ZodError) { + return `${this.rawMessage}\n${formatZodError(this.cause)}`; + } else { + return this.toString(); + } + } +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/sdkerror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/sdkerror.ts new file mode 100644 index 00000000..efcdf908 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/errors/sdkerror.ts @@ -0,0 +1,35 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +/** The base class for all HTTP error responses */ +export class SDKError extends Error { + /** HTTP status code */ + public readonly statusCode: number; + /** HTTP body */ + public readonly body: string; + /** HTTP headers */ + public readonly headers: Headers; + /** HTTP content type */ + public readonly contentType: string; + /** Raw response */ + public readonly rawResponse: Response; + + constructor( + message: string, + httpMeta: { + response: Response; + request: Request; + body: string; + }, + ) { + super(message); + this.statusCode = httpMeta.response.status; + this.body = httpMeta.body; + this.headers = httpMeta.response.headers; + this.contentType = httpMeta.response.headers.get("content-type") || ""; + this.rawResponse = httpMeta.response; + + this.name = "SDKError"; + } +} diff --git a/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts b/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts index 16929b9e..6826e120 100644 --- a/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts +++ b/frameworks-elysia/sdk-typescript/src/models/errors/sdkvalidationerror.ts @@ -2,7 +2,7 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import * as z from "zod"; +import * as z from "zod/v3"; export class SDKValidationError extends Error { /** @@ -15,6 +15,18 @@ export class SDKValidationError extends Error { */ public readonly rawMessage: unknown; + // Allows for backwards compatibility for `instanceof` checks of `ResponseValidationError` + static override [Symbol.hasInstance]( + instance: unknown, + ): instance is SDKValidationError { + if (!(instance instanceof Error)) return false; + if (!("rawValue" in instance)) return false; + if (!("rawMessage" in instance)) return false; + if (!("pretty" in instance)) return false; + if (typeof instance.pretty !== "function") return false; + return true; + } + constructor(message: string, cause: unknown, rawValue: unknown) { super(`${message}: ${cause}`); this.name = "SDKValidationError"; diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/createbooking.ts b/frameworks-elysia/sdk-typescript/src/models/operations/createbooking.ts new file mode 100644 index 00000000..c07601c3 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/createbooking.ts @@ -0,0 +1,123 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +/** + * Booking details. + */ +export type CreateBookingBookingsRequestRequestBody = { + tripId: string; + passengerName: string; + hasBicycle?: boolean | undefined; + hasDog?: boolean | undefined; +}; + +export type CreateBookingLinks = { + self: string; +}; + +/** + * A booking for a train trip. + */ +export type CreateBookingResponseBody = { + id: string; + tripId: string; + passengerName: string; + hasBicycle: boolean; + hasDog: boolean; + links: CreateBookingLinks; +}; + +/** @internal */ +export type CreateBookingBookingsRequestRequestBody$Outbound = { + trip_id: string; + passenger_name: string; + has_bicycle?: boolean | undefined; + has_dog?: boolean | undefined; +}; + +/** @internal */ +export const CreateBookingBookingsRequestRequestBody$outboundSchema: z.ZodType< + CreateBookingBookingsRequestRequestBody$Outbound, + z.ZodTypeDef, + CreateBookingBookingsRequestRequestBody +> = z.object({ + tripId: z.string(), + passengerName: z.string(), + hasBicycle: z.boolean().optional(), + hasDog: z.boolean().optional(), +}).transform((v) => { + return remap$(v, { + tripId: "trip_id", + passengerName: "passenger_name", + hasBicycle: "has_bicycle", + hasDog: "has_dog", + }); +}); + +export function createBookingBookingsRequestRequestBodyToJSON( + createBookingBookingsRequestRequestBody: + CreateBookingBookingsRequestRequestBody, +): string { + return JSON.stringify( + CreateBookingBookingsRequestRequestBody$outboundSchema.parse( + createBookingBookingsRequestRequestBody, + ), + ); +} + +/** @internal */ +export const CreateBookingLinks$inboundSchema: z.ZodType< + CreateBookingLinks, + z.ZodTypeDef, + unknown +> = z.object({ + self: z.string(), +}); + +export function createBookingLinksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => CreateBookingLinks$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingLinks' from JSON`, + ); +} + +/** @internal */ +export const CreateBookingResponseBody$inboundSchema: z.ZodType< + CreateBookingResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + trip_id: z.string(), + passenger_name: z.string(), + has_bicycle: z.boolean(), + has_dog: z.boolean(), + links: z.lazy(() => CreateBookingLinks$inboundSchema), +}).transform((v) => { + return remap$(v, { + "trip_id": "tripId", + "passenger_name": "passengerName", + "has_bicycle": "hasBicycle", + "has_dog": "hasDog", + }); +}); + +export function createBookingResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => CreateBookingResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/createbookingpayment.ts b/frameworks-elysia/sdk-typescript/src/models/operations/createbookingpayment.ts new file mode 100644 index 00000000..d17d7f95 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/createbookingpayment.ts @@ -0,0 +1,468 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { ClosedEnum } from "../../types/enums.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export const CreateBookingPaymentPaymentsCurrency = { + Bam: "bam", + Bgn: "bgn", + Chf: "chf", + Eur: "eur", + Gbp: "gbp", + Nok: "nok", + Sek: "sek", +} as const; +export type CreateBookingPaymentPaymentsCurrency = ClosedEnum< + typeof CreateBookingPaymentPaymentsCurrency +>; + +export const CreateBookingPaymentSourceAccountType = { + Individual: "individual", + Company: "company", +} as const; +export type CreateBookingPaymentSourceAccountType = ClosedEnum< + typeof CreateBookingPaymentSourceAccountType +>; + +export type CreateBookingPaymentSource2 = { + object: "bank_account"; + name: string; + number: string; + sortCode?: string | undefined; + accountType: CreateBookingPaymentSourceAccountType; + bankName: string; + country: string; +}; + +export type CreateBookingPaymentSource1 = { + object: "card"; + name: string; + number: string; + cvc: string; + expMonth: number; + expYear: number; + addressCountry: string; + addressPostCode?: string | undefined; +}; + +export type CreateBookingPaymentPaymentsSource = + | CreateBookingPaymentSource1 + | CreateBookingPaymentSource2; + +export type CreateBookingPaymentPaymentsRequestRequestBody = { + amount: number; + currency: CreateBookingPaymentPaymentsCurrency; + promoCode?: string | null | undefined; + source: CreateBookingPaymentSource1 | CreateBookingPaymentSource2; +}; + +export type CreateBookingPaymentRequest = { + bookingId: string; + requestBody: CreateBookingPaymentPaymentsRequestRequestBody; +}; + +export const CreateBookingPaymentSourcePaymentsAccountType = { + Individual: "individual", + Company: "company", +} as const; +export type CreateBookingPaymentSourcePaymentsAccountType = ClosedEnum< + typeof CreateBookingPaymentSourcePaymentsAccountType +>; + +export type CreateBookingPaymentSourcePayments2 = { + object: "bank_account"; + name: string; + number: string; + sortCode?: string | undefined; + accountType: CreateBookingPaymentSourcePaymentsAccountType; + bankName: string; + country: string; +}; + +export type CreateBookingPaymentSourcePayments1 = { + object: "card"; + name: string; + number: string; + cvc: string; + expMonth: number; + expYear: number; + addressCountry: string; + addressPostCode?: string | undefined; +}; + +export type CreateBookingPaymentPaymentsResponseSource = + | CreateBookingPaymentSourcePayments1 + | CreateBookingPaymentSourcePayments2; + +export const Status = { + Pending: "pending", + Succeeded: "succeeded", + Failed: "failed", +} as const; +export type Status = ClosedEnum; + +export type CreateBookingPaymentLinks = { + booking: string; +}; + +/** + * Payment successful + */ +export type CreateBookingPaymentResponseBody = { + id: string; + amount: number; + currency: string; + source: + | CreateBookingPaymentSourcePayments1 + | CreateBookingPaymentSourcePayments2; + status: Status; + links: CreateBookingPaymentLinks; +}; + +/** @internal */ +export const CreateBookingPaymentPaymentsCurrency$outboundSchema: + z.ZodNativeEnum = z.nativeEnum( + CreateBookingPaymentPaymentsCurrency, + ); + +/** @internal */ +export const CreateBookingPaymentSourceAccountType$outboundSchema: + z.ZodNativeEnum = z.nativeEnum( + CreateBookingPaymentSourceAccountType, + ); + +/** @internal */ +export type CreateBookingPaymentSource2$Outbound = { + object: "bank_account"; + name: string; + number: string; + sort_code?: string | undefined; + account_type: string; + bank_name: string; + country: string; +}; + +/** @internal */ +export const CreateBookingPaymentSource2$outboundSchema: z.ZodType< + CreateBookingPaymentSource2$Outbound, + z.ZodTypeDef, + CreateBookingPaymentSource2 +> = z.object({ + object: z.literal("bank_account"), + name: z.string(), + number: z.string(), + sortCode: z.string().optional(), + accountType: CreateBookingPaymentSourceAccountType$outboundSchema, + bankName: z.string(), + country: z.string(), +}).transform((v) => { + return remap$(v, { + sortCode: "sort_code", + accountType: "account_type", + bankName: "bank_name", + }); +}); + +export function createBookingPaymentSource2ToJSON( + createBookingPaymentSource2: CreateBookingPaymentSource2, +): string { + return JSON.stringify( + CreateBookingPaymentSource2$outboundSchema.parse( + createBookingPaymentSource2, + ), + ); +} + +/** @internal */ +export type CreateBookingPaymentSource1$Outbound = { + object: "card"; + name: string; + number: string; + cvc: string; + exp_month: number; + exp_year: number; + address_country: string; + address_post_code?: string | undefined; +}; + +/** @internal */ +export const CreateBookingPaymentSource1$outboundSchema: z.ZodType< + CreateBookingPaymentSource1$Outbound, + z.ZodTypeDef, + CreateBookingPaymentSource1 +> = z.object({ + object: z.literal("card"), + name: z.string(), + number: z.string(), + cvc: z.string(), + expMonth: z.number(), + expYear: z.number(), + addressCountry: z.string(), + addressPostCode: z.string().optional(), +}).transform((v) => { + return remap$(v, { + expMonth: "exp_month", + expYear: "exp_year", + addressCountry: "address_country", + addressPostCode: "address_post_code", + }); +}); + +export function createBookingPaymentSource1ToJSON( + createBookingPaymentSource1: CreateBookingPaymentSource1, +): string { + return JSON.stringify( + CreateBookingPaymentSource1$outboundSchema.parse( + createBookingPaymentSource1, + ), + ); +} + +/** @internal */ +export type CreateBookingPaymentPaymentsSource$Outbound = + | CreateBookingPaymentSource1$Outbound + | CreateBookingPaymentSource2$Outbound; + +/** @internal */ +export const CreateBookingPaymentPaymentsSource$outboundSchema: z.ZodType< + CreateBookingPaymentPaymentsSource$Outbound, + z.ZodTypeDef, + CreateBookingPaymentPaymentsSource +> = z.union([ + z.lazy(() => CreateBookingPaymentSource1$outboundSchema), + z.lazy(() => CreateBookingPaymentSource2$outboundSchema), +]); + +export function createBookingPaymentPaymentsSourceToJSON( + createBookingPaymentPaymentsSource: CreateBookingPaymentPaymentsSource, +): string { + return JSON.stringify( + CreateBookingPaymentPaymentsSource$outboundSchema.parse( + createBookingPaymentPaymentsSource, + ), + ); +} + +/** @internal */ +export type CreateBookingPaymentPaymentsRequestRequestBody$Outbound = { + amount: number; + currency: string; + promo_code?: string | null | undefined; + source: + | CreateBookingPaymentSource1$Outbound + | CreateBookingPaymentSource2$Outbound; +}; + +/** @internal */ +export const CreateBookingPaymentPaymentsRequestRequestBody$outboundSchema: + z.ZodType< + CreateBookingPaymentPaymentsRequestRequestBody$Outbound, + z.ZodTypeDef, + CreateBookingPaymentPaymentsRequestRequestBody + > = z.object({ + amount: z.number(), + currency: CreateBookingPaymentPaymentsCurrency$outboundSchema, + promoCode: z.nullable(z.string()).optional(), + source: z.union([ + z.lazy(() => CreateBookingPaymentSource1$outboundSchema), + z.lazy(() => CreateBookingPaymentSource2$outboundSchema), + ]), + }).transform((v) => { + return remap$(v, { + promoCode: "promo_code", + }); + }); + +export function createBookingPaymentPaymentsRequestRequestBodyToJSON( + createBookingPaymentPaymentsRequestRequestBody: + CreateBookingPaymentPaymentsRequestRequestBody, +): string { + return JSON.stringify( + CreateBookingPaymentPaymentsRequestRequestBody$outboundSchema.parse( + createBookingPaymentPaymentsRequestRequestBody, + ), + ); +} + +/** @internal */ +export type CreateBookingPaymentRequest$Outbound = { + bookingId: string; + RequestBody: CreateBookingPaymentPaymentsRequestRequestBody$Outbound; +}; + +/** @internal */ +export const CreateBookingPaymentRequest$outboundSchema: z.ZodType< + CreateBookingPaymentRequest$Outbound, + z.ZodTypeDef, + CreateBookingPaymentRequest +> = z.object({ + bookingId: z.string(), + requestBody: z.lazy(() => + CreateBookingPaymentPaymentsRequestRequestBody$outboundSchema + ), +}).transform((v) => { + return remap$(v, { + requestBody: "RequestBody", + }); +}); + +export function createBookingPaymentRequestToJSON( + createBookingPaymentRequest: CreateBookingPaymentRequest, +): string { + return JSON.stringify( + CreateBookingPaymentRequest$outboundSchema.parse( + createBookingPaymentRequest, + ), + ); +} + +/** @internal */ +export const CreateBookingPaymentSourcePaymentsAccountType$inboundSchema: + z.ZodNativeEnum = z + .nativeEnum(CreateBookingPaymentSourcePaymentsAccountType); + +/** @internal */ +export const CreateBookingPaymentSourcePayments2$inboundSchema: z.ZodType< + CreateBookingPaymentSourcePayments2, + z.ZodTypeDef, + unknown +> = z.object({ + object: z.literal("bank_account"), + name: z.string(), + number: z.string(), + sort_code: z.string().optional(), + account_type: CreateBookingPaymentSourcePaymentsAccountType$inboundSchema, + bank_name: z.string(), + country: z.string(), +}).transform((v) => { + return remap$(v, { + "sort_code": "sortCode", + "account_type": "accountType", + "bank_name": "bankName", + }); +}); + +export function createBookingPaymentSourcePayments2FromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => + CreateBookingPaymentSourcePayments2$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingPaymentSourcePayments2' from JSON`, + ); +} + +/** @internal */ +export const CreateBookingPaymentSourcePayments1$inboundSchema: z.ZodType< + CreateBookingPaymentSourcePayments1, + z.ZodTypeDef, + unknown +> = z.object({ + object: z.literal("card"), + name: z.string(), + number: z.string(), + cvc: z.string(), + exp_month: z.number(), + exp_year: z.number(), + address_country: z.string(), + address_post_code: z.string().optional(), +}).transform((v) => { + return remap$(v, { + "exp_month": "expMonth", + "exp_year": "expYear", + "address_country": "addressCountry", + "address_post_code": "addressPostCode", + }); +}); + +export function createBookingPaymentSourcePayments1FromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => + CreateBookingPaymentSourcePayments1$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingPaymentSourcePayments1' from JSON`, + ); +} + +/** @internal */ +export const CreateBookingPaymentPaymentsResponseSource$inboundSchema: + z.ZodType = + z.union([ + z.lazy(() => CreateBookingPaymentSourcePayments1$inboundSchema), + z.lazy(() => CreateBookingPaymentSourcePayments2$inboundSchema), + ]); + +export function createBookingPaymentPaymentsResponseSourceFromJSON( + jsonString: string, +): SafeParseResult< + CreateBookingPaymentPaymentsResponseSource, + SDKValidationError +> { + return safeParse( + jsonString, + (x) => + CreateBookingPaymentPaymentsResponseSource$inboundSchema.parse( + JSON.parse(x), + ), + `Failed to parse 'CreateBookingPaymentPaymentsResponseSource' from JSON`, + ); +} + +/** @internal */ +export const Status$inboundSchema: z.ZodNativeEnum = z + .nativeEnum(Status); + +/** @internal */ +export const CreateBookingPaymentLinks$inboundSchema: z.ZodType< + CreateBookingPaymentLinks, + z.ZodTypeDef, + unknown +> = z.object({ + booking: z.string(), +}); + +export function createBookingPaymentLinksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => CreateBookingPaymentLinks$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingPaymentLinks' from JSON`, + ); +} + +/** @internal */ +export const CreateBookingPaymentResponseBody$inboundSchema: z.ZodType< + CreateBookingPaymentResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + amount: z.number(), + currency: z.string(), + source: z.union([ + z.lazy(() => CreateBookingPaymentSourcePayments1$inboundSchema), + z.lazy(() => CreateBookingPaymentSourcePayments2$inboundSchema), + ]), + status: Status$inboundSchema, + links: z.lazy(() => CreateBookingPaymentLinks$inboundSchema), +}); + +export function createBookingPaymentResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => CreateBookingPaymentResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'CreateBookingPaymentResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/deletebooking.ts b/frameworks-elysia/sdk-typescript/src/models/operations/deletebooking.ts new file mode 100644 index 00000000..a6b04310 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/deletebooking.ts @@ -0,0 +1,31 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; + +export type DeleteBookingRequest = { + bookingId: string; +}; + +/** @internal */ +export type DeleteBookingRequest$Outbound = { + bookingId: string; +}; + +/** @internal */ +export const DeleteBookingRequest$outboundSchema: z.ZodType< + DeleteBookingRequest$Outbound, + z.ZodTypeDef, + DeleteBookingRequest +> = z.object({ + bookingId: z.string(), +}); + +export function deleteBookingRequestToJSON( + deleteBookingRequest: DeleteBookingRequest, +): string { + return JSON.stringify( + DeleteBookingRequest$outboundSchema.parse(deleteBookingRequest), + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts deleted file mode 100644 index a28e9218..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/operations/deleteusersbyid.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type DeleteUsersByIdRequest = { - id: string; -}; - -/** @internal */ -export const DeleteUsersByIdRequest$inboundSchema: z.ZodType< - DeleteUsersByIdRequest, - z.ZodTypeDef, - unknown -> = z.object({ - id: z.string(), -}); - -/** @internal */ -export type DeleteUsersByIdRequest$Outbound = { - id: string; -}; - -/** @internal */ -export const DeleteUsersByIdRequest$outboundSchema: z.ZodType< - DeleteUsersByIdRequest$Outbound, - z.ZodTypeDef, - DeleteUsersByIdRequest -> = z.object({ - id: z.string(), -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace DeleteUsersByIdRequest$ { - /** @deprecated use `DeleteUsersByIdRequest$inboundSchema` instead. */ - export const inboundSchema = DeleteUsersByIdRequest$inboundSchema; - /** @deprecated use `DeleteUsersByIdRequest$outboundSchema` instead. */ - export const outboundSchema = DeleteUsersByIdRequest$outboundSchema; - /** @deprecated use `DeleteUsersByIdRequest$Outbound` instead. */ - export type Outbound = DeleteUsersByIdRequest$Outbound; -} - -export function deleteUsersByIdRequestToJSON( - deleteUsersByIdRequest: DeleteUsersByIdRequest, -): string { - return JSON.stringify( - DeleteUsersByIdRequest$outboundSchema.parse(deleteUsersByIdRequest), - ); -} - -export function deleteUsersByIdRequestFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => DeleteUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'DeleteUsersByIdRequest' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/getbooking.ts b/frameworks-elysia/sdk-typescript/src/models/operations/getbooking.ts new file mode 100644 index 00000000..0e87d118 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/getbooking.ts @@ -0,0 +1,101 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type GetBookingRequest = { + bookingId: string; +}; + +export type GetBookingLinks = { + self: string; +}; + +/** + * A booking for a train trip. + */ +export type GetBookingResponseBody = { + id: string; + tripId: string; + passengerName: string; + hasBicycle: boolean; + hasDog: boolean; + links: GetBookingLinks; +}; + +/** @internal */ +export type GetBookingRequest$Outbound = { + bookingId: string; +}; + +/** @internal */ +export const GetBookingRequest$outboundSchema: z.ZodType< + GetBookingRequest$Outbound, + z.ZodTypeDef, + GetBookingRequest +> = z.object({ + bookingId: z.string(), +}); + +export function getBookingRequestToJSON( + getBookingRequest: GetBookingRequest, +): string { + return JSON.stringify( + GetBookingRequest$outboundSchema.parse(getBookingRequest), + ); +} + +/** @internal */ +export const GetBookingLinks$inboundSchema: z.ZodType< + GetBookingLinks, + z.ZodTypeDef, + unknown +> = z.object({ + self: z.string(), +}); + +export function getBookingLinksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetBookingLinks$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetBookingLinks' from JSON`, + ); +} + +/** @internal */ +export const GetBookingResponseBody$inboundSchema: z.ZodType< + GetBookingResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + trip_id: z.string(), + passenger_name: z.string(), + has_bicycle: z.boolean(), + has_dog: z.boolean(), + links: z.lazy(() => GetBookingLinks$inboundSchema), +}).transform((v) => { + return remap$(v, { + "trip_id": "tripId", + "passenger_name": "passengerName", + "has_bicycle": "hasBicycle", + "has_dog": "hasDog", + }); +}); + +export function getBookingResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetBookingResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetBookingResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/getbookings.ts b/frameworks-elysia/sdk-typescript/src/models/operations/getbookings.ts new file mode 100644 index 00000000..d6173b7b --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/getbookings.ts @@ -0,0 +1,134 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type GetBookingsRequest = { + page?: number | undefined; + limit?: number | undefined; +}; + +/** + * A booking for a train trip. + */ +export type GetBookingsData = { + id: string; + tripId: string; + passengerName: string; + hasBicycle: boolean; + hasDog: boolean; +}; + +export type GetBookingsLinks = { + self: string; + next?: string | undefined; + prev?: string | undefined; +}; + +/** + * A list of bookings + */ +export type GetBookingsResponseBody = { + data: Array; + links: GetBookingsLinks; +}; + +/** @internal */ +export type GetBookingsRequest$Outbound = { + page: number; + limit: number; +}; + +/** @internal */ +export const GetBookingsRequest$outboundSchema: z.ZodType< + GetBookingsRequest$Outbound, + z.ZodTypeDef, + GetBookingsRequest +> = z.object({ + page: z.number().default(1), + limit: z.number().default(10), +}); + +export function getBookingsRequestToJSON( + getBookingsRequest: GetBookingsRequest, +): string { + return JSON.stringify( + GetBookingsRequest$outboundSchema.parse(getBookingsRequest), + ); +} + +/** @internal */ +export const GetBookingsData$inboundSchema: z.ZodType< + GetBookingsData, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + trip_id: z.string(), + passenger_name: z.string(), + has_bicycle: z.boolean(), + has_dog: z.boolean(), +}).transform((v) => { + return remap$(v, { + "trip_id": "tripId", + "passenger_name": "passengerName", + "has_bicycle": "hasBicycle", + "has_dog": "hasDog", + }); +}); + +export function getBookingsDataFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetBookingsData$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetBookingsData' from JSON`, + ); +} + +/** @internal */ +export const GetBookingsLinks$inboundSchema: z.ZodType< + GetBookingsLinks, + z.ZodTypeDef, + unknown +> = z.object({ + self: z.string(), + next: z.string().optional(), + prev: z.string().optional(), +}); + +export function getBookingsLinksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetBookingsLinks$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetBookingsLinks' from JSON`, + ); +} + +/** @internal */ +export const GetBookingsResponseBody$inboundSchema: z.ZodType< + GetBookingsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + data: z.array(z.lazy(() => GetBookingsData$inboundSchema)), + links: z.lazy(() => GetBookingsLinks$inboundSchema), +}); + +export function getBookingsResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetBookingsResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetBookingsResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/getstations.ts b/frameworks-elysia/sdk-typescript/src/models/operations/getstations.ts new file mode 100644 index 00000000..fab7696c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/getstations.ts @@ -0,0 +1,134 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type GetStationsRequest = { + page?: number | undefined; + limit?: number | undefined; + coordinates?: string | undefined; + search?: string | undefined; + country?: string | undefined; +}; + +/** + * A train station. + */ +export type Data = { + id: string; + name: string; + address: string; + countryCode: string; + timezone: string; +}; + +export type Links = { + self: string; + next?: string | undefined; + prev?: string | undefined; +}; + +/** + * OK + */ +export type GetStationsResponseBody = { + data: Array; + links: Links; +}; + +/** @internal */ +export type GetStationsRequest$Outbound = { + page: number; + limit: number; + coordinates?: string | undefined; + search?: string | undefined; + country?: string | undefined; +}; + +/** @internal */ +export const GetStationsRequest$outboundSchema: z.ZodType< + GetStationsRequest$Outbound, + z.ZodTypeDef, + GetStationsRequest +> = z.object({ + page: z.number().default(1), + limit: z.number().default(10), + coordinates: z.string().optional(), + search: z.string().optional(), + country: z.string().optional(), +}); + +export function getStationsRequestToJSON( + getStationsRequest: GetStationsRequest, +): string { + return JSON.stringify( + GetStationsRequest$outboundSchema.parse(getStationsRequest), + ); +} + +/** @internal */ +export const Data$inboundSchema: z.ZodType = z + .object({ + id: z.string(), + name: z.string(), + address: z.string(), + country_code: z.string(), + timezone: z.string(), + }).transform((v) => { + return remap$(v, { + "country_code": "countryCode", + }); + }); + +export function dataFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => Data$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'Data' from JSON`, + ); +} + +/** @internal */ +export const Links$inboundSchema: z.ZodType = z + .object({ + self: z.string(), + next: z.string().optional(), + prev: z.string().optional(), + }); + +export function linksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => Links$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'Links' from JSON`, + ); +} + +/** @internal */ +export const GetStationsResponseBody$inboundSchema: z.ZodType< + GetStationsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + data: z.array(z.lazy(() => Data$inboundSchema)), + links: z.lazy(() => Links$inboundSchema), +}); + +export function getStationsResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetStationsResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetStationsResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/gettrips.ts b/frameworks-elysia/sdk-typescript/src/models/operations/gettrips.ts new file mode 100644 index 00000000..d0b4c2c3 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/models/operations/gettrips.ts @@ -0,0 +1,159 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod/v3"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type GetTripsRequest = { + page?: number | undefined; + limit?: number | undefined; + origin: string; + destination: string; + date: Date; + bicycles?: boolean | undefined; + dogs?: boolean | undefined; +}; + +/** + * A train trip. + */ +export type GetTripsData = { + id: string; + origin: string; + destination: string; + departureTime: Date; + arrivalTime: Date; + operator: string; + price: number; + bicyclesAllowed: boolean; + dogsAllowed: boolean; +}; + +export type GetTripsLinks = { + self: string; + next?: string | undefined; + prev?: string | undefined; +}; + +/** + * A list of available train trips + */ +export type GetTripsResponseBody = { + data: Array; + links: GetTripsLinks; +}; + +/** @internal */ +export type GetTripsRequest$Outbound = { + page: number; + limit: number; + origin: string; + destination: string; + date: string; + bicycles: boolean; + dogs: boolean; +}; + +/** @internal */ +export const GetTripsRequest$outboundSchema: z.ZodType< + GetTripsRequest$Outbound, + z.ZodTypeDef, + GetTripsRequest +> = z.object({ + page: z.number().default(1), + limit: z.number().default(10), + origin: z.string(), + destination: z.string(), + date: z.date().transform(v => v.toISOString()), + bicycles: z.boolean().default(false), + dogs: z.boolean().default(false), +}); + +export function getTripsRequestToJSON( + getTripsRequest: GetTripsRequest, +): string { + return JSON.stringify(GetTripsRequest$outboundSchema.parse(getTripsRequest)); +} + +/** @internal */ +export const GetTripsData$inboundSchema: z.ZodType< + GetTripsData, + z.ZodTypeDef, + unknown +> = z.object({ + id: z.string(), + origin: z.string(), + destination: z.string(), + departure_time: z.string().datetime({ offset: true }).transform(v => + new Date(v) + ), + arrival_time: z.string().datetime({ offset: true }).transform(v => + new Date(v) + ), + operator: z.string(), + price: z.number(), + bicycles_allowed: z.boolean(), + dogs_allowed: z.boolean(), +}).transform((v) => { + return remap$(v, { + "departure_time": "departureTime", + "arrival_time": "arrivalTime", + "bicycles_allowed": "bicyclesAllowed", + "dogs_allowed": "dogsAllowed", + }); +}); + +export function getTripsDataFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetTripsData$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetTripsData' from JSON`, + ); +} + +/** @internal */ +export const GetTripsLinks$inboundSchema: z.ZodType< + GetTripsLinks, + z.ZodTypeDef, + unknown +> = z.object({ + self: z.string(), + next: z.string().optional(), + prev: z.string().optional(), +}); + +export function getTripsLinksFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetTripsLinks$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetTripsLinks' from JSON`, + ); +} + +/** @internal */ +export const GetTripsResponseBody$inboundSchema: z.ZodType< + GetTripsResponseBody, + z.ZodTypeDef, + unknown +> = z.object({ + data: z.array(z.lazy(() => GetTripsData$inboundSchema)), + links: z.lazy(() => GetTripsLinks$inboundSchema), +}); + +export function getTripsResponseBodyFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetTripsResponseBody$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetTripsResponseBody' from JSON`, + ); +} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts deleted file mode 100644 index d6c88a1c..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/operations/getusersbyid.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type GetUsersByIdRequest = { - id: string; -}; - -/** @internal */ -export const GetUsersByIdRequest$inboundSchema: z.ZodType< - GetUsersByIdRequest, - z.ZodTypeDef, - unknown -> = z.object({ - id: z.string(), -}); - -/** @internal */ -export type GetUsersByIdRequest$Outbound = { - id: string; -}; - -/** @internal */ -export const GetUsersByIdRequest$outboundSchema: z.ZodType< - GetUsersByIdRequest$Outbound, - z.ZodTypeDef, - GetUsersByIdRequest -> = z.object({ - id: z.string(), -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace GetUsersByIdRequest$ { - /** @deprecated use `GetUsersByIdRequest$inboundSchema` instead. */ - export const inboundSchema = GetUsersByIdRequest$inboundSchema; - /** @deprecated use `GetUsersByIdRequest$outboundSchema` instead. */ - export const outboundSchema = GetUsersByIdRequest$outboundSchema; - /** @deprecated use `GetUsersByIdRequest$Outbound` instead. */ - export type Outbound = GetUsersByIdRequest$Outbound; -} - -export function getUsersByIdRequestToJSON( - getUsersByIdRequest: GetUsersByIdRequest, -): string { - return JSON.stringify( - GetUsersByIdRequest$outboundSchema.parse(getUsersByIdRequest), - ); -} - -export function getUsersByIdRequestFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => GetUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'GetUsersByIdRequest' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/index.ts b/frameworks-elysia/sdk-typescript/src/models/operations/index.ts index 83476b75..638d1f90 100644 --- a/frameworks-elysia/sdk-typescript/src/models/operations/index.ts +++ b/frameworks-elysia/sdk-typescript/src/models/operations/index.ts @@ -2,7 +2,10 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -export * from "./deleteusersbyid.js"; -export * from "./getusersbyid.js"; -export * from "./patchusersbyid.js"; -export * from "./postusers.js"; +export * from "./createbooking.js"; +export * from "./createbookingpayment.js"; +export * from "./deletebooking.js"; +export * from "./getbooking.js"; +export * from "./getbookings.js"; +export * from "./getstations.js"; +export * from "./gettrips.js"; diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts b/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts deleted file mode 100644 index 0513699b..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/operations/patchusersbyid.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { remap as remap$ } from "../../lib/primitives.js"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type PatchUsersByIdRequestBody = { - name?: string | undefined; - age?: number | undefined; -}; - -export type PatchUsersByIdRequest = { - id: string; - requestBody: PatchUsersByIdRequestBody; -}; - -/** @internal */ -export const PatchUsersByIdRequestBody$inboundSchema: z.ZodType< - PatchUsersByIdRequestBody, - z.ZodTypeDef, - unknown -> = z.object({ - name: z.string().optional(), - age: z.number().optional(), -}); - -/** @internal */ -export type PatchUsersByIdRequestBody$Outbound = { - name?: string | undefined; - age?: number | undefined; -}; - -/** @internal */ -export const PatchUsersByIdRequestBody$outboundSchema: z.ZodType< - PatchUsersByIdRequestBody$Outbound, - z.ZodTypeDef, - PatchUsersByIdRequestBody -> = z.object({ - name: z.string().optional(), - age: z.number().optional(), -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace PatchUsersByIdRequestBody$ { - /** @deprecated use `PatchUsersByIdRequestBody$inboundSchema` instead. */ - export const inboundSchema = PatchUsersByIdRequestBody$inboundSchema; - /** @deprecated use `PatchUsersByIdRequestBody$outboundSchema` instead. */ - export const outboundSchema = PatchUsersByIdRequestBody$outboundSchema; - /** @deprecated use `PatchUsersByIdRequestBody$Outbound` instead. */ - export type Outbound = PatchUsersByIdRequestBody$Outbound; -} - -export function patchUsersByIdRequestBodyToJSON( - patchUsersByIdRequestBody: PatchUsersByIdRequestBody, -): string { - return JSON.stringify( - PatchUsersByIdRequestBody$outboundSchema.parse(patchUsersByIdRequestBody), - ); -} - -export function patchUsersByIdRequestBodyFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => PatchUsersByIdRequestBody$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'PatchUsersByIdRequestBody' from JSON`, - ); -} - -/** @internal */ -export const PatchUsersByIdRequest$inboundSchema: z.ZodType< - PatchUsersByIdRequest, - z.ZodTypeDef, - unknown -> = z.object({ - id: z.string(), - RequestBody: z.lazy(() => PatchUsersByIdRequestBody$inboundSchema), -}).transform((v) => { - return remap$(v, { - "RequestBody": "requestBody", - }); -}); - -/** @internal */ -export type PatchUsersByIdRequest$Outbound = { - id: string; - RequestBody: PatchUsersByIdRequestBody$Outbound; -}; - -/** @internal */ -export const PatchUsersByIdRequest$outboundSchema: z.ZodType< - PatchUsersByIdRequest$Outbound, - z.ZodTypeDef, - PatchUsersByIdRequest -> = z.object({ - id: z.string(), - requestBody: z.lazy(() => PatchUsersByIdRequestBody$outboundSchema), -}).transform((v) => { - return remap$(v, { - requestBody: "RequestBody", - }); -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace PatchUsersByIdRequest$ { - /** @deprecated use `PatchUsersByIdRequest$inboundSchema` instead. */ - export const inboundSchema = PatchUsersByIdRequest$inboundSchema; - /** @deprecated use `PatchUsersByIdRequest$outboundSchema` instead. */ - export const outboundSchema = PatchUsersByIdRequest$outboundSchema; - /** @deprecated use `PatchUsersByIdRequest$Outbound` instead. */ - export type Outbound = PatchUsersByIdRequest$Outbound; -} - -export function patchUsersByIdRequestToJSON( - patchUsersByIdRequest: PatchUsersByIdRequest, -): string { - return JSON.stringify( - PatchUsersByIdRequest$outboundSchema.parse(patchUsersByIdRequest), - ); -} - -export function patchUsersByIdRequestFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => PatchUsersByIdRequest$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'PatchUsersByIdRequest' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts b/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts deleted file mode 100644 index 5a077b17..00000000 --- a/frameworks-elysia/sdk-typescript/src/models/operations/postusers.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import * as z from "zod"; -import { safeParse } from "../../lib/schemas.js"; -import { Result as SafeParseResult } from "../../types/fp.js"; -import { SDKValidationError } from "../errors/sdkvalidationerror.js"; - -export type PostUsersRequestBody = { - name: string; - age: number; -}; - -/** @internal */ -export const PostUsersRequestBody$inboundSchema: z.ZodType< - PostUsersRequestBody, - z.ZodTypeDef, - unknown -> = z.object({ - name: z.string(), - age: z.number(), -}); - -/** @internal */ -export type PostUsersRequestBody$Outbound = { - name: string; - age: number; -}; - -/** @internal */ -export const PostUsersRequestBody$outboundSchema: z.ZodType< - PostUsersRequestBody$Outbound, - z.ZodTypeDef, - PostUsersRequestBody -> = z.object({ - name: z.string(), - age: z.number(), -}); - -/** - * @internal - * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. - */ -export namespace PostUsersRequestBody$ { - /** @deprecated use `PostUsersRequestBody$inboundSchema` instead. */ - export const inboundSchema = PostUsersRequestBody$inboundSchema; - /** @deprecated use `PostUsersRequestBody$outboundSchema` instead. */ - export const outboundSchema = PostUsersRequestBody$outboundSchema; - /** @deprecated use `PostUsersRequestBody$Outbound` instead. */ - export type Outbound = PostUsersRequestBody$Outbound; -} - -export function postUsersRequestBodyToJSON( - postUsersRequestBody: PostUsersRequestBody, -): string { - return JSON.stringify( - PostUsersRequestBody$outboundSchema.parse(postUsersRequestBody), - ); -} - -export function postUsersRequestBodyFromJSON( - jsonString: string, -): SafeParseResult { - return safeParse( - jsonString, - (x) => PostUsersRequestBody$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'PostUsersRequestBody' from JSON`, - ); -} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/bookings.ts b/frameworks-elysia/sdk-typescript/src/sdk/bookings.ts new file mode 100644 index 00000000..b48f88bd --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/bookings.ts @@ -0,0 +1,81 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { bookingsCreateBooking } from "../funcs/bookingsCreateBooking.js"; +import { bookingsDeleteBooking } from "../funcs/bookingsDeleteBooking.js"; +import { bookingsGetBooking } from "../funcs/bookingsGetBooking.js"; +import { bookingsGetBookings } from "../funcs/bookingsGetBookings.js"; +import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; + +export class Bookings extends ClientSDK { + /** + * List existing bookings + * + * @remarks + * Returns a list of all trip bookings by the authenticated user. + */ + async getBookings( + request: operations.GetBookingsRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(bookingsGetBookings( + this, + request, + options, + )); + } + + /** + * Create a booking + * + * @remarks + * A booking is a temporary hold on a trip. It is not confirmed until payment is processed. + */ + async createBooking( + request: operations.CreateBookingBookingsRequestRequestBody, + options?: RequestOptions, + ): Promise { + return unwrapAsync(bookingsCreateBooking( + this, + request, + options, + )); + } + + /** + * Get a booking + * + * @remarks + * Returns the details of a specific booking. + */ + async getBooking( + request: operations.GetBookingRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(bookingsGetBooking( + this, + request, + options, + )); + } + + /** + * Delete a booking + * + * @remarks + * Deletes a booking, cancelling the hold on the trip. + */ + async deleteBooking( + request: operations.DeleteBookingRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(bookingsDeleteBooking( + this, + request, + options, + )); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/payments.ts b/frameworks-elysia/sdk-typescript/src/sdk/payments.ts new file mode 100644 index 00000000..07655a17 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/payments.ts @@ -0,0 +1,27 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { paymentsCreateBookingPayment } from "../funcs/paymentsCreateBookingPayment.js"; +import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; + +export class Payments extends ClientSDK { + /** + * Pay for a booking + * + * @remarks + * A payment attempt confirms the booking and enables ticket retrieval. + */ + async createBookingPayment( + request: operations.CreateBookingPaymentRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(paymentsCreateBookingPayment( + this, + request, + options, + )); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts b/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts index e0d3fd62..58446642 100644 --- a/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts +++ b/frameworks-elysia/sdk-typescript/src/sdk/sdk.ts @@ -3,11 +3,29 @@ */ import { ClientSDK } from "../lib/sdks.js"; -import { Users } from "./users.js"; +import { Bookings } from "./bookings.js"; +import { Payments } from "./payments.js"; +import { Stations } from "./stations.js"; +import { Trips } from "./trips.js"; export class SDK extends ClientSDK { - private _users?: Users; - get users(): Users { - return (this._users ??= new Users(this._options)); + private _stations?: Stations; + get stations(): Stations { + return (this._stations ??= new Stations(this._options)); + } + + private _trips?: Trips; + get trips(): Trips { + return (this._trips ??= new Trips(this._options)); + } + + private _bookings?: Bookings; + get bookings(): Bookings { + return (this._bookings ??= new Bookings(this._options)); + } + + private _payments?: Payments; + get payments(): Payments { + return (this._payments ??= new Payments(this._options)); } } diff --git a/frameworks-elysia/sdk-typescript/src/sdk/stations.ts b/frameworks-elysia/sdk-typescript/src/sdk/stations.ts new file mode 100644 index 00000000..5333111e --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/stations.ts @@ -0,0 +1,27 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { stationsGetStations } from "../funcs/stationsGetStations.js"; +import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; + +export class Stations extends ClientSDK { + /** + * Get a list of train stations + * + * @remarks + * Returns a paginated and searchable list of all train stations. + */ + async getStations( + request: operations.GetStationsRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(stationsGetStations( + this, + request, + options, + )); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/trips.ts b/frameworks-elysia/sdk-typescript/src/sdk/trips.ts new file mode 100644 index 00000000..81955925 --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/sdk/trips.ts @@ -0,0 +1,27 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { tripsGetTrips } from "../funcs/tripsGetTrips.js"; +import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; + +export class Trips extends ClientSDK { + /** + * Get available train trips + * + * @remarks + * Returns a list of available train trips between the specified origin and destination stations on the given date. + */ + async getTrips( + request: operations.GetTripsRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(tripsGetTrips( + this, + request, + options, + )); + } +} diff --git a/frameworks-elysia/sdk-typescript/src/sdk/users.ts b/frameworks-elysia/sdk-typescript/src/sdk/users.ts deleted file mode 100644 index aee12068..00000000 --- a/frameworks-elysia/sdk-typescript/src/sdk/users.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. - */ - -import { usersDeleteUsersById } from "../funcs/usersDeleteUsersById.js"; -import { usersGetUsers } from "../funcs/usersGetUsers.js"; -import { usersGetUsersById } from "../funcs/usersGetUsersById.js"; -import { usersPatchUsersById } from "../funcs/usersPatchUsersById.js"; -import { usersPostUsers } from "../funcs/usersPostUsers.js"; -import { ClientSDK, RequestOptions } from "../lib/sdks.js"; -import * as components from "../models/components/index.js"; -import * as operations from "../models/operations/index.js"; -import { unwrapAsync } from "../types/fp.js"; - -export class Users extends ClientSDK { - /** - * Get all users - * - * @remarks - * Get all users from the database - */ - async getUsers( - options?: RequestOptions, - ): Promise> { - return unwrapAsync(usersGetUsers( - this, - options, - )); - } - - /** - * Create user - * - * @remarks - * Add user to the database - */ - async postUsers( - request: operations.PostUsersRequestBody, - options?: RequestOptions, - ): Promise { - return unwrapAsync(usersPostUsers( - this, - request, - options, - )); - } - - /** - * Get user - * - * @remarks - * Get user by id from the database - */ - async getUsersById( - request: operations.GetUsersByIdRequest, - options?: RequestOptions, - ): Promise { - return unwrapAsync(usersGetUsersById( - this, - request, - options, - )); - } - - /** - * Delete user - * - * @remarks - * Delete user by id from the database - */ - async deleteUsersById( - request: operations.DeleteUsersByIdRequest, - options?: RequestOptions, - ): Promise { - return unwrapAsync(usersDeleteUsersById( - this, - request, - options, - )); - } - - /** - * Update user - * - * @remarks - * Update user by id from the database - */ - async patchUsersById( - request: operations.PatchUsersByIdRequest, - options?: RequestOptions, - ): Promise { - return unwrapAsync(usersPatchUsersById( - this, - request, - options, - )); - } -} diff --git a/frameworks-elysia/sdk-typescript/src/types/async.ts b/frameworks-elysia/sdk-typescript/src/types/async.ts new file mode 100644 index 00000000..1543b95c --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/async.ts @@ -0,0 +1,69 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +export type APICall = + | { + status: "complete"; + request: Request; + response: Response; + } + | { + status: "request-error"; + request: Request; + response?: undefined; + } + | { + status: "invalid"; + request?: undefined; + response?: undefined; + }; + +export class APIPromise implements Promise { + readonly #promise: Promise<[T, APICall]>; + #unwrapped: Promise | null; + + readonly [Symbol.toStringTag] = "APIPromise"; + + constructor(p: [T, APICall] | Promise<[T, APICall]>) { + this.#promise = p instanceof Promise ? p : Promise.resolve(p); + this.#unwrapped = p instanceof Promise ? null : Promise.resolve(p[0]); + } + + #getUnwrapped(): Promise { + return (this.#unwrapped ??= this.#promise.then(([value]) => value)); + } + + then( + onfulfilled?: + | ((value: T) => TResult1 | PromiseLike) + | null + | undefined, + onrejected?: + | ((reason: any) => TResult2 | PromiseLike) + | null + | undefined, + ): Promise { + return this.#promise.then( + onfulfilled ? ([value]) => onfulfilled(value) : void 0, + onrejected, + ); + } + + catch( + onrejected?: + | ((reason: any) => TResult | PromiseLike) + | null + | undefined, + ): Promise { + return this.#getUnwrapped().catch(onrejected); + } + + finally(onfinally?: (() => void) | null | undefined): Promise { + return this.#getUnwrapped().finally(onfinally); + } + + $inspect(): Promise<[T, APICall]> { + return this.#promise; + } +} diff --git a/frameworks-elysia/sdk-typescript/src/types/blobs.ts b/frameworks-elysia/sdk-typescript/src/types/blobs.ts index 4ce84602..cce2892d 100644 --- a/frameworks-elysia/sdk-typescript/src/types/blobs.ts +++ b/frameworks-elysia/sdk-typescript/src/types/blobs.ts @@ -2,13 +2,14 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import * as z from "zod"; +import * as z from "zod/v3"; -export const blobLikeSchema: z.ZodType = - z.custom(isBlobLike, { - message: "expected a Blob, File or Blob-like object", - fatal: true, - }); +export const blobLikeSchema: z.ZodType = z.custom< + Blob +>(isBlobLike, { + message: "expected a Blob, File or Blob-like object", + fatal: true, +}); export function isBlobLike(val: unknown): val is Blob { if (val instanceof Blob) { diff --git a/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts b/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts index c0a4409c..fe62144e 100644 --- a/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts +++ b/frameworks-elysia/sdk-typescript/src/types/constdatetime.ts @@ -2,7 +2,7 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import * as z from "zod"; +import * as z from "zod/v3"; export function constDateTime( val: string, @@ -11,5 +11,5 @@ export function constDateTime( return ( typeof v === "string" && new Date(v).getTime() === new Date(val).getTime() ); - }, `Value must be equivelant to ${val}`); + }, `Value must be equivalent to ${val}`); } diff --git a/frameworks-elysia/sdk-typescript/src/types/enums.ts b/frameworks-elysia/sdk-typescript/src/types/enums.ts index 6fb6d910..aba0ffd2 100644 --- a/frameworks-elysia/sdk-typescript/src/types/enums.ts +++ b/frameworks-elysia/sdk-typescript/src/types/enums.ts @@ -2,15 +2,44 @@ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -declare const __brand: unique symbol; -export type Unrecognized = T & { [__brand]: "unrecognized" }; +import * as z from "zod/v3"; +import { Unrecognized, unrecognized } from "./unrecognized.js"; -export function catchUnrecognizedEnum(value: T): Unrecognized { - return value as Unrecognized; +export type ClosedEnum>> = + T[keyof T]; +export type OpenEnum>> = + | T[keyof T] + | Unrecognized; + +export function inboundSchema>( + enumObj: T, +): z.ZodType, z.ZodTypeDef, unknown> { + const options = Object.values(enumObj); + return z.union([ + ...options.map(x => z.literal(x)), + z.string().transform(x => unrecognized(x)), + ] as any); } -type Prettify = { [K in keyof T]: T[K] } & {}; -export type ClosedEnum = T[keyof T]; -export type OpenEnum = - | Prettify - | Unrecognized; +export function inboundSchemaInt>( + enumObj: T, +): z.ZodType, z.ZodTypeDef, unknown> { + // For numeric enums, Object.values returns both numbers and string keys + const options = Object.values(enumObj).filter(v => typeof v === "number"); + return z.union([ + ...options.map(x => z.literal(x)), + z.number().int().transform(x => unrecognized(x)), + ] as any); +} + +export function outboundSchema>( + _: T, +): z.ZodType> { + return z.string() as any; +} + +export function outboundSchemaInt>( + _: T, +): z.ZodType> { + return z.number().int() as any; +} diff --git a/frameworks-elysia/sdk-typescript/src/types/index.ts b/frameworks-elysia/sdk-typescript/src/types/index.ts index e124e817..abf0b7ab 100644 --- a/frameworks-elysia/sdk-typescript/src/types/index.ts +++ b/frameworks-elysia/sdk-typescript/src/types/index.ts @@ -3,9 +3,9 @@ */ export { blobLikeSchema, isBlobLike } from "./blobs.js"; -export { catchUnrecognizedEnum } from "./enums.js"; -export type { ClosedEnum, OpenEnum, Unrecognized } from "./enums.js"; +export type { ClosedEnum, OpenEnum } from "./enums.js"; export type { Result } from "./fp.js"; export type { PageIterator, Paginator } from "./operations.js"; export { createPageIterator } from "./operations.js"; export { RFCDate } from "./rfcdate.js"; +export * from "./unrecognized.js"; diff --git a/frameworks-elysia/sdk-typescript/src/types/unrecognized.ts b/frameworks-elysia/sdk-typescript/src/types/unrecognized.ts new file mode 100644 index 00000000..b7a2a13f --- /dev/null +++ b/frameworks-elysia/sdk-typescript/src/types/unrecognized.ts @@ -0,0 +1,35 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +declare const __brand: unique symbol; +export type Unrecognized = T & { [__brand]: "unrecognized" }; + +function unrecognized(value: T): Unrecognized { + globalCount++; + return value as Unrecognized; +} + +let globalCount = 0; +let refCount = 0; +export function startCountingUnrecognized() { + refCount++; + const start = globalCount; + return { + /** + * Ends counting and returns the delta. + * @param delta - If provided, only this amount is added to the parent counter + * (used for nested unions where we only want to record the winning option's count). + * If not provided, records all counts since start(). + */ + end: (delta?: number) => { + const count = globalCount - start; + // Reset globalCount back to start, then add only the specified delta + globalCount = start + (delta ?? count); + if (--refCount === 0) globalCount = 0; + return count; + }, + }; +} + +export { unrecognized }; diff --git a/frameworks-elysia/sdk-typescript/tsconfig.json b/frameworks-elysia/sdk-typescript/tsconfig.json index f9d286a7..76110f88 100644 --- a/frameworks-elysia/sdk-typescript/tsconfig.json +++ b/frameworks-elysia/sdk-typescript/tsconfig.json @@ -1,8 +1,7 @@ { "compilerOptions": { - "incremental": true, - "tsBuildInfoFile": ".tsbuildinfo", - "target": "ES2018", + "incremental": false, + "target": "ES2020", "lib": ["ES2022", "DOM", "DOM.Iterable"], "jsx": "react-jsx", @@ -14,6 +13,7 @@ "declaration": true, "declarationMap": true, "sourceMap": true, + "rootDir": "src", "outDir": ".", @@ -37,5 +37,5 @@ "forceConsistentCasingInFileNames": true }, "include": ["src"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "src/__tests__"] }