From ac325001aa057e0436af7fdb5abd13b173410513 Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Mon, 12 Aug 2024 08:28:28 +0000 Subject: [PATCH] ci: regenerated with OpenAPI Doc , Speakeasy CLI 1.361.1 --- .speakeasy/gen.yaml | 6 +- .speakeasy/workflow.lock | 12 +- package-lock.json | 2 +- packages/opa/.gitignore | 2 + packages/opa/.speakeasy/gen.lock | 34 +- packages/opa/CONTRIBUTING.md | 26 + packages/opa/README.md | 81 +- packages/opa/RELEASES.md | 10 +- packages/opa/USAGE.md | 7 +- .../docs/sdk/models/components/security.md | 8 + packages/opa/docs/sdks/opaapiclient/README.md | 7 +- packages/opa/jsr.json | 2 +- packages/opa/package.json | 8 +- packages/opa/src/core.ts | 13 + .../src/funcs/executeBatchPolicyWithInput.ts | 162 ++++ .../funcs/executeDefaultPolicyWithInput.ts | 152 ++++ packages/opa/src/funcs/executePolicy.ts | 152 ++++ .../opa/src/funcs/executePolicyWithInput.ts | 158 ++++ packages/opa/src/funcs/health.ts | 141 ++++ packages/opa/src/hooks/hooks.ts | 2 +- packages/opa/src/hooks/index.ts | 2 +- packages/opa/src/hooks/types.ts | 2 +- packages/opa/src/lib/base64.ts | 2 +- packages/opa/src/lib/config.ts | 12 +- packages/opa/src/lib/dlv.ts | 53 ++ packages/opa/src/lib/encodings.ts | 32 +- packages/opa/src/lib/http.ts | 691 +++++++----------- packages/opa/src/lib/is-plain-object.ts | 2 +- packages/opa/src/lib/logger.ts | 9 + packages/opa/src/lib/matchers.ts | 301 ++++++++ packages/opa/src/lib/primitives.ts | 2 +- packages/opa/src/lib/retries.ts | 45 +- packages/opa/src/lib/schemas.ts | 20 +- packages/opa/src/lib/sdks.ts | 218 +++++- packages/opa/src/lib/security.ts | 30 +- packages/opa/src/lib/url.ts | 2 +- packages/opa/src/sdk/index.ts | 2 +- .../models/components/batchmixedresults.ts | 2 +- .../batchsuccessfulpolicyevaluation.ts | 2 +- .../opa/src/sdk/models/components/explain.ts | 2 +- .../models/components/gzipacceptencoding.ts | 2 +- .../models/components/gzipcontentencoding.ts | 2 +- .../sdk/models/components/healthyserver.ts | 2 +- .../src/sdk/models/components/httpmetadata.ts | 2 +- .../opa/src/sdk/models/components/index.ts | 3 +- .../opa/src/sdk/models/components/input.ts | 2 +- .../src/sdk/models/components/provenance.ts | 2 +- .../opa/src/sdk/models/components/result.ts | 2 +- .../opa/src/sdk/models/components/security.ts | 38 + .../components/successfulpolicyresponse.ts | 2 +- .../src/sdk/models/errors/batchservererror.ts | 2 +- .../opa/src/sdk/models/errors/clienterror.ts | 2 +- .../src/sdk/models/errors/httpclienterrors.ts | 62 ++ packages/opa/src/sdk/models/errors/index.ts | 3 +- .../opa/src/sdk/models/errors/sdkerror.ts | 2 +- .../sdk/models/errors/sdkvalidationerror.ts | 16 +- .../opa/src/sdk/models/errors/servererror.ts | 2 +- .../src/sdk/models/errors/unhealthyserver.ts | 2 +- .../operations/executebatchpolicywithinput.ts | 2 +- .../executedefaultpolicywithinput.ts | 2 +- .../sdk/models/operations/executepolicy.ts | 2 +- .../operations/executepolicywithinput.ts | 2 +- .../opa/src/sdk/models/operations/health.ts | 2 +- .../opa/src/sdk/models/operations/index.ts | 2 +- packages/opa/src/sdk/sdk.ts | 403 +--------- packages/opa/src/types/blobs.ts | 2 +- packages/opa/src/types/constdatetime.ts | 15 + packages/opa/src/types/enums.ts | 2 +- packages/opa/src/types/fp.ts | 50 ++ packages/opa/src/types/index.ts | 3 +- packages/opa/src/types/operations.ts | 90 ++- packages/opa/src/types/rfcdate.ts | 2 +- 72 files changed, 2116 insertions(+), 1027 deletions(-) create mode 100644 packages/opa/CONTRIBUTING.md create mode 100644 packages/opa/docs/sdk/models/components/security.md create mode 100644 packages/opa/src/core.ts create mode 100644 packages/opa/src/funcs/executeBatchPolicyWithInput.ts create mode 100644 packages/opa/src/funcs/executeDefaultPolicyWithInput.ts create mode 100644 packages/opa/src/funcs/executePolicy.ts create mode 100644 packages/opa/src/funcs/executePolicyWithInput.ts create mode 100644 packages/opa/src/funcs/health.ts create mode 100644 packages/opa/src/lib/dlv.ts create mode 100644 packages/opa/src/lib/logger.ts create mode 100644 packages/opa/src/lib/matchers.ts create mode 100644 packages/opa/src/sdk/models/components/security.ts create mode 100644 packages/opa/src/sdk/models/errors/httpclienterrors.ts create mode 100644 packages/opa/src/types/constdatetime.ts create mode 100644 packages/opa/src/types/fp.ts diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 58cfa33..bb993bc 100755 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -12,11 +12,11 @@ generation: auth: oAuth2ClientCredentialsEnabled: false typescript: - version: 1.3.0 + version: 1.4.0 additionalDependencies: dependencies: {} devDependencies: - "@types/node": ^20.14.9 + '@types/node': ^20.14.9 eslint-plugin-markdown: ^4.0.1 prettier: 3.2.5 testcontainers: ^10.10.1 @@ -54,7 +54,7 @@ typescript: methodArguments: require-security-and-request moduleFormat: dual outputModelSuffix: output - packageName: "@styra/opa" + packageName: '@styra/opa' responseFormat: envelope-http templateVersion: v2 useIndexModules: true diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index a4bef1f..cf1f65d 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,18 +1,18 @@ -speakeasyVersion: 1.334.0 +speakeasyVersion: 1.361.1 sources: openapi: sourceNamespace: openapi - sourceRevisionDigest: sha256:93669fe964484357296c2154d1c86aef99d8ca473969ee8d70e6710ed0d80ddb - sourceBlobDigest: sha256:bff74eb96d1677dce36fd84c18da761c1a7739ec423eb3eb1bab869e5bf48321 + sourceRevisionDigest: sha256:041a9c6f5a9a2ad11fb0ecb4c958ee21331d4c1df411241715405a481a0842f4 + sourceBlobDigest: sha256:1278b402479d50883b21bc284419cdd247db61f17087a97dd47531b54f0c326c tags: - latest - - main + - dependabot-npm_and_yarn-multi-875484771a targets: first-target: source: openapi sourceNamespace: openapi - sourceRevisionDigest: sha256:93669fe964484357296c2154d1c86aef99d8ca473969ee8d70e6710ed0d80ddb - sourceBlobDigest: sha256:bff74eb96d1677dce36fd84c18da761c1a7739ec423eb3eb1bab869e5bf48321 + sourceRevisionDigest: sha256:041a9c6f5a9a2ad11fb0ecb4c958ee21331d4c1df411241715405a481a0842f4 + sourceBlobDigest: sha256:1278b402479d50883b21bc284419cdd247db61f17087a97dd47531b54f0c326c outLocation: packages/opa workflow: workflowVersion: 1.0.0 diff --git a/package-lock.json b/package-lock.json index 9f3b118..218eba0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9408,7 +9408,7 @@ }, "packages/opa": { "name": "@styra/opa", - "version": "1.3.0", + "version": "1.4.0", "license": "Apache-2.0", "devDependencies": { "@types/node": "^20.14.9", diff --git a/packages/opa/.gitignore b/packages/opa/.gitignore index 6d3207d..de1ad78 100644 --- a/packages/opa/.gitignore +++ b/packages/opa/.gitignore @@ -1,3 +1,5 @@ +/funcs +/core.* /esm /dist /.tshy diff --git a/packages/opa/.speakeasy/gen.lock b/packages/opa/.speakeasy/gen.lock index 7471cdf..c3a50a4 100755 --- a/packages/opa/.speakeasy/gen.lock +++ b/packages/opa/.speakeasy/gen.lock @@ -1,40 +1,52 @@ lockVersion: 2.0.0 id: 078615ff-ff96-44f8-8aca-2f4d3e687bf0 management: - docChecksum: 965922378d3f89a95cf055454ae72ad7 + docChecksum: 553ed43ff98c81b3e770c34850f0b5f5 docVersion: 0.2.0 - speakeasyVersion: 1.334.0 - generationVersion: 2.369.0 - releaseVersion: 1.3.0 - configChecksum: 25eea4d12bca4a64556ebe5572cdafb3 + speakeasyVersion: 1.361.1 + generationVersion: 2.393.4 + releaseVersion: 1.4.0 + configChecksum: 931fe09dabde06c0b0a9d81cf9c8e1da repoURL: https://github.com/StyraInc/opa-typescript.git repoSubDirectory: packages/opa installationURL: https://gitpkg.now.sh/StyraInc/opa-typescript/packages/opa features: typescript: additionalDependencies: 0.1.0 - constsAndDefaults: 0.1.5 - core: 3.11.6 + constsAndDefaults: 0.1.7 + core: 3.13.1 defaultEnabledRetries: 0.1.0 + envVarSecurityUsage: 0.1.1 examples: 2.81.4 flattening: 2.81.1 + globalSecurity: 2.82.11 globalSecurityCallbacks: 0.1.0 + globalSecurityFlattening: 0.1.0 globalServerURLs: 2.82.4 responseFormat: 0.2.3 retries: 2.83.0 sdkHooks: 0.1.0 - unions: 2.85.5 + unions: 2.85.7 generatedFiles: + - src/funcs/executeDefaultPolicyWithInput.ts + - src/funcs/executePolicy.ts + - src/funcs/executePolicyWithInput.ts + - src/funcs/executeBatchPolicyWithInput.ts + - src/funcs/health.ts - src/sdk/sdk.ts - .eslintrc.cjs - RUNTIMES.md - jsr.json - package.json + - src/core.ts - src/lib/base64.ts - src/lib/config.ts + - src/lib/dlv.ts - src/lib/encodings.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 @@ -42,10 +54,13 @@ generatedFiles: - src/lib/security.ts - src/lib/url.ts - src/sdk/index.ts + - src/sdk/models/errors/httpclienterrors.ts - src/sdk/models/errors/sdkerror.ts - src/sdk/models/errors/sdkvalidationerror.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 @@ -66,6 +81,7 @@ generatedFiles: - src/sdk/models/components/batchmixedresults.ts - src/sdk/models/components/batchsuccessfulpolicyevaluation.ts - src/sdk/models/components/healthyserver.ts + - src/sdk/models/components/security.ts - src/sdk/models/errors/clienterror.ts - src/sdk/models/errors/servererror.ts - src/sdk/models/errors/batchservererror.ts @@ -102,6 +118,7 @@ generatedFiles: - docs/sdk/models/components/batchmixedresults.md - docs/sdk/models/components/batchsuccessfulpolicyevaluation.md - docs/sdk/models/components/healthyserver.md + - docs/sdk/models/components/security.md - docs/sdk/models/errors/location.md - docs/sdk/models/errors/errors.md - docs/sdk/models/errors/clienterror.md @@ -117,3 +134,4 @@ generatedFiles: - src/hooks/hooks.ts - src/hooks/types.ts - src/hooks/index.ts + - CONTRIBUTING.md diff --git a/packages/opa/CONTRIBUTING.md b/packages/opa/CONTRIBUTING.md new file mode 100644 index 0000000..d585717 --- /dev/null +++ b/packages/opa/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/packages/opa/README.md b/packages/opa/README.md index de4441d..b338537 100644 --- a/packages/opa/README.md +++ b/packages/opa/README.md @@ -301,28 +301,22 @@ Some of the endpoints in this SDK support retries. If you use the SDK without a To change the default retry strategy for a single API call, simply provide a retryConfig object to the call: ```typescript import { OpaApiClient } from "@styra/opa"; -import { GzipAcceptEncoding } from "@styra/opa/sdk/models/components"; const opaApiClient = new OpaApiClient(); async function run() { - const result = await opaApiClient.executeDefaultPolicyWithInput( - 8203.11, - false, - GzipAcceptEncoding.Gzip, - { - retries: { - strategy: "backoff", - backoff: { - initialInterval: 1, - maxInterval: 50, - exponent: 1.1, - maxElapsedTime: 100, - }, - retryConnectionErrors: false, + const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11, { + retries: { + strategy: "backoff", + backoff: { + initialInterval: 1, + maxInterval: 50, + exponent: 1.1, + maxElapsedTime: 100, }, - } - ); + retryConnectionErrors: false, + }, + }); // Handle the result console.log(result); @@ -335,7 +329,6 @@ 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 { OpaApiClient } from "@styra/opa"; -import { GzipAcceptEncoding } from "@styra/opa/sdk/models/components"; const opaApiClient = new OpaApiClient({ retryConfig: { @@ -351,11 +344,7 @@ const opaApiClient = new OpaApiClient({ }); async function run() { - const result = await opaApiClient.executeDefaultPolicyWithInput( - 8203.11, - false, - GzipAcceptEncoding.Gzip - ); + const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11); // Handle the result console.log(result); @@ -366,6 +355,52 @@ run(); ``` + +## Authentication + +### Per-Client Security Schemes + +This SDK supports the following security scheme globally: + +| Name | Type | Scheme | +| ------------ | ------------ | ------------ | +| `bearerAuth` | http | HTTP Bearer | + +To authenticate with the API the `bearerAuth` parameter must be set when initializing the SDK client instance. For example: +```typescript +import { OpaApiClient } from "@styra/opa"; + +const opaApiClient = new OpaApiClient({ + bearerAuth: "", +}); + +async function run() { + const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11); + + // Handle the result + console.log(result); +} + +run(); + +``` + + + +## Debugging + +To log HTTP 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 { OpaApiClient } from "@styra/opa"; + +const sdk = new OpaApiClient({ debugLogger: console }); +``` + + ## Community diff --git a/packages/opa/RELEASES.md b/packages/opa/RELEASES.md index 9a01bd6..76f8c4c 100644 --- a/packages/opa/RELEASES.md +++ b/packages/opa/RELEASES.md @@ -397,4 +397,12 @@ Based on: - OpenAPI Doc - Speakeasy CLI 1.334.0 (2.369.0) https://github.com/speakeasy-api/speakeasy ### Generated -- [typescript v1.3.0] packages/opa \ No newline at end of file +- [typescript v1.3.0] packages/opa + +## 2024-08-12 08:27:31 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.361.1 (2.393.4) https://github.com/speakeasy-api/speakeasy +### Generated +- [typescript v1.4.0] packages/opa \ No newline at end of file diff --git a/packages/opa/USAGE.md b/packages/opa/USAGE.md index ee4b41f..cc326e6 100644 --- a/packages/opa/USAGE.md +++ b/packages/opa/USAGE.md @@ -1,16 +1,11 @@ ```typescript import { OpaApiClient } from "@styra/opa"; -import { GzipAcceptEncoding } from "@styra/opa/sdk/models/components"; const opaApiClient = new OpaApiClient(); async function run() { - const result = await opaApiClient.executeDefaultPolicyWithInput( - 8203.11, - false, - GzipAcceptEncoding.Gzip - ); + const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11); // Handle the result console.log(result); diff --git a/packages/opa/docs/sdk/models/components/security.md b/packages/opa/docs/sdk/models/components/security.md new file mode 100644 index 0000000..4576e99 --- /dev/null +++ b/packages/opa/docs/sdk/models/components/security.md @@ -0,0 +1,8 @@ +# Security + + +## Fields + +| Field | Type | Required | Description | +| ------------------ | ------------------ | ------------------ | ------------------ | +| `bearerAuth` | *string* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/packages/opa/docs/sdks/opaapiclient/README.md b/packages/opa/docs/sdks/opaapiclient/README.md index 3310a06..10ba838 100644 --- a/packages/opa/docs/sdks/opaapiclient/README.md +++ b/packages/opa/docs/sdks/opaapiclient/README.md @@ -21,12 +21,11 @@ Execute the default decision given an input ```typescript import { OpaApiClient } from "@styra/opa"; -import { GzipAcceptEncoding } from "@styra/opa/sdk/models/components"; const opaApiClient = new OpaApiClient(); async function run() { - const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11, false, GzipAcceptEncoding.Gzip); + const result = await opaApiClient.executeDefaultPolicyWithInput(8203.11); // Handle the result console.log(result) @@ -210,9 +209,7 @@ import { OpaApiClient } from "@styra/opa"; const opaApiClient = new OpaApiClient(); async function run() { - const result = await opaApiClient.health(false, false, [ - "", - ]); + const result = await opaApiClient.health(); // Handle the result console.log(result) diff --git a/packages/opa/jsr.json b/packages/opa/jsr.json index 0e78fc7..ec2c10d 100644 --- a/packages/opa/jsr.json +++ b/packages/opa/jsr.json @@ -2,7 +2,7 @@ { "name": "@styra/opa", - "version": "1.3.0", + "version": "1.4.0", "exports": { ".": "./src/index.ts", "./sdk/models/errors": "./src/sdk/models/errors/index.ts", diff --git a/packages/opa/package.json b/packages/opa/package.json index a9ca2e3..0851a7d 100644 --- a/packages/opa/package.json +++ b/packages/opa/package.json @@ -1,6 +1,6 @@ { "name": "@styra/opa", - "version": "1.3.0", + "version": "1.4.0", "author": "Styra", "license": "Apache-2.0", "publishConfig": { @@ -53,9 +53,9 @@ "testcontainers": "^10.10.1", "tshy": "^1.16.2", "tsx": "^4.16.2", - "typedoc": "^0.25.13", - "typedoc-plugin-extras": "^3.0.0", - "typedoc-plugin-replace-text": "^3.3.0", + "typedoc": "^0.26.5", + "typedoc-plugin-extras": "^3.1.0", + "typedoc-plugin-replace-text": "^4.0.0", "typescript": "^5.4.5", "zod": "^3.23.4" }, diff --git a/packages/opa/src/core.ts b/packages/opa/src/core.ts new file mode 100644 index 0000000..cb31c8e --- /dev/null +++ b/packages/opa/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 OpaApiClientCore extends ClientSDK {} diff --git a/packages/opa/src/funcs/executeBatchPolicyWithInput.ts b/packages/opa/src/funcs/executeBatchPolicyWithInput.ts new file mode 100644 index 0000000..372020a --- /dev/null +++ b/packages/opa/src/funcs/executeBatchPolicyWithInput.ts @@ -0,0 +1,162 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { OpaApiClientCore } from "../core.js"; +import { + encodeFormQuery as encodeFormQuery$, + encodeJSON as encodeJSON$, + encodeSimple as encodeSimple$, +} from "../lib/encodings.js"; +import * as m$ from "../lib/matchers.js"; +import * as schemas$ 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 "../sdk/models/errors/httpclienterrors.js"; +import * as errors from "../sdk/models/errors/index.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import * as operations from "../sdk/models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Execute a policy given a batch of inputs + */ +export async function executeBatchPolicyWithInput( + client$: OpaApiClientCore, + request: operations.ExecuteBatchPolicyWithInputRequest, + options?: RequestOptions +): Promise< + Result< + operations.ExecuteBatchPolicyWithInputResponse, + | errors.ClientError + | errors.BatchServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input$ = request; + + const parsed$ = schemas$.safeParse( + input$, + (value$) => operations.ExecuteBatchPolicyWithInputRequest$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$ = { + path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), + }; + + const path$ = pathToFunc("/v1/batch/data/{path}")(pathParams$); + + const query$ = encodeFormQuery$({ + explain: payload$.explain, + instrument: payload$.instrument, + metrics: payload$.metrics, + pretty: payload$.pretty, + provenance: payload$.provenance, + "strict-builtin-errors": payload$["strict-builtin-errors"], + }); + + const headers$ = new Headers({ + "Content-Type": "application/json", + Accept: "application/json", + "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { + explode: false, + charEncoding: "none", + }), + "Content-Encoding": encodeSimple$("Content-Encoding", payload$["Content-Encoding"], { + explode: false, + charEncoding: "none", + }), + }); + + const bearerAuth$ = await extractSecurity(client$.options$.bearerAuth); + const security$ = bearerAuth$ == null ? {} : { bearerAuth: bearerAuth$ }; + const context = { + operationID: "executeBatchPolicyWithInput", + oAuth2Scopes: [], + securitySource: client$.options$.bearerAuth, + }; + const securitySettings$ = resolveGlobalSecurity(security$); + + const requestRes = client$.createRequest$( + context, + { + security: securitySettings$, + method: "POST", + path: path$, + headers: headers$, + query: query$, + body: body$, + timeoutMs: options?.timeoutMs || client$.options$.timeoutMs || -1, + }, + options + ); + if (!requestRes.ok) { + return requestRes; + } + const request$ = requestRes.value; + + const doResult = await client$.do$(request$, { + context, + errorCodes: ["400", "4XX", "500", "5XX"], + retryConfig: options?.retries || client$.options$.retryConfig, + retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields$ = { + HttpMeta: { Response: response, Request: request$ }, + }; + + const [result$] = await m$.match< + operations.ExecuteBatchPolicyWithInputResponse, + | errors.ClientError + | errors.BatchServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + m$.json(200, operations.ExecuteBatchPolicyWithInputResponse$inboundSchema, { + hdrs: true, + key: "BatchSuccessfulPolicyEvaluation", + }), + m$.json(207, operations.ExecuteBatchPolicyWithInputResponse$inboundSchema, { + hdrs: true, + key: "BatchMixedResults", + }), + m$.jsonErr(400, errors.ClientError$inboundSchema), + m$.jsonErr(500, errors.BatchServerError$inboundSchema), + m$.fail(["4XX", "5XX"]) + )(response, request$, { extraFields: responseFields$ }); + if (!result$.ok) { + return result$; + } + + return result$; +} diff --git a/packages/opa/src/funcs/executeDefaultPolicyWithInput.ts b/packages/opa/src/funcs/executeDefaultPolicyWithInput.ts new file mode 100644 index 0000000..bc9c943 --- /dev/null +++ b/packages/opa/src/funcs/executeDefaultPolicyWithInput.ts @@ -0,0 +1,152 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { OpaApiClientCore } from "../core.js"; +import { + encodeFormQuery as encodeFormQuery$, + encodeJSON as encodeJSON$, + encodeSimple as encodeSimple$, +} from "../lib/encodings.js"; +import * as m$ from "../lib/matchers.js"; +import * as schemas$ from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import * as components from "../sdk/models/components/index.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../sdk/models/errors/httpclienterrors.js"; +import * as errors from "../sdk/models/errors/index.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import * as operations from "../sdk/models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Execute the default decision given an input + */ +export async function executeDefaultPolicyWithInput( + client$: OpaApiClientCore, + input: components.Input, + pretty?: boolean | undefined, + acceptEncoding?: components.GzipAcceptEncoding | undefined, + options?: RequestOptions +): Promise< + Result< + operations.ExecuteDefaultPolicyWithInputResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input$: operations.ExecuteDefaultPolicyWithInputRequest = { + pretty: pretty, + acceptEncoding: acceptEncoding, + input: input, + }; + + const parsed$ = schemas$.safeParse( + input$, + (value$) => operations.ExecuteDefaultPolicyWithInputRequest$outboundSchema.parse(value$), + "Input validation failed" + ); + if (!parsed$.ok) { + return parsed$; + } + const payload$ = parsed$.value; + const body$ = encodeJSON$("body", payload$.input, { explode: true }); + + const path$ = pathToFunc("/")(); + + const query$ = encodeFormQuery$({ + pretty: payload$.pretty, + }); + + const headers$ = new Headers({ + "Content-Type": "application/json", + Accept: "application/json", + "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { + explode: false, + charEncoding: "none", + }), + }); + + const bearerAuth$ = await extractSecurity(client$.options$.bearerAuth); + const security$ = bearerAuth$ == null ? {} : { bearerAuth: bearerAuth$ }; + const context = { + operationID: "executeDefaultPolicyWithInput", + oAuth2Scopes: [], + securitySource: client$.options$.bearerAuth, + }; + const securitySettings$ = resolveGlobalSecurity(security$); + + const requestRes = client$.createRequest$( + context, + { + security: securitySettings$, + method: "POST", + path: path$, + headers: headers$, + query: query$, + body: body$, + timeoutMs: options?.timeoutMs || client$.options$.timeoutMs || -1, + }, + options + ); + if (!requestRes.ok) { + return requestRes; + } + const request$ = requestRes.value; + + const doResult = await client$.do$(request$, { + context, + errorCodes: ["400", "404", "4XX", "500", "5XX"], + retryConfig: options?.retries || client$.options$.retryConfig, + retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields$ = { + HttpMeta: { Response: response, Request: request$ }, + }; + + const [result$] = await m$.match< + operations.ExecuteDefaultPolicyWithInputResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + m$.json(200, operations.ExecuteDefaultPolicyWithInputResponse$inboundSchema, { + hdrs: true, + key: "result", + }), + m$.jsonErr([400, 404], errors.ClientError$inboundSchema), + m$.jsonErr(500, errors.ServerError$inboundSchema), + m$.fail(["4XX", "5XX"]) + )(response, request$, { extraFields: responseFields$ }); + if (!result$.ok) { + return result$; + } + + return result$; +} diff --git a/packages/opa/src/funcs/executePolicy.ts b/packages/opa/src/funcs/executePolicy.ts new file mode 100644 index 0000000..d2dd878 --- /dev/null +++ b/packages/opa/src/funcs/executePolicy.ts @@ -0,0 +1,152 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { OpaApiClientCore } from "../core.js"; +import { + encodeFormQuery as encodeFormQuery$, + encodeSimple as encodeSimple$, +} from "../lib/encodings.js"; +import * as m$ from "../lib/matchers.js"; +import * as schemas$ 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 "../sdk/models/errors/httpclienterrors.js"; +import * as errors from "../sdk/models/errors/index.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import * as operations from "../sdk/models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Execute a policy + */ +export async function executePolicy( + client$: OpaApiClientCore, + request: operations.ExecutePolicyRequest, + options?: RequestOptions +): Promise< + Result< + operations.ExecutePolicyResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input$ = request; + + const parsed$ = schemas$.safeParse( + input$, + (value$) => operations.ExecutePolicyRequest$outboundSchema.parse(value$), + "Input validation failed" + ); + if (!parsed$.ok) { + return parsed$; + } + const payload$ = parsed$.value; + const body$ = null; + + const pathParams$ = { + path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), + }; + + const path$ = pathToFunc("/v1/data/{path}")(pathParams$); + + const query$ = encodeFormQuery$({ + explain: payload$.explain, + instrument: payload$.instrument, + metrics: payload$.metrics, + pretty: payload$.pretty, + provenance: payload$.provenance, + "strict-builtin-errors": payload$["strict-builtin-errors"], + }); + + const headers$ = new Headers({ + Accept: "application/json", + "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { + explode: false, + charEncoding: "none", + }), + }); + + const bearerAuth$ = await extractSecurity(client$.options$.bearerAuth); + const security$ = bearerAuth$ == null ? {} : { bearerAuth: bearerAuth$ }; + const context = { + operationID: "executePolicy", + oAuth2Scopes: [], + securitySource: client$.options$.bearerAuth, + }; + const securitySettings$ = resolveGlobalSecurity(security$); + + const requestRes = client$.createRequest$( + context, + { + security: securitySettings$, + method: "GET", + path: path$, + headers: headers$, + query: query$, + body: body$, + timeoutMs: options?.timeoutMs || client$.options$.timeoutMs || -1, + }, + options + ); + if (!requestRes.ok) { + return requestRes; + } + const request$ = requestRes.value; + + const doResult = await client$.do$(request$, { + context, + errorCodes: ["400", "4XX", "500", "5XX"], + retryConfig: options?.retries || client$.options$.retryConfig, + retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields$ = { + HttpMeta: { Response: response, Request: request$ }, + }; + + const [result$] = await m$.match< + operations.ExecutePolicyResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + m$.json(200, operations.ExecutePolicyResponse$inboundSchema, { + hdrs: true, + key: "SuccessfulPolicyResponse", + }), + m$.jsonErr(400, errors.ClientError$inboundSchema), + m$.jsonErr(500, errors.ServerError$inboundSchema), + m$.fail(["4XX", "5XX"]) + )(response, request$, { extraFields: responseFields$ }); + if (!result$.ok) { + return result$; + } + + return result$; +} diff --git a/packages/opa/src/funcs/executePolicyWithInput.ts b/packages/opa/src/funcs/executePolicyWithInput.ts new file mode 100644 index 0000000..c7125da --- /dev/null +++ b/packages/opa/src/funcs/executePolicyWithInput.ts @@ -0,0 +1,158 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { OpaApiClientCore } from "../core.js"; +import { + encodeFormQuery as encodeFormQuery$, + encodeJSON as encodeJSON$, + encodeSimple as encodeSimple$, +} from "../lib/encodings.js"; +import * as m$ from "../lib/matchers.js"; +import * as schemas$ 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 "../sdk/models/errors/httpclienterrors.js"; +import * as errors from "../sdk/models/errors/index.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import * as operations from "../sdk/models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Execute a policy given an input + */ +export async function executePolicyWithInput( + client$: OpaApiClientCore, + request: operations.ExecutePolicyWithInputRequest, + options?: RequestOptions +): Promise< + Result< + operations.ExecutePolicyWithInputResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input$ = request; + + const parsed$ = schemas$.safeParse( + input$, + (value$) => operations.ExecutePolicyWithInputRequest$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$ = { + path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), + }; + + const path$ = pathToFunc("/v1/data/{path}")(pathParams$); + + const query$ = encodeFormQuery$({ + explain: payload$.explain, + instrument: payload$.instrument, + metrics: payload$.metrics, + pretty: payload$.pretty, + provenance: payload$.provenance, + "strict-builtin-errors": payload$["strict-builtin-errors"], + }); + + const headers$ = new Headers({ + "Content-Type": "application/json", + Accept: "application/json", + "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { + explode: false, + charEncoding: "none", + }), + "Content-Encoding": encodeSimple$("Content-Encoding", payload$["Content-Encoding"], { + explode: false, + charEncoding: "none", + }), + }); + + const bearerAuth$ = await extractSecurity(client$.options$.bearerAuth); + const security$ = bearerAuth$ == null ? {} : { bearerAuth: bearerAuth$ }; + const context = { + operationID: "executePolicyWithInput", + oAuth2Scopes: [], + securitySource: client$.options$.bearerAuth, + }; + const securitySettings$ = resolveGlobalSecurity(security$); + + const requestRes = client$.createRequest$( + context, + { + security: securitySettings$, + method: "POST", + path: path$, + headers: headers$, + query: query$, + body: body$, + timeoutMs: options?.timeoutMs || client$.options$.timeoutMs || -1, + }, + options + ); + if (!requestRes.ok) { + return requestRes; + } + const request$ = requestRes.value; + + const doResult = await client$.do$(request$, { + context, + errorCodes: ["400", "4XX", "500", "5XX"], + retryConfig: options?.retries || client$.options$.retryConfig, + retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields$ = { + HttpMeta: { Response: response, Request: request$ }, + }; + + const [result$] = await m$.match< + operations.ExecutePolicyWithInputResponse, + | errors.ClientError + | errors.ServerError + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + m$.json(200, operations.ExecutePolicyWithInputResponse$inboundSchema, { + hdrs: true, + key: "SuccessfulPolicyResponse", + }), + m$.jsonErr(400, errors.ClientError$inboundSchema), + m$.jsonErr(500, errors.ServerError$inboundSchema), + m$.fail(["4XX", "5XX"]) + )(response, request$, { extraFields: responseFields$ }); + if (!result$.ok) { + return result$; + } + + return result$; +} diff --git a/packages/opa/src/funcs/health.ts b/packages/opa/src/funcs/health.ts new file mode 100644 index 0000000..5ae06d8 --- /dev/null +++ b/packages/opa/src/funcs/health.ts @@ -0,0 +1,141 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { OpaApiClientCore } from "../core.js"; +import { encodeFormQuery as encodeFormQuery$ } from "../lib/encodings.js"; +import * as m$ from "../lib/matchers.js"; +import * as schemas$ 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 "../sdk/models/errors/httpclienterrors.js"; +import * as errors from "../sdk/models/errors/index.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import * as operations from "../sdk/models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Verify the server is operational + * + * @remarks + * The health API endpoint executes a simple built-in policy query to verify that the server is operational. Optionally it can account for bundle activation as well (useful for “ready” checks at startup). + */ +export async function health( + client$: OpaApiClientCore, + bundles?: boolean | undefined, + plugins?: boolean | undefined, + excludePlugin?: Array | undefined, + options?: RequestOptions +): Promise< + Result< + operations.HealthResponse, + | errors.UnhealthyServer + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input$: operations.HealthRequest = { + bundles: bundles, + plugins: plugins, + excludePlugin: excludePlugin, + }; + + const parsed$ = schemas$.safeParse( + input$, + (value$) => operations.HealthRequest$outboundSchema.parse(value$), + "Input validation failed" + ); + if (!parsed$.ok) { + return parsed$; + } + const payload$ = parsed$.value; + const body$ = null; + + const path$ = pathToFunc("/health")(); + + const query$ = encodeFormQuery$({ + bundles: payload$.bundles, + "exclude-plugin": payload$["exclude-plugin"], + plugins: payload$.plugins, + }); + + const headers$ = new Headers({ + Accept: "application/json", + }); + + const bearerAuth$ = await extractSecurity(client$.options$.bearerAuth); + const security$ = bearerAuth$ == null ? {} : { bearerAuth: bearerAuth$ }; + const context = { + operationID: "health", + oAuth2Scopes: [], + securitySource: client$.options$.bearerAuth, + }; + const securitySettings$ = resolveGlobalSecurity(security$); + + const requestRes = client$.createRequest$( + context, + { + security: securitySettings$, + method: "GET", + path: path$, + headers: headers$, + query: query$, + body: body$, + timeoutMs: options?.timeoutMs || client$.options$.timeoutMs || -1, + }, + options + ); + if (!requestRes.ok) { + return requestRes; + } + const request$ = requestRes.value; + + const doResult = await client$.do$(request$, { + context, + errorCodes: ["4XX", "500", "5XX"], + retryConfig: options?.retries || client$.options$.retryConfig, + retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields$ = { + HttpMeta: { Response: response, Request: request$ }, + }; + + const [result$] = await m$.match< + operations.HealthResponse, + | errors.UnhealthyServer + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + m$.json(200, operations.HealthResponse$inboundSchema, { key: "HealthyServer" }), + m$.jsonErr(500, errors.UnhealthyServer$inboundSchema), + m$.fail(["4XX", "5XX"]) + )(response, request$, { extraFields: responseFields$ }); + if (!result$.ok) { + return result$; + } + + return result$; +} diff --git a/packages/opa/src/hooks/hooks.ts b/packages/opa/src/hooks/hooks.ts index 6a1e31e..a6b6e17 100644 --- a/packages/opa/src/hooks/hooks.ts +++ b/packages/opa/src/hooks/hooks.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { RequestInput } from "../lib/http.js"; diff --git a/packages/opa/src/hooks/index.ts b/packages/opa/src/hooks/index.ts index d5fdd74..8f0e4db 100644 --- a/packages/opa/src/hooks/index.ts +++ b/packages/opa/src/hooks/index.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export * from "./types.js"; diff --git a/packages/opa/src/hooks/types.ts b/packages/opa/src/hooks/types.ts index dd23b02..3a31914 100644 --- a/packages/opa/src/hooks/types.ts +++ b/packages/opa/src/hooks/types.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { HTTPClient, RequestInput } from "../lib/http.js"; diff --git a/packages/opa/src/lib/base64.ts b/packages/opa/src/lib/base64.ts index cda0764..c2d5b38 100644 --- a/packages/opa/src/lib/base64.ts +++ b/packages/opa/src/lib/base64.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/lib/config.ts b/packages/opa/src/lib/config.ts index 08a2cd8..224bf5b 100644 --- a/packages/opa/src/lib/config.ts +++ b/packages/opa/src/lib/config.ts @@ -1,8 +1,9 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * 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"; @@ -17,6 +18,8 @@ export const ServerList = [ ] as const; export type SDKOptions = { + bearerAuth?: string | (() => Promise); + httpClient?: HTTPClient; /** * Allows overriding the default server used by the SDK @@ -31,6 +34,7 @@ export type SDKOptions = { */ retryConfig?: RetryConfig; timeoutMs?: number; + debugLogger?: Logger; }; export function serverURLFromOptions(options: SDKOptions): URL | null { @@ -53,7 +57,7 @@ export function serverURLFromOptions(options: SDKOptions): URL | null { export const SDK_METADATA = { language: "typescript", openapiDocVersion: "0.2.0", - sdkVersion: "1.3.0", - genVersion: "2.369.0", - userAgent: "speakeasy-sdk/typescript 1.3.0 2.369.0 0.2.0 @styra/opa", + sdkVersion: "1.4.0", + genVersion: "2.393.4", + userAgent: "speakeasy-sdk/typescript 1.4.0 2.393.4 0.2.0 @styra/opa", } as const; diff --git a/packages/opa/src/lib/dlv.ts b/packages/opa/src/lib/dlv.ts new file mode 100644 index 0000000..e81091f --- /dev/null +++ b/packages/opa/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/packages/opa/src/lib/encodings.ts b/packages/opa/src/lib/encodings.ts index 49f536b..44fa728 100644 --- a/packages/opa/src/lib/encodings.ts +++ b/packages/opa/src/lib/encodings.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { bytesToBase64 } from "./base64.js"; @@ -212,6 +212,24 @@ export function encodeDeepObject( 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) => { @@ -219,9 +237,7 @@ export function encodeDeepObject( }; if (!isPlainObject(value)) { - throw new EncodingError( - `Value of parameter '${key}' which uses deepObject encoding must be an object`, - ); + throw new EncodingError(`Expected parameter '${key}' to be an object.`); } Object.entries(value).forEach(([ck, cv]) => { @@ -232,9 +248,11 @@ export function encodeDeepObject( const pk = `${key}[${ck}]`; if (isPlainObject(cv)) { - throw new EncodingError( - `Value of parameter field '${pk}' cannot be an array or object.`, - ); + const objOut = encodeDeepObjectObject(pk, cv, options); + + out += `&${objOut}`; + + return; } const pairs: unknown[] = Array.isArray(cv) ? cv : [cv]; diff --git a/packages/opa/src/lib/http.ts b/packages/opa/src/lib/http.ts index 54ed529..13cf1fd 100644 --- a/packages/opa/src/lib/http.ts +++ b/packages/opa/src/lib/http.ts @@ -1,41 +1,39 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import { never as znever } from "zod"; -import { parse } from "./schemas.js"; -import { isPlainObject } from "./is-plain-object.js"; -import { SDKError } from "../sdk/models/errors/sdkerror.js"; - -export type Fetcher = (input: RequestInfo | URL, init?: RequestInit) => Promise; +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); - } + // 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; + /** + * 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; + fetcher?: Fetcher; } export type BeforeRequestHook = (req: Request) => Awaitable; @@ -43,114 +41,114 @@ 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; + 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; + } } - 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; - } - } + 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); + } - /** - * 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; + 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]}`); } - /** 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; + const index = target.findIndex((v) => v === args[1]); + if (index >= 0) { + target.splice(index, 1); } - clone(): HTTPClient { - const child = new HTTPClient(this.options); - child.requestHooks = this.requestHooks.slice(); - child.requestErrorHooks = this.requestErrorHooks.slice(); - child.responseHooks = this.responseHooks.slice(); + return this; + } - return child; - } + 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)[]; @@ -159,344 +157,167 @@ export type StatusCodePredicate = number | string | (number | string)[]; // segments in a media type string. const mediaParamSeparator = /\s*;\s*/g; -function matchContentType(response: Response, pattern: string): boolean { - // `*` is a special case which means anything is acceptable. - if (pattern === "*") { - return true; +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; } + } - let contentType = response.headers.get("content-type")?.trim() || "application/octet-stream"; - contentType = contentType.toLowerCase(); + return true; +} - const wantParts = pattern.toLowerCase().trim().split(mediaParamSeparator); - const [wantType = "", ...wantParams] = wantParts; +const codeRangeRE = new RegExp("^[0-9]xx$", "i"); - if (wantType.split("/").length !== 2) { - return false; - } +export function matchStatusCode( + response: Response, + codes: StatusCodePredicate, +): boolean { + const actual = `${response.status}`; + const expectedCodes = Array.isArray(codes) ? codes : [codes]; + if (!expectedCodes.length) { + return false; + } - const gotParts = contentType.split(mediaParamSeparator); - const [gotType = "", ...gotParams] = gotParts; + return expectedCodes.some((ec) => { + const code = `${ec}`; - const [type = "", subtype = ""] = gotType.split("/"); - if (!type || !subtype) { - return false; + if (code === "default") { + return true; } - if ( - wantType !== "*/*" && - gotType !== wantType && - `${type}/*` !== wantType && - `*/${subtype}` !== wantType - ) { - return false; + if (!codeRangeRE.test(`${code}`)) { + return code === actual; } - if (gotParams.length < wantParams.length) { - return false; + const expectFamily = code.charAt(0); + if (!expectFamily) { + throw new Error("Invalid status code range"); } - const params = new Set(gotParams); - for (const wantParam of wantParams) { - if (!params.has(wantParam)) { - return false; - } + const actualFamily = actual.charAt(0); + if (!actualFamily) { + throw new Error(`Invalid response status code: ${actual}`); } - 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; - }); + return actualFamily === expectFamily; + }); } export function matchResponse( - response: Response, - code: StatusCodePredicate, - contentTypePattern: string + response: Response, + code: StatusCodePredicate, + contentTypePattern: string, ): boolean { - return matchStatusCode(response, code) && matchContentType(response, contentTypePattern); -} - -const headerValRE = /, */; -export function unpackHeaders(headers: Headers): Record { - const out: Record = {}; - - for (const [k, v] of headers.entries()) { - out[k] = v.split(headerValRE); - } - - return out; + return ( + matchStatusCode(response, code) && + matchContentType(response, contentTypePattern) + ); } -type ResponseMatcherSchema = - | { parse: (data: unknown) => T } - | { inboundSchema: { parse: (data: unknown) => T } }; +/** + * 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; + } -type SerializationMethod = "sse" | "json" | "rawBytes" | "rawStream" | "text" | "void" | "fail"; + // Covers fetch in Deno as well + const isBrowserErr = + err instanceof TypeError && + err.message.toLowerCase().startsWith("failed to fetch"); -const defaultContentTypes: Record = { - sse: "text/event-stream", - json: "application/json", - rawBytes: "application/octet-stream", - rawStream: "application/octet-stream", - text: "text/plain", - void: "", - fail: "", -}; + const isNodeErr = + err instanceof TypeError && + err.message.toLowerCase().startsWith("fetch failed"); -type ResponsePredicateMatch = { - method: SerializationMethod; - codes: StatusCodePredicate; - ctype: string; - schema: ResponseMatcherSchema; - hdrs: boolean; - key: string | undefined; - err: boolean; - fail: boolean; -}; + const isBunErr = "name" in err && err.name === "ConnectionError"; -type ResponsePredicateOptions = { - /** Content type to match on. */ - ctype?: string; - /** Pass HTTP headers to deserializer. */ - hdrs?: boolean; -} & ( - | { - /** The result key to store the deserialized value into. */ - key?: string; - fail?: never; - err?: never; - } - | { - /** Indicates the matched response must throw the built-in error. */ - fail: true; - key?: never; - err?: never; - } - | { - /** Indicates the matched response is a custom error. */ - err: true; - key?: never; - fail?: never; - } -); - -export class ResponseMatcher { - private predicates: ResponsePredicateMatch[] = []; - - #any( - method: SerializationMethod, - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: ResponsePredicateOptions - ) { - const ctype = opts?.ctype || defaultContentTypes[method]; - const hdrs = !!opts?.hdrs; - const key = opts?.key; - const err = !!opts?.err; - const fail = !!opts?.fail; - this.predicates.push({ - method, - codes, - ctype, - schema, - hdrs, - key, - err, - fail, - }); - return this; - } + const isGenericErr = + "code" in err && + typeof err.code === "string" && + err.code.toLowerCase() === "econnreset"; - json( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: ResponsePredicateOptions - ): this { - return this.#any("json", codes, schema, opts); - } - bytes( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: ResponsePredicateOptions - ): this { - return this.#any("rawBytes", codes, schema, opts); - } - stream( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: ResponsePredicateOptions - ): this { - return this.#any("rawStream", codes, schema, opts); - } - text( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: ResponsePredicateOptions - ): this { - return this.#any("text", codes, schema, opts); - } - sse( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: Omit - ): this { - return this.#any("sse", codes, schema, opts); - } - void( - codes: StatusCodePredicate, - schema: ResponseMatcherSchema, - opts?: Pick - ): this { - return this.#any("void", codes, schema, opts); - } - fail(codes: StatusCodePredicate): this { - return this.#any("fail", codes, znever(), { fail: true }); - } - - async match( - response: Response, - // envelope-http - request: Request, - - options?: { - resultKey?: string; - extraFields?: Record; - } - ): Promise<[result: Result, rawData: unknown]> { - let pred: ResponsePredicateMatch | undefined; - for (const predicate of this.predicates) { - const { codes, ctype } = predicate; - if (ctype && matchResponse(response, codes, ctype)) { - pred = predicate; - break; - } else if (!ctype && matchStatusCode(response, codes)) { - pred = predicate; - break; - } - } - if (pred == null) { - await discardResponseBody(response); - throw new SDKError("Unexpected API response status or content-type", { - response, - request, - }); - } - - const { method, schema } = pred; - - let raw: unknown; - switch (method) { - case "json": - raw = await response.json(); - break; - case "rawBytes": - raw = await response.arrayBuffer(); - break; - case "rawStream": - raw = response.body; - break; - case "text": - raw = await response.text(); - break; - case "sse": - raw = response.body; - break; - case "void": - raw = await discardResponseBody(response); - break; - case "fail": - raw = await discardResponseBody(response); - break; - default: - method satisfies never; - throw new Error(`Unsupported response type: ${method}`); - } - - const resultKey = pred.key || options?.resultKey; - let data: unknown; - if (pred.fail) { - throw new SDKError("API error occurred", { response, request }); - } else if (pred.err) { - data = { - ...options?.extraFields, - ...(pred.hdrs ? { Headers: unpackHeaders(response.headers) } : null), - ...(isPlainObject(raw) ? raw : null), - }; - } else if (resultKey) { - data = { - ...options?.extraFields, - ...(pred.hdrs ? { Headers: unpackHeaders(response.headers) } : null), - [resultKey]: raw, - }; - } else { - data = { - ...options?.extraFields, - ...(pred.hdrs ? { Headers: unpackHeaders(response.headers) } : null), - }; - } - - const parser = "inboundSchema" in schema ? schema.inboundSchema : schema; - const body = parse(data, (v: unknown) => parser.parse(v), "Response validation failed"); - - if (body instanceof Error) { - throw body; - } - - return [body, raw]; - } + return isBrowserErr || isNodeErr || isGenericErr || isBunErr; } /** - * 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 + * Uses various heurisitics to determine if an error is a timeout error. */ -export async function discardResponseBody(res: Response) { - const reader = res.body?.getReader(); - if (reader == null) { - return; - } +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; +} - try { - let done = false; - while (!done) { - const res = await reader.read(); - done = res.done; - } - } finally { - reader.releaseLock(); - } +/** + * 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/packages/opa/src/lib/is-plain-object.ts b/packages/opa/src/lib/is-plain-object.ts index af0d6e7..61070d3 100644 --- a/packages/opa/src/lib/is-plain-object.ts +++ b/packages/opa/src/lib/is-plain-object.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ /* diff --git a/packages/opa/src/lib/logger.ts b/packages/opa/src/lib/logger.ts new file mode 100644 index 0000000..d181f29 --- /dev/null +++ b/packages/opa/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/packages/opa/src/lib/matchers.ts b/packages/opa/src/lib/matchers.ts new file mode 100644 index 0000000..03086d8 --- /dev/null +++ b/packages/opa/src/lib/matchers.ts @@ -0,0 +1,301 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { safeParse } from "./schemas.js"; +import { StatusCodePredicate, matchResponse, matchStatusCode } from "./http.js"; +import { isPlainObject } from "./is-plain-object.js"; +import { SDKError } from "../sdk/models/errors/sdkerror.js"; +import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import { Result } from "../types/fp.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, + request: Request, + + options?: { resultKey?: string; extraFields?: Record } +) => Promise<[result: Result, raw: unknown]>; + +export function match( + ...matchers: Array> +): MatchFunc { + return async function matchFunc( + response: Response, + request: Request, + + 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) { + await discardResponseBody(response); + return [ + { + ok: false, + error: new SDKError("Unexpected API response status or content-type", { + response, + request, + }), + }, + raw, + ]; + } + + const encoding = matcher.enc; + switch (encoding) { + case "json": + raw = await response.json(); + break; + case "bytes": + raw = 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 discardResponseBody(response); + break; + default: + encoding satisfies never; + throw new Error(`Unsupported response type: ${encoding}`); + } + + if (matcher.enc === "fail") { + return [ + { ok: false, error: new SDKError("API error occurred", { response, request }) }, + 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 { + data = { + ...options?.extraFields, + ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null), + }; + } + + 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/packages/opa/src/lib/primitives.ts b/packages/opa/src/lib/primitives.ts index d3aae30..23794a2 100644 --- a/packages/opa/src/lib/primitives.ts +++ b/packages/opa/src/lib/primitives.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export type Remap = { diff --git a/packages/opa/src/lib/retries.ts b/packages/opa/src/lib/retries.ts index ed9b495..df3e0bc 100644 --- a/packages/opa/src/lib/retries.ts +++ b/packages/opa/src/lib/retries.ts @@ -1,7 +1,9 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ +import { isConnectionError, isTimeoutError } from "./http.js"; + export type BackoffStrategy = { initialInterval: number; maxInterval: number; @@ -99,47 +101,6 @@ function wrapFetcher( }; } -function isConnectionError(err: unknown) { - 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; -} - -function isTimeoutError(err: unknown) { - if (typeof err !== "object" || err == null) { - return false; - } - - // Fetch in browser, Node.js, Bun, Deno - const isNative = "name" in err && err.name === "TimeoutError"; - - // Node.js HTTP client and Axios - const isGenericErr = - "code" in err && - typeof err.code === "string" && - err.code.toLowerCase() === "econnaborted"; - - return isNative || isGenericErr; -} - const codeRangeRE = new RegExp("^[0-9]xx$", "i"); function isRetryableResponse(res: Response, statusCodes: string[]): boolean { diff --git a/packages/opa/src/lib/schemas.ts b/packages/opa/src/lib/schemas.ts index 390a82d..5700792 100644 --- a/packages/opa/src/lib/schemas.ts +++ b/packages/opa/src/lib/schemas.ts @@ -1,9 +1,10 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { output, ZodEffects, ZodError, ZodObject, ZodRawShape, ZodTypeAny } from "zod"; import { SDKValidationError } from "../sdk/models/errors/sdkvalidationerror.js"; +import { ERR, OK, Result } from "../types/fp.js"; /** * Utility function that executes some code which may throw a ZodError. It @@ -21,6 +22,23 @@ export function parse(rawValue: Inp, fn: (value: Inp) => Out, errorMes } } +/** + * 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, diff --git a/packages/opa/src/lib/sdks.ts b/packages/opa/src/lib/sdks.ts index 22d8a5c..027a898 100644 --- a/packages/opa/src/lib/sdks.ts +++ b/packages/opa/src/lib/sdks.ts @@ -1,16 +1,31 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import { ResponseMatcher, HTTPClient, matchStatusCode } from "./http.js"; -import { SecurityState, resolveSecurity } from "./security.js"; +import { + HTTPClient, + matchContentType, + matchStatusCode, + isAbortError, + isTimeoutError, + isConnectionError, +} from "./http.js"; +import { SecurityState } from "./security.js"; import { retry, RetryConfig } from "./retries.js"; -import { pathToFunc } from "./url.js"; +import { Logger } from "./logger.js"; import { encodeForm } from "./encodings.js"; import { stringToBase64 } from "./base64.js"; -import { SDK_METADATA } from "./config.js"; +import { SDKOptions, SDK_METADATA, serverURLFromOptions } from "./config.js"; import { SDKHooks } from "../hooks/hooks.js"; import { HookContext } from "../hooks/types.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../sdk/models/errors/httpclienterrors.js"; +import { ERR, OK, Result } from "../types/fp.js"; export type RequestOptions = { /** @@ -58,32 +73,49 @@ const isBrowserLike = (typeof window === "object" && typeof window.document !== "undefined"); export class ClientSDK { - private readonly client: HTTPClient; + private readonly httpClient: HTTPClient; protected readonly baseURL: URL | null; protected readonly hooks$: SDKHooks; + protected readonly logger?: Logger | undefined; + public readonly options$: SDKOptions & { hooks?: SDKHooks }; - constructor(init: { client: HTTPClient; baseURL: URL | null; hooks: SDKHooks }) { - const url = init.baseURL; + 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(/\/+$/, "") + "/"; } - - this.hooks$ = init.hooks; - const { baseURL, client } = this.hooks$.sdkInit({ baseURL: url, client: init.client }); + const { baseURL, client } = this.hooks$.sdkInit({ + baseURL: url, + client: options.httpClient || new HTTPClient(), + }); this.baseURL = baseURL; - this.client = client; + this.httpClient = client; + this.logger = options.debugLogger; } - protected createRequest$( + public createRequest$( context: HookContext, conf: RequestConfig, options?: RequestOptions - ): Request { + ): Result { const { method, path, query, headers: opHeaders, security } = conf; const base = conf.baseURL ?? this.baseURL; if (!base) { - throw new TypeError("No base URL provided for operation"); + return ERR(new InvalidRequestError("No base URL provided for operation")); } const reqURL = new URL(base); const inputURL = new URL(path, reqURL); @@ -149,20 +181,27 @@ export class ClientSDK { } } - const input = this.hooks$.beforeCreateRequest(context, { - url: reqURL, - options: { - ...fetchOptions, - body: conf.body ?? null, - headers, - method, - }, - }); + 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 new Request(input.url, input.options); + return OK(new Request(input.url, input.options)); } - protected async do$( + public async do$( request: Request, options: { context: HookContext; @@ -170,19 +209,25 @@ export class ClientSDK { retryConfig?: RetryConfig | undefined; retryCodes?: string[] | undefined; } - ): Promise { + ): Promise< + Result< + Response, + RequestAbortedError | RequestTimeoutError | ConnectionError | UnexpectedClientError + > + > { const { context, errorCodes } = options; const retryConfig = options.retryConfig || { strategy: "none" }; const retryCodes = options.retryCodes || []; return retry( async () => { - const req = request.clone(); - - let response = await this.client.request( - await this.hooks$.beforeRequest(context, req) + 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); + if (matchStatusCode(response, errorCodes)) { const result = await this.hooks$.afterError(context, response, null); if (result.error) { @@ -193,17 +238,120 @@ export class ClientSDK { response = await this.hooks$.afterSuccess(context, response); } + await logResponse(this.logger, response, req).catch((e) => + this.logger?.log("Failed to log response:", e) + ); + return response; }, { config: retryConfig, statusCodes: 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, + }) + ); + } + } ); } +} - protected matcher(): ResponseMatcher { - return new ResponseMatcher(); +const jsonLikeContentTypeRE = /^application\/(?:.{0,100}\+)?json/; +async function logRequest(logger: Logger | undefined, req: Request) { + if (!logger) { + return; } - protected templateURLComponent = pathToFunc; + 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(); - protected resolveSecurity = resolveSecurity; + logger.groupEnd(); } diff --git a/packages/opa/src/lib/security.ts b/packages/opa/src/lib/security.ts index 560cb62..e4063e9 100644 --- a/packages/opa/src/lib/security.ts +++ b/packages/opa/src/lib/security.ts @@ -1,7 +1,9 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ +import * as components from "../sdk/models/components/index.js"; + export enum SecurityErrorCode { Incomplete = "incomplete", UnrecognisedSecurityType = "unrecognized_security_type", @@ -65,7 +67,8 @@ type SecurityInputOAuth2 = { type SecurityInputOAuth2ClientCredentials = { type: "oauth2:client_credentials"; - value: { clientID?: string | undefined; clientSecret?: string | undefined } | null | undefined; + value: string | null | undefined; + fieldName: string; }; export type SecurityInput = @@ -90,8 +93,6 @@ export function resolveSecurity(...options: SecurityInput[][]): SecurityState | return false; } else if (o.type === "http:basic") { return o.value.username != null || o.value.password != null; - } 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 { @@ -168,3 +169,24 @@ function applyBearer( state.headers[spec.fieldName] = value; } +export function resolveGlobalSecurity( + security: Partial | null | undefined +): SecurityState | null { + return resolveSecurity([ + { + fieldName: "Authorization", + type: "http:bearer", + value: security?.bearerAuth, + }, + ]); +} + +export async function extractSecurity>( + sec: T | (() => Promise) | undefined +): Promise { + if (sec == null) { + return; + } + + return typeof sec === "function" ? sec() : sec; +} diff --git a/packages/opa/src/lib/url.ts b/packages/opa/src/lib/url.ts index df58acb..6bc6356 100644 --- a/packages/opa/src/lib/url.ts +++ b/packages/opa/src/lib/url.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ const hasOwn = Object.prototype.hasOwnProperty; diff --git a/packages/opa/src/sdk/index.ts b/packages/opa/src/sdk/index.ts index 34a84fc..ecac226 100644 --- a/packages/opa/src/sdk/index.ts +++ b/packages/opa/src/sdk/index.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export * from "./sdk.js"; diff --git a/packages/opa/src/sdk/models/components/batchmixedresults.ts b/packages/opa/src/sdk/models/components/batchmixedresults.ts index 796fa6c..0799c63 100644 --- a/packages/opa/src/sdk/models/components/batchmixedresults.ts +++ b/packages/opa/src/sdk/models/components/batchmixedresults.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/components/batchsuccessfulpolicyevaluation.ts b/packages/opa/src/sdk/models/components/batchsuccessfulpolicyevaluation.ts index 0c5de14..ffd2bb6 100644 --- a/packages/opa/src/sdk/models/components/batchsuccessfulpolicyevaluation.ts +++ b/packages/opa/src/sdk/models/components/batchsuccessfulpolicyevaluation.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/components/explain.ts b/packages/opa/src/sdk/models/components/explain.ts index 7497a2c..29e5535 100644 --- a/packages/opa/src/sdk/models/components/explain.ts +++ b/packages/opa/src/sdk/models/components/explain.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/gzipacceptencoding.ts b/packages/opa/src/sdk/models/components/gzipacceptencoding.ts index b72cf74..23076fd 100644 --- a/packages/opa/src/sdk/models/components/gzipacceptencoding.ts +++ b/packages/opa/src/sdk/models/components/gzipacceptencoding.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/gzipcontentencoding.ts b/packages/opa/src/sdk/models/components/gzipcontentencoding.ts index dc07a70..9c2507b 100644 --- a/packages/opa/src/sdk/models/components/gzipcontentencoding.ts +++ b/packages/opa/src/sdk/models/components/gzipcontentencoding.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/healthyserver.ts b/packages/opa/src/sdk/models/components/healthyserver.ts index 6702106..b351a8b 100644 --- a/packages/opa/src/sdk/models/components/healthyserver.ts +++ b/packages/opa/src/sdk/models/components/healthyserver.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/httpmetadata.ts b/packages/opa/src/sdk/models/components/httpmetadata.ts index 07197a2..15437df 100644 --- a/packages/opa/src/sdk/models/components/httpmetadata.ts +++ b/packages/opa/src/sdk/models/components/httpmetadata.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/components/index.ts b/packages/opa/src/sdk/models/components/index.ts index ad2422c..f7ed269 100644 --- a/packages/opa/src/sdk/models/components/index.ts +++ b/packages/opa/src/sdk/models/components/index.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export * from "./batchmixedresults.js"; @@ -12,4 +12,5 @@ export * from "./httpmetadata.js"; export * from "./input.js"; export * from "./provenance.js"; export * from "./result.js"; +export * from "./security.js"; export * from "./successfulpolicyresponse.js"; diff --git a/packages/opa/src/sdk/models/components/input.ts b/packages/opa/src/sdk/models/components/input.ts index c9e4cc1..2cfbc17 100644 --- a/packages/opa/src/sdk/models/components/input.ts +++ b/packages/opa/src/sdk/models/components/input.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/provenance.ts b/packages/opa/src/sdk/models/components/provenance.ts index 8ab8b61..ddce0a9 100644 --- a/packages/opa/src/sdk/models/components/provenance.ts +++ b/packages/opa/src/sdk/models/components/provenance.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/components/result.ts b/packages/opa/src/sdk/models/components/result.ts index ca878ff..aa13716 100644 --- a/packages/opa/src/sdk/models/components/result.ts +++ b/packages/opa/src/sdk/models/components/result.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/components/security.ts b/packages/opa/src/sdk/models/components/security.ts new file mode 100644 index 0000000..83e1941 --- /dev/null +++ b/packages/opa/src/sdk/models/components/security.ts @@ -0,0 +1,38 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; + +export type Security = { + bearerAuth?: string | undefined; +}; + +/** @internal */ +export const Security$inboundSchema: z.ZodType = z.object({ + bearerAuth: z.string().optional(), +}); + +/** @internal */ +export type Security$Outbound = { + bearerAuth?: string | undefined; +}; + +/** @internal */ +export const Security$outboundSchema: z.ZodType = + z.object({ + bearerAuth: z.string().optional(), + }); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace Security$ { + /** @deprecated use `Security$inboundSchema` instead. */ + export const inboundSchema = Security$inboundSchema; + /** @deprecated use `Security$outboundSchema` instead. */ + export const outboundSchema = Security$outboundSchema; + /** @deprecated use `Security$Outbound` instead. */ + export type Outbound = Security$Outbound; +} diff --git a/packages/opa/src/sdk/models/components/successfulpolicyresponse.ts b/packages/opa/src/sdk/models/components/successfulpolicyresponse.ts index 3d0d6fe..a5597af 100644 --- a/packages/opa/src/sdk/models/components/successfulpolicyresponse.ts +++ b/packages/opa/src/sdk/models/components/successfulpolicyresponse.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/errors/batchservererror.ts b/packages/opa/src/sdk/models/errors/batchservererror.ts index a503701..884e9f5 100644 --- a/packages/opa/src/sdk/models/errors/batchservererror.ts +++ b/packages/opa/src/sdk/models/errors/batchservererror.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/errors/clienterror.ts b/packages/opa/src/sdk/models/errors/clienterror.ts index e064034..8f9aac7 100644 --- a/packages/opa/src/sdk/models/errors/clienterror.ts +++ b/packages/opa/src/sdk/models/errors/clienterror.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/errors/httpclienterrors.ts b/packages/opa/src/sdk/models/errors/httpclienterrors.ts new file mode 100644 index 0000000..cdb2995 --- /dev/null +++ b/packages/opa/src/sdk/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/packages/opa/src/sdk/models/errors/index.ts b/packages/opa/src/sdk/models/errors/index.ts index 9dcc949..445f94a 100644 --- a/packages/opa/src/sdk/models/errors/index.ts +++ b/packages/opa/src/sdk/models/errors/index.ts @@ -1,9 +1,10 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export * from "./batchservererror.js"; export * from "./clienterror.js"; +export * from "./httpclienterrors.js"; export * from "./sdkerror.js"; export * from "./sdkvalidationerror.js"; export * from "./servererror.js"; diff --git a/packages/opa/src/sdk/models/errors/sdkerror.ts b/packages/opa/src/sdk/models/errors/sdkerror.ts index b726137..f4a15bc 100644 --- a/packages/opa/src/sdk/models/errors/sdkerror.ts +++ b/packages/opa/src/sdk/models/errors/sdkerror.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export class SDKError extends Error { diff --git a/packages/opa/src/sdk/models/errors/sdkvalidationerror.ts b/packages/opa/src/sdk/models/errors/sdkvalidationerror.ts index 5eb9218..16929b9 100644 --- a/packages/opa/src/sdk/models/errors/sdkvalidationerror.ts +++ b/packages/opa/src/sdk/models/errors/sdkvalidationerror.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; @@ -10,15 +10,17 @@ export class SDKValidationError extends Error { */ public readonly rawValue: unknown; + /** + * The raw message that failed validation. + */ + public readonly rawMessage: unknown; + constructor(message: string, cause: unknown, rawValue: unknown) { - super(message); + super(`${message}: ${cause}`); this.name = "SDKValidationError"; this.cause = cause; this.rawValue = rawValue; - } - - public override toString(): string { - return `${this.message}: ${this.cause}`; + this.rawMessage = message; } /** @@ -28,7 +30,7 @@ export class SDKValidationError extends Error { */ public pretty(): string { if (this.cause instanceof z.ZodError) { - return `${this.message}\n${formatZodError(this.cause)}`; + return `${this.rawMessage}\n${formatZodError(this.cause)}`; } else { return this.toString(); } diff --git a/packages/opa/src/sdk/models/errors/servererror.ts b/packages/opa/src/sdk/models/errors/servererror.ts index 7096f73..5982da6 100644 --- a/packages/opa/src/sdk/models/errors/servererror.ts +++ b/packages/opa/src/sdk/models/errors/servererror.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/errors/unhealthyserver.ts b/packages/opa/src/sdk/models/errors/unhealthyserver.ts index 44f5ec6..044a210 100644 --- a/packages/opa/src/sdk/models/errors/unhealthyserver.ts +++ b/packages/opa/src/sdk/models/errors/unhealthyserver.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/sdk/models/operations/executebatchpolicywithinput.ts b/packages/opa/src/sdk/models/operations/executebatchpolicywithinput.ts index f136536..731c07b 100644 --- a/packages/opa/src/sdk/models/operations/executebatchpolicywithinput.ts +++ b/packages/opa/src/sdk/models/operations/executebatchpolicywithinput.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/operations/executedefaultpolicywithinput.ts b/packages/opa/src/sdk/models/operations/executedefaultpolicywithinput.ts index 81f88c7..ae681b7 100644 --- a/packages/opa/src/sdk/models/operations/executedefaultpolicywithinput.ts +++ b/packages/opa/src/sdk/models/operations/executedefaultpolicywithinput.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/operations/executepolicy.ts b/packages/opa/src/sdk/models/operations/executepolicy.ts index 52284b8..13523d1 100644 --- a/packages/opa/src/sdk/models/operations/executepolicy.ts +++ b/packages/opa/src/sdk/models/operations/executepolicy.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/operations/executepolicywithinput.ts b/packages/opa/src/sdk/models/operations/executepolicywithinput.ts index c79ac70..8113e8e 100644 --- a/packages/opa/src/sdk/models/operations/executepolicywithinput.ts +++ b/packages/opa/src/sdk/models/operations/executepolicywithinput.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/operations/health.ts b/packages/opa/src/sdk/models/operations/health.ts index 18f63cf..8562522 100644 --- a/packages/opa/src/sdk/models/operations/health.ts +++ b/packages/opa/src/sdk/models/operations/health.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import { remap as remap$ } from "../../../lib/primitives.js"; diff --git a/packages/opa/src/sdk/models/operations/index.ts b/packages/opa/src/sdk/models/operations/index.ts index c44716a..cc36809 100644 --- a/packages/opa/src/sdk/models/operations/index.ts +++ b/packages/opa/src/sdk/models/operations/index.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export * from "./executebatchpolicywithinput.js"; diff --git a/packages/opa/src/sdk/sdk.ts b/packages/opa/src/sdk/sdk.ts index a869b70..4fc428c 100644 --- a/packages/opa/src/sdk/sdk.ts +++ b/packages/opa/src/sdk/sdk.ts @@ -1,48 +1,18 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -import { SDKHooks } from "../hooks/hooks.js"; -import { SDKOptions, serverURLFromOptions } from "../lib/config.js"; -import { - encodeFormQuery as encodeFormQuery$, - encodeJSON as encodeJSON$, - encodeSimple as encodeSimple$, -} from "../lib/encodings.js"; -import { HTTPClient } from "../lib/http.js"; -import * as schemas$ from "../lib/schemas.js"; +import { executeBatchPolicyWithInput } from "../funcs/executeBatchPolicyWithInput.js"; +import { executeDefaultPolicyWithInput } from "../funcs/executeDefaultPolicyWithInput.js"; +import { executePolicy } from "../funcs/executePolicy.js"; +import { executePolicyWithInput } from "../funcs/executePolicyWithInput.js"; +import { health } from "../funcs/health.js"; import { ClientSDK, RequestOptions } from "../lib/sdks.js"; +import { unwrapAsync } from "../types/fp.js"; import * as components from "./models/components/index.js"; -import * as errors from "./models/errors/index.js"; import * as operations from "./models/operations/index.js"; export class OpaApiClient extends ClientSDK { - private readonly options$: SDKOptions & { hooks?: SDKHooks }; - - constructor(options: SDKOptions = {}) { - const opt = options as unknown; - let hooks: SDKHooks; - if ( - typeof opt === "object" && - opt != null && - "hooks" in opt && - opt.hooks instanceof SDKHooks - ) { - hooks = opt.hooks; - } else { - hooks = new SDKHooks(); - } - - super({ - client: options.httpClient || new HTTPClient(), - baseURL: serverURLFromOptions(options), - hooks, - }); - - this.options$ = { ...options, hooks }; - void this.options$; - } - /** * Execute the default decision given an input */ @@ -52,76 +22,9 @@ export class OpaApiClient extends ClientSDK { acceptEncoding?: components.GzipAcceptEncoding | undefined, options?: RequestOptions ): Promise { - const input$: operations.ExecuteDefaultPolicyWithInputRequest = { - pretty: pretty, - acceptEncoding: acceptEncoding, - input: input, - }; - - const payload$ = schemas$.parse( - input$, - (value$) => - operations.ExecuteDefaultPolicyWithInputRequest$outboundSchema.parse(value$), - "Input validation failed" - ); - const body$ = encodeJSON$("body", payload$.input, { explode: true }); - - const path$ = this.templateURLComponent("/")(); - - const query$ = encodeFormQuery$({ - pretty: payload$.pretty, - }); - - const headers$ = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { - explode: false, - charEncoding: "none", - }), - }); - - const context = { - operationID: "executeDefaultPolicyWithInput", - oAuth2Scopes: [], - securitySource: null, - }; - - const request$ = this.createRequest$( - context, - { - method: "POST", - path: path$, - headers: headers$, - query: query$, - body: body$, - timeoutMs: options?.timeoutMs || this.options$.timeoutMs || -1, - }, - options + return unwrapAsync( + executeDefaultPolicyWithInput(this, input, pretty, acceptEncoding, options) ); - - const response = await this.do$(request$, { - context, - errorCodes: ["400", "404", "4XX", "500", "5XX"], - retryConfig: options?.retries || this.options$.retryConfig, - retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], - }); - - const responseFields$ = { - HttpMeta: { Response: response, Request: request$ }, - }; - - const [result$] = await this.matcher() - .json(200, operations.ExecuteDefaultPolicyWithInputResponse$inboundSchema, { - hdrs: true, - key: "result", - }) - .json([400, 404], errors.ClientError$inboundSchema, { err: true }) - .json(500, errors.ServerError$inboundSchema, { err: true }) - .fail(["4XX", "5XX"]) - .match(response, request$, { extraFields: responseFields$ }); - - return result$; } /** @@ -131,74 +34,7 @@ export class OpaApiClient extends ClientSDK { request: operations.ExecutePolicyRequest, options?: RequestOptions ): Promise { - const input$ = request; - - const payload$ = schemas$.parse( - input$, - (value$) => operations.ExecutePolicyRequest$outboundSchema.parse(value$), - "Input validation failed" - ); - const body$ = null; - - const pathParams$ = { - path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), - }; - const path$ = this.templateURLComponent("/v1/data/{path}")(pathParams$); - - const query$ = encodeFormQuery$({ - explain: payload$.explain, - instrument: payload$.instrument, - metrics: payload$.metrics, - pretty: payload$.pretty, - provenance: payload$.provenance, - "strict-builtin-errors": payload$["strict-builtin-errors"], - }); - - const headers$ = new Headers({ - Accept: "application/json", - "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { - explode: false, - charEncoding: "none", - }), - }); - - const context = { operationID: "executePolicy", oAuth2Scopes: [], securitySource: null }; - - const request$ = this.createRequest$( - context, - { - method: "GET", - path: path$, - headers: headers$, - query: query$, - body: body$, - timeoutMs: options?.timeoutMs || this.options$.timeoutMs || -1, - }, - options - ); - - const response = await this.do$(request$, { - context, - errorCodes: ["400", "4XX", "500", "5XX"], - retryConfig: options?.retries || this.options$.retryConfig, - retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], - }); - - const responseFields$ = { - HttpMeta: { Response: response, Request: request$ }, - }; - - const [result$] = await this.matcher() - .json(200, operations.ExecutePolicyResponse$inboundSchema, { - hdrs: true, - key: "SuccessfulPolicyResponse", - }) - .json(400, errors.ClientError$inboundSchema, { err: true }) - .json(500, errors.ServerError$inboundSchema, { err: true }) - .fail(["4XX", "5XX"]) - .match(response, request$, { extraFields: responseFields$ }); - - return result$; + return unwrapAsync(executePolicy(this, request, options)); } /** @@ -208,83 +44,7 @@ export class OpaApiClient extends ClientSDK { request: operations.ExecutePolicyWithInputRequest, options?: RequestOptions ): Promise { - const input$ = request; - - const payload$ = schemas$.parse( - input$, - (value$) => operations.ExecutePolicyWithInputRequest$outboundSchema.parse(value$), - "Input validation failed" - ); - const body$ = encodeJSON$("body", payload$.RequestBody, { explode: true }); - - const pathParams$ = { - path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), - }; - const path$ = this.templateURLComponent("/v1/data/{path}")(pathParams$); - - const query$ = encodeFormQuery$({ - explain: payload$.explain, - instrument: payload$.instrument, - metrics: payload$.metrics, - pretty: payload$.pretty, - provenance: payload$.provenance, - "strict-builtin-errors": payload$["strict-builtin-errors"], - }); - - const headers$ = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { - explode: false, - charEncoding: "none", - }), - "Content-Encoding": encodeSimple$("Content-Encoding", payload$["Content-Encoding"], { - explode: false, - charEncoding: "none", - }), - }); - - const context = { - operationID: "executePolicyWithInput", - oAuth2Scopes: [], - securitySource: null, - }; - - const request$ = this.createRequest$( - context, - { - method: "POST", - path: path$, - headers: headers$, - query: query$, - body: body$, - timeoutMs: options?.timeoutMs || this.options$.timeoutMs || -1, - }, - options - ); - - const response = await this.do$(request$, { - context, - errorCodes: ["400", "4XX", "500", "5XX"], - retryConfig: options?.retries || this.options$.retryConfig, - retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], - }); - - const responseFields$ = { - HttpMeta: { Response: response, Request: request$ }, - }; - - const [result$] = await this.matcher() - .json(200, operations.ExecutePolicyWithInputResponse$inboundSchema, { - hdrs: true, - key: "SuccessfulPolicyResponse", - }) - .json(400, errors.ClientError$inboundSchema, { err: true }) - .json(500, errors.ServerError$inboundSchema, { err: true }) - .fail(["4XX", "5XX"]) - .match(response, request$, { extraFields: responseFields$ }); - - return result$; + return unwrapAsync(executePolicyWithInput(this, request, options)); } /** @@ -294,87 +54,7 @@ export class OpaApiClient extends ClientSDK { request: operations.ExecuteBatchPolicyWithInputRequest, options?: RequestOptions ): Promise { - const input$ = request; - - const payload$ = schemas$.parse( - input$, - (value$) => operations.ExecuteBatchPolicyWithInputRequest$outboundSchema.parse(value$), - "Input validation failed" - ); - const body$ = encodeJSON$("body", payload$.RequestBody, { explode: true }); - - const pathParams$ = { - path: encodeSimple$("path", payload$.path, { explode: false, charEncoding: "percent" }), - }; - const path$ = this.templateURLComponent("/v1/batch/data/{path}")(pathParams$); - - const query$ = encodeFormQuery$({ - explain: payload$.explain, - instrument: payload$.instrument, - metrics: payload$.metrics, - pretty: payload$.pretty, - provenance: payload$.provenance, - "strict-builtin-errors": payload$["strict-builtin-errors"], - }); - - const headers$ = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - "Accept-Encoding": encodeSimple$("Accept-Encoding", payload$["Accept-Encoding"], { - explode: false, - charEncoding: "none", - }), - "Content-Encoding": encodeSimple$("Content-Encoding", payload$["Content-Encoding"], { - explode: false, - charEncoding: "none", - }), - }); - - const context = { - operationID: "executeBatchPolicyWithInput", - oAuth2Scopes: [], - securitySource: null, - }; - - const request$ = this.createRequest$( - context, - { - method: "POST", - path: path$, - headers: headers$, - query: query$, - body: body$, - timeoutMs: options?.timeoutMs || this.options$.timeoutMs || -1, - }, - options - ); - - const response = await this.do$(request$, { - context, - errorCodes: ["400", "4XX", "500", "5XX"], - retryConfig: options?.retries || this.options$.retryConfig, - retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], - }); - - const responseFields$ = { - HttpMeta: { Response: response, Request: request$ }, - }; - - const [result$] = await this.matcher() - .json(200, operations.ExecuteBatchPolicyWithInputResponse$inboundSchema, { - hdrs: true, - key: "BatchSuccessfulPolicyEvaluation", - }) - .json(207, operations.ExecuteBatchPolicyWithInputResponse$inboundSchema, { - hdrs: true, - key: "BatchMixedResults", - }) - .json(400, errors.ClientError$inboundSchema, { err: true }) - .json(500, errors.BatchServerError$inboundSchema, { err: true }) - .fail(["4XX", "5XX"]) - .match(response, request$, { extraFields: responseFields$ }); - - return result$; + return unwrapAsync(executeBatchPolicyWithInput(this, request, options)); } /** @@ -389,63 +69,6 @@ export class OpaApiClient extends ClientSDK { excludePlugin?: Array | undefined, options?: RequestOptions ): Promise { - const input$: operations.HealthRequest = { - bundles: bundles, - plugins: plugins, - excludePlugin: excludePlugin, - }; - - const payload$ = schemas$.parse( - input$, - (value$) => operations.HealthRequest$outboundSchema.parse(value$), - "Input validation failed" - ); - const body$ = null; - - const path$ = this.templateURLComponent("/health")(); - - const query$ = encodeFormQuery$({ - bundles: payload$.bundles, - "exclude-plugin": payload$["exclude-plugin"], - plugins: payload$.plugins, - }); - - const headers$ = new Headers({ - Accept: "application/json", - }); - - const context = { operationID: "health", oAuth2Scopes: [], securitySource: null }; - - const request$ = this.createRequest$( - context, - { - method: "GET", - path: path$, - headers: headers$, - query: query$, - body: body$, - timeoutMs: options?.timeoutMs || this.options$.timeoutMs || -1, - }, - options - ); - - const response = await this.do$(request$, { - context, - errorCodes: ["4XX", "500", "5XX"], - retryConfig: options?.retries || this.options$.retryConfig, - retryCodes: options?.retryCodes || ["429", "500", "502", "503", "504"], - }); - - const responseFields$ = { - HttpMeta: { Response: response, Request: request$ }, - }; - - const [result$] = await this.matcher() - .json(200, operations.HealthResponse$inboundSchema, { key: "HealthyServer" }) - .json(500, errors.UnhealthyServer$inboundSchema, { err: true }) - .fail(["4XX", "5XX"]) - .match(response, request$, { extraFields: responseFields$ }); - - return result$; + return unwrapAsync(health(this, bundles, plugins, excludePlugin, options)); } } diff --git a/packages/opa/src/types/blobs.ts b/packages/opa/src/types/blobs.ts index cbb8a57..4ce8460 100644 --- a/packages/opa/src/types/blobs.ts +++ b/packages/opa/src/types/blobs.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ import * as z from "zod"; diff --git a/packages/opa/src/types/constdatetime.ts b/packages/opa/src/types/constdatetime.ts new file mode 100644 index 0000000..c0a4409 --- /dev/null +++ b/packages/opa/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/packages/opa/src/types/enums.ts b/packages/opa/src/types/enums.ts index 4de0142..6fb6d91 100644 --- a/packages/opa/src/types/enums.ts +++ b/packages/opa/src/types/enums.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ declare const __brand: unique symbol; diff --git a/packages/opa/src/types/fp.ts b/packages/opa/src/types/fp.ts new file mode 100644 index 0000000..ccbe51e --- /dev/null +++ b/packages/opa/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/packages/opa/src/types/index.ts b/packages/opa/src/types/index.ts index 374373e..dbaa5e6 100644 --- a/packages/opa/src/types/index.ts +++ b/packages/opa/src/types/index.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ export { RFCDate } from "./rfcdate.js"; @@ -8,3 +8,4 @@ export type { Paginator, PageIterator } from "./operations.js"; export { createPageIterator } from "./operations.js"; export { catchUnrecognizedEnum } from "./enums.js"; export type { OpenEnum, ClosedEnum, Unrecognized } from "./enums.js"; +export type { Result } from "./fp.js"; diff --git a/packages/opa/src/types/operations.ts b/packages/opa/src/types/operations.ts index 7f83351..0952f6f 100644 --- a/packages/opa/src/types/operations.ts +++ b/packages/opa/src/types/operations.ts @@ -1,25 +1,99 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ -export type Paginator = () => Promise> | null; +import { Result } from "./fp.js"; -export type PageIterator = Result & { - next: Paginator; - [Symbol.asyncIterator]: () => AsyncIterableIterator; +export type Paginator = () => Promise }> | null; + +export type PageIterator = V & { + next: Paginator; + [Symbol.asyncIterator]: () => AsyncIterableIterator; }; -export function createPageIterator( - page: Result & { next: Paginator }, -): { [Symbol.asyncIterator]: () => AsyncIterableIterator } { +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>>, +): Promise> { + const resultIter = await iteratorPromise; + + if (!resultIter.ok) { + throw resultIter.error; + } + + return { + ...resultIter.value, + next: unwrapPaginator(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; + }); + }; +} diff --git a/packages/opa/src/types/rfcdate.ts b/packages/opa/src/types/rfcdate.ts index e80b693..c79b3f5 100644 --- a/packages/opa/src/types/rfcdate.ts +++ b/packages/opa/src/types/rfcdate.ts @@ -1,5 +1,5 @@ /* - * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. */ const dateRE = /^\d{4}-\d{2}-\d{2}$/;