From 89005ef835d03f1c896592e9aba132c46e9c50cc Mon Sep 17 00:00:00 2001 From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 00:39:14 +0000 Subject: [PATCH 1/3] SDK regeneration --- .fern/metadata.json | 7 +- CONTRIBUTING.md | 133 +++++ README.md | 38 +- package.json | 7 +- pnpm-lock.yaml | 459 +++++++++--------- reference.md | 64 +++ src/BaseClient.ts | 27 +- src/Client.ts | 6 + src/api/resources/index.ts | 3 + src/api/resources/oauth/client/Client.ts | 89 ++++ src/api/resources/oauth/client/index.ts | 1 + .../oauth/client/requests/GetTokenRequest.ts | 12 + .../resources/oauth/client/requests/index.ts | 1 + src/api/resources/oauth/index.ts | 2 + .../resources/oauth/types/GetTokenResponse.ts | 16 + src/api/resources/oauth/types/index.ts | 1 + src/api/types/BadRequestErrorBody.ts | 6 + src/api/types/UnauthorizedErrorBody.ts | 6 + src/api/types/index.ts | 2 + src/auth/BearerAuthProvider.ts | 37 -- src/auth/OAuthAuthProvider.ts | 147 ++++++ src/auth/index.ts | 2 +- src/core/pagination/CustomPager.ts | 174 +++---- src/core/pagination/exports.ts | 1 - src/core/pagination/index.ts | 2 +- src/version.ts | 2 +- tests/mock-server/withFormUrlEncoded.ts | 23 +- tests/wire/entities.test.ts | 190 +++++++- tests/wire/mockAuth.ts | 27 ++ tests/wire/oauth.test.ts | 99 ++++ tests/wire/objects.test.ts | 142 ++++-- tests/wire/tasks.test.ts | 163 ++++++- 32 files changed, 1437 insertions(+), 452 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 src/api/resources/oauth/client/Client.ts create mode 100644 src/api/resources/oauth/client/index.ts create mode 100644 src/api/resources/oauth/client/requests/GetTokenRequest.ts create mode 100644 src/api/resources/oauth/client/requests/index.ts create mode 100644 src/api/resources/oauth/index.ts create mode 100644 src/api/resources/oauth/types/GetTokenResponse.ts create mode 100644 src/api/resources/oauth/types/index.ts create mode 100644 src/api/types/BadRequestErrorBody.ts create mode 100644 src/api/types/UnauthorizedErrorBody.ts delete mode 100644 src/auth/BearerAuthProvider.ts create mode 100644 src/auth/OAuthAuthProvider.ts create mode 100644 tests/wire/mockAuth.ts create mode 100644 tests/wire/oauth.test.ts diff --git a/.fern/metadata.json b/.fern/metadata.json index 6dfac06..ac086cf 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,8 +1,9 @@ { - "cliVersion": "3.17.0", + "cliVersion": "3.40.0", "generatorName": "fernapi/fern-typescript-node-sdk", - "generatorVersion": "3.39.3", + "generatorVersion": "3.42.8", "generatorConfig": { "namespaceExport": "Lattice" - } + }, + "sdkVersion": "5.0.0" } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fe5bc2f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,133 @@ +# Contributing + +Thanks for your interest in contributing to this SDK! This document provides guidelines for contributing to the project. + +## Getting Started + +### Prerequisites + +- Node.js 20 or higher +- pnpm package manager + +### Installation + +Install the project dependencies: + +```bash +pnpm install +``` + +### Building + +Build the project: + +```bash +pnpm build +``` + +### Testing + +Run the test suite: + +```bash +pnpm test +``` + +Run specific test types: +- `pnpm test:unit` - Run unit tests +- `pnpm test:wire` - Run wire/integration tests + +### Linting and Formatting + +Check code style: + +```bash +pnpm run lint +pnpm run format:check +``` + +Fix code style issues: + +```bash +pnpm run lint:fix +pnpm run format:fix +``` + +Or use the combined check command: + +```bash +pnpm run check:fix +``` + +## About Generated Code + +**Important**: Most files in this SDK are automatically generated by [Fern](https://buildwithfern.com) from the API definition. Direct modifications to generated files will be overwritten the next time the SDK is generated. + +### Generated Files + +The following directories contain generated code: +- `src/api/` - API client classes and types +- `src/serialization/` - Serialization/deserialization logic +- Most TypeScript files in `src/` + +### How to Customize + +If you need to customize the SDK, you have two options: + +#### Option 1: Use `.fernignore` + +For custom code that should persist across SDK regenerations: + +1. Create a `.fernignore` file in the project root +2. Add file patterns for files you want to preserve (similar to `.gitignore` syntax) +3. Add your custom code to those files + +Files listed in `.fernignore` will not be overwritten when the SDK is regenerated. + +For more information, see the [Fern documentation on custom code](https://buildwithfern.com/learn/sdks/overview/custom-code). + +#### Option 2: Contribute to the Generator + +If you want to change how code is generated for all users of this SDK: + +1. The TypeScript SDK generator lives in the [Fern repository](https://github.com/fern-api/fern) +2. Generator code is located at `generators/typescript/sdk/` +3. Follow the [Fern contributing guidelines](https://github.com/fern-api/fern/blob/main/CONTRIBUTING.md) +4. Submit a pull request with your changes to the generator + +This approach is best for: +- Bug fixes in generated code +- New features that would benefit all users +- Improvements to code generation patterns + +## Making Changes + +### Workflow + +1. Create a new branch for your changes +2. Make your modifications +3. Run tests to ensure nothing breaks: `pnpm test` +4. Run linting and formatting: `pnpm run check:fix` +5. Build the project: `pnpm build` +6. Commit your changes with a clear commit message +7. Push your branch and create a pull request + +### Commit Messages + +Write clear, descriptive commit messages that explain what changed and why. + +### Code Style + +This project uses automated code formatting and linting. Run `pnpm run check:fix` before committing to ensure your code meets the project's style guidelines. + +## Questions or Issues? + +If you have questions or run into issues: + +1. Check the [Fern documentation](https://buildwithfern.com) +2. Search existing [GitHub issues](https://github.com/fern-api/fern/issues) +3. Open a new issue if your question hasn't been addressed + +## License + +By contributing to this project, you agree that your contributions will be licensed under the same license as the project. diff --git a/README.md b/README.md index 8f3b453..64c46e9 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The Lattice SDK TypeScript library provides convenient access to the Lattice SDK - [Support](#support) - [Reference](#reference) - [Usage](#usage) +- [Authentication](#authentication) - [Request and Response Types](#request-and-response-types) - [Exception Handling](#exception-handling) - [Streaming Response](#streaming-response) @@ -61,12 +62,43 @@ Instantiate and use the client with the following: ```typescript import { LatticeClient } from "@anduril-industries/lattice-sdk"; -const client = new LatticeClient({ token: "YOUR_TOKEN" }); +const client = new LatticeClient({ clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET" }); await client.entities.longPollEntityEvents({ sessionToken: "sessionToken" }); ``` +## Authentication + +The SDK supports OAuth authentication with two options: + +**Option 1: OAuth Client Credentials Flow** + +Use this when you want the SDK to automatically handle OAuth token retrieval and refreshing: + +```typescript +import { LatticeClient } from "@anduril-industries/lattice-sdk"; + +const client = new LatticeClient({ + clientId: "YOUR_CLIENT_ID", + clientSecret: "YOUR_CLIENT_SECRET", + ... +}); +``` + +**Option 2: Token Override** + +Use this when you already have a valid bearer token and want to skip the OAuth flow: + +```typescript +import { LatticeClient } from "@anduril-industries/lattice-sdk"; + +const client = new LatticeClient({ + token: "my-pre-generated-bearer-token", + ... +}); +``` + ## Request and Response Types The SDK exports all request and response types as TypeScript interfaces. Simply import them with the @@ -108,7 +140,7 @@ The SDK uses async iterators, so you can consume the responses using a `for awai ```typescript import { LatticeClient } from "@anduril-industries/lattice-sdk"; -const client = new LatticeClient({ token: "YOUR_TOKEN" }); +const client = new LatticeClient({ clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET" }); const response = await client.entities.streamEntities(); for await (const item of response) { console.log(item); @@ -556,7 +588,7 @@ List endpoints are paginated. The SDK provides an iterator so that you can simpl ```typescript import { LatticeClient } from "@anduril-industries/lattice-sdk"; -const client = new LatticeClient({ token: "YOUR_TOKEN" }); +const client = new LatticeClient({ clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET" }); const pageableResponse = await client.objects.listObjects(); for await (const item of pageableResponse) { console.log(item); diff --git a/package.json b/package.json index 7a41587..08cd7d7 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "@anduril-industries/lattice-sdk", - "version": "4.0.0", + "version": "5.0.0", "private": false, - "repository": "github:anduril/lattice-sdk-javascript", + "repository": { + "type": "git", + "url": "git+https://github.com/anduril/lattice-sdk-javascript.git" + }, "license": "See LICENSE", "type": "commonjs", "main": "./dist/cjs/index.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4db7755..408add9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 2.11.2(@types/node@18.19.130)(typescript@5.7.3) ts-loader: specifier: ^9.5.1 - version: 9.5.4(typescript@5.7.3)(webpack@5.103.0) + version: 9.5.4(typescript@5.7.3)(webpack@5.104.1) typescript: specifier: ~5.7.2 version: 5.7.3 @@ -28,7 +28,7 @@ importers: version: 3.2.4(@types/node@18.19.130)(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(terser@5.44.1) webpack: specifier: ^5.97.1 - version: 5.103.0 + version: 5.104.1 packages: @@ -91,158 +91,158 @@ packages: '@bundled-es-modules/statuses@1.0.1': resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -311,113 +311,113 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.53.5': + resolution: {integrity: sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.53.5': + resolution: {integrity: sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.53.5': + resolution: {integrity: sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.53.5': + resolution: {integrity: sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.53.5': + resolution: {integrity: sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.53.5': + resolution: {integrity: sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.53.5': + resolution: {integrity: sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.53.5': + resolution: {integrity: sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.53.5': + resolution: {integrity: sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.53.5': + resolution: {integrity: sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-gnu@4.53.5': + resolution: {integrity: sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-ppc64-gnu@4.53.5': + resolution: {integrity: sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-riscv64-gnu@4.53.5': + resolution: {integrity: sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.53.5': + resolution: {integrity: sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.53.5': + resolution: {integrity: sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.53.5': + resolution: {integrity: sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.53.5': + resolution: {integrity: sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openharmony-arm64@4.53.5': + resolution: {integrity: sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.53.5': + resolution: {integrity: sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.53.5': + resolution: {integrity: sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.53.5': + resolution: {integrity: sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.53.5': + resolution: {integrity: sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==} cpu: [x64] os: [win32] @@ -567,8 +567,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - baseline-browser-mapping@2.9.6: - resolution: {integrity: sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==} + baseline-browser-mapping@2.9.10: + resolution: {integrity: sha512-2VIKvDx8Z1a9rTB2eCkdPE5nSe28XnA+qivGnWHoB40hMMt/h1hSz0960Zqsn6ZyxWXUie0EBdElKv8may20AA==} hasBin: true braces@3.0.3: @@ -654,8 +654,11 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true @@ -854,8 +857,8 @@ packages: rettime@0.7.0: resolution: {integrity: sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==} - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.53.5: + resolution: {integrity: sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1009,8 +1012,8 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -1020,8 +1023,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@7.2.7: - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1096,8 +1099,8 @@ packages: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} - webpack@5.103.0: - resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -1180,82 +1183,82 @@ snapshots: dependencies: statuses: 2.0.2 - '@esbuild/aix-ppc64@0.25.12': + '@esbuild/aix-ppc64@0.27.2': optional: true - '@esbuild/android-arm64@0.25.12': + '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm@0.25.12': + '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-x64@0.25.12': + '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.25.12': + '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-x64@0.25.12': + '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.25.12': + '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.25.12': + '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/linux-arm64@0.25.12': + '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm@0.25.12': + '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-ia32@0.25.12': + '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-loong64@0.25.12': + '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-mips64el@0.25.12': + '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/openharmony-arm64@0.25.12': + '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/sunos-x64@0.25.12': + '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-arm64@0.25.12': + '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-ia32@0.25.12': + '@esbuild/win32-ia32@0.27.2': optional: true - '@esbuild/win32-x64@0.25.12': + '@esbuild/win32-x64@0.27.2': optional: true '@inquirer/ansi@1.0.2': {} @@ -1323,70 +1326,70 @@ snapshots: '@open-draft/until@2.1.0': {} - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-android-arm-eabi@4.53.5': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-android-arm64@4.53.5': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-darwin-arm64@4.53.5': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-darwin-x64@4.53.5': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.53.5': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-freebsd-x64@4.53.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.53.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.53.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.53.5': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.53.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.53.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.53.5': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-linux-x64-musl@4.53.5': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-openharmony-arm64@4.53.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.53.5': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-win32-ia32-msvc@4.53.5': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-win32-x64-gnu@4.53.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-x64-msvc@4.53.5': optional: true '@types/chai@5.2.3': @@ -1426,14 +1429,14 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.2.7(@types/node@18.19.130)(terser@5.44.1))': + '@vitest/mocker@3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.3.0(@types/node@18.19.130)(terser@5.44.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.11.2(@types/node@18.19.130)(typescript@5.7.3) - vite: 7.2.7(@types/node@18.19.130)(terser@5.44.1) + vite: 7.3.0(@types/node@18.19.130)(terser@5.44.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -1571,7 +1574,7 @@ snapshots: assertion-error@2.0.1: {} - baseline-browser-mapping@2.9.6: {} + baseline-browser-mapping@2.9.10: {} braces@3.0.3: dependencies: @@ -1579,11 +1582,11 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.6 + baseline-browser-mapping: 2.9.10 caniuse-lite: 1.0.30001760 electron-to-chromium: 1.5.267 node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + update-browserslist-db: 1.2.3(browserslist@4.28.1) buffer-from@1.1.2: {} @@ -1643,34 +1646,36 @@ snapshots: es-module-lexer@1.7.0: {} - esbuild@0.25.12: + es-module-lexer@2.0.0: {} + + esbuild@0.27.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 escalade@3.2.0: {} @@ -1827,32 +1832,32 @@ snapshots: rettime@0.7.0: {} - rollup@4.53.3: + rollup@4.53.5: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + '@rollup/rollup-android-arm-eabi': 4.53.5 + '@rollup/rollup-android-arm64': 4.53.5 + '@rollup/rollup-darwin-arm64': 4.53.5 + '@rollup/rollup-darwin-x64': 4.53.5 + '@rollup/rollup-freebsd-arm64': 4.53.5 + '@rollup/rollup-freebsd-x64': 4.53.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.5 + '@rollup/rollup-linux-arm-musleabihf': 4.53.5 + '@rollup/rollup-linux-arm64-gnu': 4.53.5 + '@rollup/rollup-linux-arm64-musl': 4.53.5 + '@rollup/rollup-linux-loong64-gnu': 4.53.5 + '@rollup/rollup-linux-ppc64-gnu': 4.53.5 + '@rollup/rollup-linux-riscv64-gnu': 4.53.5 + '@rollup/rollup-linux-riscv64-musl': 4.53.5 + '@rollup/rollup-linux-s390x-gnu': 4.53.5 + '@rollup/rollup-linux-x64-gnu': 4.53.5 + '@rollup/rollup-linux-x64-musl': 4.53.5 + '@rollup/rollup-openharmony-arm64': 4.53.5 + '@rollup/rollup-win32-arm64-msvc': 4.53.5 + '@rollup/rollup-win32-ia32-msvc': 4.53.5 + '@rollup/rollup-win32-x64-gnu': 4.53.5 + '@rollup/rollup-win32-x64-msvc': 4.53.5 fsevents: 2.3.3 safe-buffer@5.2.1: {} @@ -1917,14 +1922,14 @@ snapshots: tapable@2.3.0: {} - terser-webpack-plugin@5.3.16(webpack@5.103.0): + terser-webpack-plugin@5.3.16(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.1 - webpack: 5.103.0 + webpack: 5.104.1 terser@5.44.1: dependencies: @@ -1962,7 +1967,7 @@ snapshots: dependencies: tldts: 7.0.19 - ts-loader@9.5.4(typescript@5.7.3)(webpack@5.103.0): + ts-loader@9.5.4(typescript@5.7.3)(webpack@5.104.1): dependencies: chalk: 4.1.2 enhanced-resolve: 5.18.4 @@ -1970,7 +1975,7 @@ snapshots: semver: 7.7.3 source-map: 0.7.6 typescript: 5.7.3 - webpack: 5.103.0 + webpack: 5.104.1 type-fest@4.41.0: {} @@ -1978,7 +1983,7 @@ snapshots: undici-types@5.26.5: {} - update-browserslist-db@1.2.2(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 @@ -1990,7 +1995,7 @@ snapshots: debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.2.7(@types/node@18.19.130)(terser@5.44.1) + vite: 7.3.0(@types/node@18.19.130)(terser@5.44.1) transitivePeerDependencies: - '@types/node' - jiti @@ -2005,13 +2010,13 @@ snapshots: - tsx - yaml - vite@7.2.7(@types/node@18.19.130)(terser@5.44.1): + vite@7.3.0(@types/node@18.19.130)(terser@5.44.1): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.53.3 + rollup: 4.53.5 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 18.19.130 @@ -2022,7 +2027,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.2.7(@types/node@18.19.130)(terser@5.44.1)) + '@vitest/mocker': 3.2.4(msw@2.11.2(@types/node@18.19.130)(typescript@5.7.3))(vite@7.3.0(@types/node@18.19.130)(terser@5.44.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -2040,7 +2045,7 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.2.7(@types/node@18.19.130)(terser@5.44.1) + vite: 7.3.0(@types/node@18.19.130)(terser@5.44.1) vite-node: 3.2.4(@types/node@18.19.130)(terser@5.44.1) why-is-node-running: 2.3.0 optionalDependencies: @@ -2066,7 +2071,7 @@ snapshots: webpack-sources@3.3.3: {} - webpack@5.103.0: + webpack@5.104.1: dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -2079,7 +2084,7 @@ snapshots: browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.4 - es-module-lexer: 1.7.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -2090,7 +2095,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(webpack@5.103.0) + terser-webpack-plugin: 5.3.16(webpack@5.104.1) watchpack: 2.4.4 webpack-sources: 3.3.3 transitivePeerDependencies: diff --git a/reference.md b/reference.md index b8a6647..e58ebec 100644 --- a/reference.md +++ b/reference.md @@ -1130,6 +1130,70 @@ await client.objects.getObjectMetadata({ + + + + +## oauth +
client.oauth.getToken({ ...params }) -> Lattice.GetTokenResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Gets a new short-lived token using the specified client credentials +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.oauth.getToken({}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Lattice.GetTokenRequest` + +
+
+ +
+
+ +**requestOptions:** `OauthClient.RequestOptions` + +
+
+
+
+ +
diff --git a/src/BaseClient.ts b/src/BaseClient.ts index e8065ae..236ecf7 100644 --- a/src/BaseClient.ts +++ b/src/BaseClient.ts @@ -1,6 +1,6 @@ // This file was auto-generated by Fern from our API Definition. -import { BearerAuthProvider } from "./auth/BearerAuthProvider.js"; +import { OAuthAuthProvider } from "./auth/OAuthAuthProvider.js"; import { mergeHeaders } from "./core/headers.js"; import * as core from "./core/index.js"; import type * as environments from "./environments.js"; @@ -19,7 +19,7 @@ export type BaseClientOptions = { fetch?: typeof fetch; /** Configure logging for the client. */ logging?: core.logging.LogConfig | core.logging.Logger; -} & BearerAuthProvider.AuthOptions; +} & OAuthAuthProvider.AuthOptions; export interface BaseRequestOptions { /** The maximum time to wait for a response in seconds. */ @@ -34,22 +34,25 @@ export interface BaseRequestOptions { headers?: Record | null | undefined>; } -export type NormalizedClientOptions = T & { +export type NormalizedClientOptions = T & { logging: core.logging.Logger; authProvider?: core.AuthProvider; }; -export type NormalizedClientOptionsWithAuth = NormalizedClientOptions & { - authProvider: core.AuthProvider; -}; +export type NormalizedClientOptionsWithAuth = + NormalizedClientOptions & { + authProvider: core.AuthProvider; + }; -export function normalizeClientOptions(options: T): NormalizedClientOptions { +export function normalizeClientOptions( + options: T, +): NormalizedClientOptions { const headers = mergeHeaders( { "X-Fern-Language": "JavaScript", "X-Fern-SDK-Name": "@anduril-industries/lattice-sdk", - "X-Fern-SDK-Version": "4.0.0", - "User-Agent": "@anduril-industries/lattice-sdk/4.0.0", + "X-Fern-SDK-Version": "5.0.0", + "User-Agent": "@anduril-industries/lattice-sdk/5.0.0", "X-Fern-Runtime": core.RUNTIME.type, "X-Fern-Runtime-Version": core.RUNTIME.version, }, @@ -63,16 +66,16 @@ export function normalizeClientOptions(options: T): } as NormalizedClientOptions; } -export function normalizeClientOptionsWithAuth( +export function normalizeClientOptionsWithAuth( options: T, ): NormalizedClientOptionsWithAuth { const normalized = normalizeClientOptions(options) as NormalizedClientOptionsWithAuth; const normalizedWithNoOpAuthProvider = withNoOpAuthProvider(normalized); - normalized.authProvider ??= new BearerAuthProvider(normalizedWithNoOpAuthProvider); + normalized.authProvider ??= OAuthAuthProvider.createInstance(normalizedWithNoOpAuthProvider); return normalized; } -function withNoOpAuthProvider( +function withNoOpAuthProvider( options: NormalizedClientOptions, ): NormalizedClientOptionsWithAuth { return { diff --git a/src/Client.ts b/src/Client.ts index 9144377..7342098 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,6 +1,7 @@ // This file was auto-generated by Fern from our API Definition. import { EntitiesClient } from "./api/resources/entities/client/Client.js"; +import { OauthClient } from "./api/resources/oauth/client/Client.js"; import { ObjectsClient } from "./api/resources/objects/client/Client.js"; import { TasksClient } from "./api/resources/tasks/client/Client.js"; import type { BaseClientOptions, BaseRequestOptions } from "./BaseClient.js"; @@ -17,6 +18,7 @@ export class LatticeClient { protected _entities: EntitiesClient | undefined; protected _tasks: TasksClient | undefined; protected _objects: ObjectsClient | undefined; + protected _oauth: OauthClient | undefined; constructor(options: LatticeClient.Options) { this._options = normalizeClientOptionsWithAuth(options); @@ -33,4 +35,8 @@ export class LatticeClient { public get objects(): ObjectsClient { return (this._objects ??= new ObjectsClient(this._options)); } + + public get oauth(): OauthClient { + return (this._oauth ??= new OauthClient(this._options)); + } } diff --git a/src/api/resources/index.ts b/src/api/resources/index.ts index 64d9d8a..2c79610 100644 --- a/src/api/resources/index.ts +++ b/src/api/resources/index.ts @@ -2,6 +2,9 @@ export * from "./entities/client/requests/index.js"; export * as entities from "./entities/index.js"; export * from "./entities/types/index.js"; export * as entity from "./entity/index.js"; +export * from "./oauth/client/requests/index.js"; +export * as oauth from "./oauth/index.js"; +export * from "./oauth/types/index.js"; export * as object from "./object/index.js"; export * from "./objects/client/requests/index.js"; export * as objects from "./objects/index.js"; diff --git a/src/api/resources/oauth/client/Client.ts b/src/api/resources/oauth/client/Client.ts new file mode 100644 index 0000000..8e4e3f3 --- /dev/null +++ b/src/api/resources/oauth/client/Client.ts @@ -0,0 +1,89 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { BaseClientOptions, BaseRequestOptions } from "../../../../BaseClient.js"; +import { type NormalizedClientOptionsWithAuth, normalizeClientOptionsWithAuth } from "../../../../BaseClient.js"; +import { mergeHeaders } from "../../../../core/headers.js"; +import * as core from "../../../../core/index.js"; +import * as environments from "../../../../environments.js"; +import { handleNonStatusCodeError } from "../../../../errors/handleNonStatusCodeError.js"; +import * as errors from "../../../../errors/index.js"; +import * as Lattice from "../../../index.js"; + +export declare namespace OauthClient { + export type Options = BaseClientOptions; + + export interface RequestOptions extends BaseRequestOptions {} +} + +export class OauthClient { + protected readonly _options: NormalizedClientOptionsWithAuth; + + constructor(options: OauthClient.Options) { + this._options = normalizeClientOptionsWithAuth(options); + } + + /** + * Gets a new short-lived token using the specified client credentials + * + * @param {Lattice.GetTokenRequest} request + * @param {OauthClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Lattice.BadRequestError} + * @throws {@link Lattice.UnauthorizedError} + * + * @example + * await client.oauth.getToken({}) + */ + public getToken( + request: Lattice.GetTokenRequest, + requestOptions?: OauthClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__getToken(request, requestOptions)); + } + + private async __getToken( + request: Lattice.GetTokenRequest, + requestOptions?: OauthClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders(this._options?.headers, requestOptions?.headers); + const _response = await core.fetcher({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)) ?? + environments.LatticeEnvironment.Default, + "api/v1/oauth/token", + ), + method: "POST", + headers: _headers, + contentType: "application/x-www-form-urlencoded", + queryParameters: requestOptions?.queryParams, + requestType: "form", + body: { ...request, grant_type: "client_credentials" }, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as Lattice.GetTokenResponse, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 400: + throw new Lattice.BadRequestError(_response.error.body as unknown, _response.rawResponse); + case 401: + throw new Lattice.UnauthorizedError(_response.error.body as unknown, _response.rawResponse); + default: + throw new errors.LatticeError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/api/v1/oauth/token"); + } +} diff --git a/src/api/resources/oauth/client/index.ts b/src/api/resources/oauth/client/index.ts new file mode 100644 index 0000000..195f9aa --- /dev/null +++ b/src/api/resources/oauth/client/index.ts @@ -0,0 +1 @@ +export * from "./requests/index.js"; diff --git a/src/api/resources/oauth/client/requests/GetTokenRequest.ts b/src/api/resources/oauth/client/requests/GetTokenRequest.ts new file mode 100644 index 0000000..435b784 --- /dev/null +++ b/src/api/resources/oauth/client/requests/GetTokenRequest.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by Fern from our API Definition. + +/** + * @example + * {} + */ +export interface GetTokenRequest { + /** The client identifier */ + client_id?: string; + /** The client secret */ + client_secret?: string; +} diff --git a/src/api/resources/oauth/client/requests/index.ts b/src/api/resources/oauth/client/requests/index.ts new file mode 100644 index 0000000..3bf23ef --- /dev/null +++ b/src/api/resources/oauth/client/requests/index.ts @@ -0,0 +1 @@ +export type { GetTokenRequest } from "./GetTokenRequest.js"; diff --git a/src/api/resources/oauth/index.ts b/src/api/resources/oauth/index.ts new file mode 100644 index 0000000..d9adb1a --- /dev/null +++ b/src/api/resources/oauth/index.ts @@ -0,0 +1,2 @@ +export * from "./client/index.js"; +export * from "./types/index.js"; diff --git a/src/api/resources/oauth/types/GetTokenResponse.ts b/src/api/resources/oauth/types/GetTokenResponse.ts new file mode 100644 index 0000000..1f6ec45 --- /dev/null +++ b/src/api/resources/oauth/types/GetTokenResponse.ts @@ -0,0 +1,16 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface GetTokenResponse { + /** The access token */ + access_token: string; + /** The type of token (typically "Bearer") */ + token_type: string; + /** Lifetime of the access token in seconds */ + expires_in?: number; + /** Lifetime of the refresh token */ + refresh_expires_in?: number; + /** Enforce that a token cannot be used before a specific unixtime */ + "not-before-policy"?: number; + /** The scope of the access token */ + scope?: string; +} diff --git a/src/api/resources/oauth/types/index.ts b/src/api/resources/oauth/types/index.ts new file mode 100644 index 0000000..cecadaf --- /dev/null +++ b/src/api/resources/oauth/types/index.ts @@ -0,0 +1 @@ +export * from "./GetTokenResponse.js"; diff --git a/src/api/types/BadRequestErrorBody.ts b/src/api/types/BadRequestErrorBody.ts new file mode 100644 index 0000000..f31c4f0 --- /dev/null +++ b/src/api/types/BadRequestErrorBody.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface BadRequestErrorBody { + error: string; + error_description?: string; +} diff --git a/src/api/types/UnauthorizedErrorBody.ts b/src/api/types/UnauthorizedErrorBody.ts new file mode 100644 index 0000000..522d20a --- /dev/null +++ b/src/api/types/UnauthorizedErrorBody.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface UnauthorizedErrorBody { + error: string; + error_description?: string; +} diff --git a/src/api/types/index.ts b/src/api/types/index.ts index af29099..c097bc2 100644 --- a/src/api/types/index.ts +++ b/src/api/types/index.ts @@ -8,6 +8,7 @@ export * from "./Aliases.js"; export * from "./Allocation.js"; export * from "./AlternateId.js"; export * from "./AngleOfArrival.js"; +export * from "./BadRequestErrorBody.js"; export * from "./Bandwidth.js"; export * from "./BandwidthRange.js"; export * from "./CancelRequest.js"; @@ -139,5 +140,6 @@ export * from "./Tracked.js"; export * from "./TrackedBy.js"; export * from "./TransponderCodes.js"; export * from "./UInt32Range.js"; +export * from "./UnauthorizedErrorBody.js"; export * from "./User.js"; export * from "./VisualDetails.js"; diff --git a/src/auth/BearerAuthProvider.ts b/src/auth/BearerAuthProvider.ts deleted file mode 100644 index 943c8aa..0000000 --- a/src/auth/BearerAuthProvider.ts +++ /dev/null @@ -1,37 +0,0 @@ -// This file was auto-generated by Fern from our API Definition. - -import * as core from "../core/index.js"; -import * as errors from "../errors/index.js"; - -export namespace BearerAuthProvider { - export interface AuthOptions { - token: core.Supplier; - } - - export interface Options extends AuthOptions {} -} - -export class BearerAuthProvider implements core.AuthProvider { - private readonly token: core.Supplier; - - constructor(options: BearerAuthProvider.Options) { - this.token = options.token; - } - - public static canCreate(options: BearerAuthProvider.Options): boolean { - return options.token != null; - } - - public async getAuthRequest(_arg?: { endpointMetadata?: core.EndpointMetadata }): Promise { - const token = await core.Supplier.get(this.token); - if (token == null) { - throw new errors.LatticeError({ - message: "Please specify a token by passing it in to the constructor", - }); - } - - return { - headers: { Authorization: `Bearer ${token}` }, - }; - } -} diff --git a/src/auth/OAuthAuthProvider.ts b/src/auth/OAuthAuthProvider.ts new file mode 100644 index 0000000..aaa0609 --- /dev/null +++ b/src/auth/OAuthAuthProvider.ts @@ -0,0 +1,147 @@ +// This file was auto-generated by Fern from our API Definition. + +import { OauthClient } from "../api/resources/oauth/client/Client.js"; +import type { BaseClientOptions } from "../BaseClient.js"; +import * as core from "../core/index.js"; +import * as errors from "../errors/index.js"; + +export class OAuthAuthProvider implements core.AuthProvider { + private readonly BUFFER_IN_MINUTES: number = 2; + private readonly _clientId: core.Supplier; + private readonly _clientSecret: core.Supplier; + private readonly _authClient: OauthClient; + private _accessToken: string | undefined; + private _expiresAt: Date; + private _refreshPromise: Promise | undefined; + + constructor(options: OAuthAuthProvider.Options & OAuthAuthProvider.AuthOptions.ClientCredentials) { + if (options.clientId == null) { + throw new errors.LatticeError({ + message: "clientId is required. Please provide it in options.", + }); + } + this._clientId = options.clientId; + if (options.clientSecret == null) { + throw new errors.LatticeError({ + message: "clientSecret is required. Please provide it in options.", + }); + } + this._clientSecret = options.clientSecret; + this._authClient = new OauthClient(options); + this._expiresAt = new Date(); + } + + public static canCreate( + options: OAuthAuthProvider.Options, + ): options is OAuthAuthProvider.Options & OAuthAuthProvider.AuthOptions.ClientCredentials { + return ( + "clientId" in options && + options.clientId != null && + "clientSecret" in options && + options.clientSecret != null + ); + } + + public async getAuthRequest(arg?: { endpointMetadata?: core.EndpointMetadata }): Promise { + const token = await this.getToken(arg); + + return { + headers: { + Authorization: `Bearer ${token}`, + }, + }; + } + + private async getToken(arg?: { endpointMetadata?: core.EndpointMetadata }): Promise { + if (this._accessToken && this._expiresAt > new Date()) { + return this._accessToken; + } + // If a refresh is already in progress, return the existing promise + if (this._refreshPromise != null) { + return this._refreshPromise; + } + return this.refresh(arg); + } + + private async refresh(_arg?: { endpointMetadata?: core.EndpointMetadata }): Promise { + this._refreshPromise = (async () => { + try { + const clientId = await core.Supplier.get(this._clientId); + + const clientSecret = await core.Supplier.get(this._clientSecret); + const tokenResponse = await this._authClient.getToken({ + client_id: clientId, + client_secret: clientSecret, + }); + + this._accessToken = tokenResponse.access_token; + this._expiresAt = this.getExpiresAt(tokenResponse.expires_in ?? 3600, this.BUFFER_IN_MINUTES); + return this._accessToken; + } finally { + this._refreshPromise = undefined; + } + })(); + return this._refreshPromise; + } + + private getExpiresAt(expiresInSeconds: number, bufferInMinutes: number): Date { + const now = new Date(); + return new Date(now.getTime() + expiresInSeconds * 1000 - bufferInMinutes * 60 * 1000); + } +} + +export class OAuthTokenOverrideAuthProvider implements core.AuthProvider { + private readonly _token: core.Supplier; + + constructor(options: OAuthAuthProvider.Options & OAuthAuthProvider.AuthOptions.TokenOverride) { + if (options.token == null) { + throw new errors.LatticeError({ + message: "token is required. Please provide it in options.", + }); + } + this._token = options.token; + } + + public static canCreate( + options: OAuthAuthProvider.Options, + ): options is OAuthAuthProvider.Options & OAuthAuthProvider.AuthOptions.TokenOverride { + return "token" in options && options.token != null; + } + + public async getAuthRequest(_arg?: { endpointMetadata?: core.EndpointMetadata }): Promise { + return { + headers: { + Authorization: `Bearer ${await core.Supplier.get(this._token)}`, + }, + }; + } +} + +export namespace OAuthAuthProvider { + export type AuthOptions = AuthOptions.ClientCredentials | AuthOptions.TokenOverride; + + export namespace AuthOptions { + export interface ClientCredentials { + clientId: core.Supplier; + clientSecret: core.Supplier; + } + + export interface TokenOverride { + token: core.Supplier; + } + } + + export type Options = BaseClientOptions; + + export function createInstance(options: Options): core.AuthProvider { + if (OAuthTokenOverrideAuthProvider.canCreate(options)) { + return new OAuthTokenOverrideAuthProvider(options); + } else if (OAuthAuthProvider.canCreate(options)) { + return new OAuthAuthProvider(options); + } + throw new errors.LatticeError({ + message: + "Insufficient options to create OAuthAuthProvider. Please provide either clientId and clientSecret, or token.", + }); + } +} diff --git a/src/auth/index.ts b/src/auth/index.ts index 0ecb12b..83e326d 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -1 +1 @@ -export { BearerAuthProvider } from "./BearerAuthProvider.js"; +export { OAuthAuthProvider } from "./OAuthAuthProvider.js"; diff --git a/src/core/pagination/CustomPager.ts b/src/core/pagination/CustomPager.ts index c810b7e..f9bb918 100644 --- a/src/core/pagination/CustomPager.ts +++ b/src/core/pagination/CustomPager.ts @@ -1,41 +1,14 @@ -import type { HttpResponsePromise, RawResponse, WithRawResponse } from "../fetcher/index.js"; +import type { BaseRequestOptions, NormalizedClientOptions } from "../../BaseClient.js"; +import type { APIResponse } from "../fetcher/APIResponse.js"; +import type { Fetcher } from "../fetcher/Fetcher.js"; +import type { RawResponse } from "../fetcher/index.js"; /** - * Parser function type for custom pagination. - * SDK authors implement this to define how to extract items and determine pagination state. - * - * @template TItem The type of items in the paginated response. - * @template TRequest The type of the request object. - * @template TResponse The type of the API response. - */ -export type CustomPagerParser = ( - request: TRequest, - response: WithRawResponse, -) => Promise<{ - /** The request to use for fetching the next page, if any */ - nextRequest?: TRequest; - /** Whether there is a next page available */ - hasNextPage: boolean; - /** The request to use for fetching the previous page, if any */ - previousRequest?: TRequest; - /** Whether there is a previous page available */ - hasPreviousPage: boolean; - /** The items extracted from the current response */ - items: TItem[]; -}>; - -/** - * A custom pager for paginated API responses where the pagination logic - * must be implemented by the SDK author. - * - * SDK authors provide a parser callback to extract items and determine - * pagination state from responses. * * @template TItem The type of the items in the page. - * @template TRequest The type of the request object. * @template TResponse The type of the API response. */ -export class CustomPager implements AsyncIterable { +export class CustomPager implements AsyncIterable { /** The items from the current page */ public data: TItem[]; /** The raw HTTP response */ @@ -43,29 +16,21 @@ export class CustomPager implements AsyncIterable HttpResponsePromise; - currentRequest: TRequest; - }; - private parser: CustomPagerParser; - private nextRequest?: TRequest; - private previousRequest?: TRequest; + private sendRequest: (request: Fetcher.Args) => Promise>; + private nextRequest?: Fetcher.Args; + private previousRequest?: Fetcher.Args; private _hasNextPage: boolean; private _hasPreviousPage: boolean; - private constructor(args: { + constructor(args: { response: TResponse; rawResponse: RawResponse; items: TItem[]; hasNextPage: boolean; hasPreviousPage: boolean; - nextRequest?: TRequest; - previousRequest?: TRequest; - context: { - sendRequest: (request: TRequest) => HttpResponsePromise; - currentRequest: TRequest; - }; - parser: CustomPagerParser; + nextRequest?: Fetcher.Args; + previousRequest?: Fetcher.Args; + sendRequest: (request: Fetcher.Args) => Promise>; }) { this.response = args.response; this.rawResponse = args.rawResponse; @@ -74,8 +39,7 @@ export class CustomPager implements AsyncIterable implements AsyncIterable implements AsyncIterable({ request: this.nextRequest, data, rawResponse }); this.response = data; this.rawResponse = rawResponse; this.data = parsed.items; this._hasNextPage = parsed.hasNextPage; this._hasPreviousPage = parsed.hasPreviousPage; - this.context.currentRequest = this.nextRequest; this.nextRequest = parsed.nextRequest; this.previousRequest = parsed.previousRequest; return this; @@ -123,14 +103,20 @@ export class CustomPager implements AsyncIterable({ request: this.previousRequest, data, rawResponse }); this.response = data; this.rawResponse = rawResponse; this.data = parsed.items; this._hasNextPage = parsed.hasNextPage; this._hasPreviousPage = parsed.hasPreviousPage; - this.context.currentRequest = this.previousRequest; this.nextRequest = parsed.nextRequest; this.previousRequest = parsed.previousRequest; return this; @@ -154,35 +140,55 @@ export class CustomPager implements AsyncIterable(args: { - sendRequest: (request: TRequest) => HttpResponsePromise; - initialRequest: TRequest; - parse: CustomPagerParser; - }): Promise> { - const { data, rawResponse } = await args.sendRequest(args.initialRequest).withRawResponse(); - const parsed = await args.parse(args.initialRequest, { data, rawResponse }); - return new CustomPager({ - response: data, - rawResponse, - items: parsed.items, - hasNextPage: parsed.hasNextPage, - hasPreviousPage: parsed.hasPreviousPage, - nextRequest: parsed.nextRequest, - previousRequest: parsed.previousRequest, - context: { - sendRequest: args.sendRequest, - currentRequest: args.initialRequest, - }, - parser: args.parse, - }); +export async function createCustomPager({ + sendRequest, + initialHttpRequest, + clientOptions, +}: { + sendRequest: (request: Fetcher.Args) => Promise>; + initialHttpRequest: Fetcher.Args; + clientOptions: NormalizedClientOptions; + requestOptions?: BaseRequestOptions; +}): Promise> { + const response = await sendRequest(initialHttpRequest); + if (!response.ok) { + const reason = + response.error.reason === "status-code" ? `HTTP ${response.error.statusCode}` : response.error.reason; + throw new Error(`Failed to fetch initial page: ${reason}`); } + const data = response.body; + const rawResponse = response.rawResponse; + const parsed = await parse({ request: initialHttpRequest, data, rawResponse }); + return new CustomPager({ + response: data, + rawResponse, + items: parsed.items, + hasNextPage: parsed.hasNextPage, + hasPreviousPage: parsed.hasPreviousPage, + nextRequest: parsed.nextRequest, + previousRequest: parsed.previousRequest, + sendRequest: sendRequest, + }); +} + +async function parse(_args: { + request: Fetcher.Args; + data: TResponse; + rawResponse: RawResponse; +}): Promise<{ + nextRequest?: Fetcher.Args; + hasNextPage: boolean; + previousRequest?: Fetcher.Args; + hasPreviousPage: boolean; + items: TItem[]; +}> { + // Placeholder implementation. + // TODO: Replace this with actual parsing logic. + return { + items: [], + hasNextPage: false, + hasPreviousPage: false, + }; } diff --git a/src/core/pagination/exports.ts b/src/core/pagination/exports.ts index c386a05..d3acc60 100644 --- a/src/core/pagination/exports.ts +++ b/src/core/pagination/exports.ts @@ -1,2 +1 @@ -export { CustomPager, type CustomPagerParser } from "./CustomPager.js"; export type { Page } from "./Page.js"; diff --git a/src/core/pagination/index.ts b/src/core/pagination/index.ts index 97d348c..fe9dc94 100644 --- a/src/core/pagination/index.ts +++ b/src/core/pagination/index.ts @@ -1,2 +1,2 @@ -export { CustomPager, type CustomPagerParser } from "./CustomPager.js"; +export { CustomPager, createCustomPager } from "./CustomPager.js"; export { Page } from "./Page.js"; diff --git a/src/version.ts b/src/version.ts index c8a6ab3..c0103fd 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const SDK_VERSION = "4.0.0"; +export const SDK_VERSION = "5.0.0"; diff --git a/tests/mock-server/withFormUrlEncoded.ts b/tests/mock-server/withFormUrlEncoded.ts index e9e6ff2..e250cb3 100644 --- a/tests/mock-server/withFormUrlEncoded.ts +++ b/tests/mock-server/withFormUrlEncoded.ts @@ -18,13 +18,22 @@ export function withFormUrlEncoded(expectedBody: unknown, resolver: HttpResponse clonedRequest = request.clone(); bodyText = await clonedRequest.text(); if (bodyText === "") { - console.error("Request body is empty, expected a form-urlencoded body."); - return passthrough(); - } - const params = new URLSearchParams(bodyText); - actualBody = {}; - for (const [key, value] of params.entries()) { - actualBody[key] = value; + // Empty body is valid if expected body is also empty + const isExpectedEmpty = + expectedBody != null && + typeof expectedBody === "object" && + Object.keys(expectedBody as Record).length === 0; + if (!isExpectedEmpty) { + console.error("Request body is empty, expected a form-urlencoded body."); + return passthrough(); + } + actualBody = {}; + } else { + const params = new URLSearchParams(bodyText); + actualBody = {}; + for (const [key, value] of params.entries()) { + actualBody[key] = value; + } } } catch (error) { console.error(`Error processing form-urlencoded request body:\n\tError: ${error}\n\tBody: ${bodyText}`); diff --git a/tests/wire/entities.test.ts b/tests/wire/entities.test.ts index 5693906..22f4c41 100644 --- a/tests/wire/entities.test.ts +++ b/tests/wire/entities.test.ts @@ -3,11 +3,19 @@ import * as Lattice from "../../src/api/index"; import { LatticeClient } from "../../src/Client"; import { mockServerPool } from "../mock-server/MockServerPool"; +import { mockOAuth } from "./mockAuth"; describe("EntitiesClient", () => { test("publishEntity (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { entityId: "entityId", @@ -388,7 +396,14 @@ describe("EntitiesClient", () => { test("publishEntity (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -407,7 +422,14 @@ describe("EntitiesClient", () => { test("publishEntity (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -426,7 +448,14 @@ describe("EntitiesClient", () => { test("getEntity (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { entityId: "entityId", @@ -808,7 +837,14 @@ describe("EntitiesClient", () => { test("getEntity (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -828,7 +864,14 @@ describe("EntitiesClient", () => { test("getEntity (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -848,7 +891,14 @@ describe("EntitiesClient", () => { test("getEntity (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -868,7 +918,14 @@ describe("EntitiesClient", () => { test("overrideEntity (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { entityId: "entityId", @@ -1252,7 +1309,14 @@ describe("EntitiesClient", () => { test("overrideEntity (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -1274,7 +1338,14 @@ describe("EntitiesClient", () => { test("overrideEntity (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -1296,7 +1367,14 @@ describe("EntitiesClient", () => { test("overrideEntity (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -1318,7 +1396,14 @@ describe("EntitiesClient", () => { test("removeEntityOverride (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { entityId: "entityId", @@ -1701,7 +1786,14 @@ describe("EntitiesClient", () => { test("removeEntityOverride (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -1722,7 +1814,14 @@ describe("EntitiesClient", () => { test("removeEntityOverride (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -1743,7 +1842,14 @@ describe("EntitiesClient", () => { test("removeEntityOverride (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -1764,7 +1870,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { sessionToken: "sessionToken", @@ -1795,7 +1908,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { key: "value" }; server @@ -1816,7 +1936,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { key: "value" }; server @@ -1837,7 +1964,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { key: "value" }; server @@ -1858,7 +1992,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (5)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { key: "value" }; server @@ -1879,7 +2020,14 @@ describe("EntitiesClient", () => { test("longPollEntityEvents (6)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = { sessionToken: "sessionToken" }; const rawResponseBody = { key: "value" }; server diff --git a/tests/wire/mockAuth.ts b/tests/wire/mockAuth.ts new file mode 100644 index 0000000..b21fa9a --- /dev/null +++ b/tests/wire/mockAuth.ts @@ -0,0 +1,27 @@ +// This file was auto-generated by Fern from our API Definition. + +import type { MockServer } from "../mock-server/MockServer"; + +export function mockOAuth(server: MockServer): void { + const rawRequestBody = { + grant_type: "client_credentials", + client_id: "test_client_id", + client_secret: "test_client_secret", + }; + const rawResponseBody = { + access_token: "access_token", + token_type: "Bearer", + expires_in: 3600, + refresh_expires_in: 1, + "not-before-policy": 1, + scope: "scope", + }; + server + .mockEndpoint() + .post("/api/v1/oauth/token") + .formUrlEncodedBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); +} diff --git a/tests/wire/oauth.test.ts b/tests/wire/oauth.test.ts new file mode 100644 index 0000000..97ba3c3 --- /dev/null +++ b/tests/wire/oauth.test.ts @@ -0,0 +1,99 @@ +// This file was auto-generated by Fern from our API Definition. + +import * as Lattice from "../../src/api/index"; +import { LatticeClient } from "../../src/Client"; +import { mockServerPool } from "../mock-server/MockServerPool"; +import { mockOAuth } from "./mockAuth"; + +describe("OauthClient", () => { + test("getToken (1)", async () => { + const server = mockServerPool.createServer(); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); + const rawRequestBody = { grant_type: "client_credentials" }; + const rawResponseBody = { + access_token: "access_token", + token_type: "Bearer", + expires_in: 3600, + refresh_expires_in: 1, + "not-before-policy": 1, + scope: "scope", + }; + server + .mockEndpoint() + .post("/api/v1/oauth/token") + .formUrlEncodedBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.oauth.getToken({}); + expect(response).toEqual({ + access_token: "access_token", + token_type: "Bearer", + expires_in: 3600, + refresh_expires_in: 1, + "not-before-policy": 1, + scope: "scope", + }); + }); + + test("getToken (2)", async () => { + const server = mockServerPool.createServer(); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); + const rawRequestBody = { grant_type: "client_credentials" }; + const rawResponseBody = { key: "value" }; + server + .mockEndpoint() + .post("/api/v1/oauth/token") + .formUrlEncodedBody(rawRequestBody) + .respondWith() + .statusCode(400) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.oauth.getToken({}); + }).rejects.toThrow(Lattice.BadRequestError); + }); + + test("getToken (3)", async () => { + const server = mockServerPool.createServer(); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); + const rawRequestBody = { grant_type: "client_credentials" }; + const rawResponseBody = { key: "value" }; + server + .mockEndpoint() + .post("/api/v1/oauth/token") + .formUrlEncodedBody(rawRequestBody) + .respondWith() + .statusCode(401) + .jsonBody(rawResponseBody) + .build(); + + await expect(async () => { + return await client.oauth.getToken({}); + }).rejects.toThrow(Lattice.UnauthorizedError); + }); +}); diff --git a/tests/wire/objects.test.ts b/tests/wire/objects.test.ts index c569b81..ce308f8 100644 --- a/tests/wire/objects.test.ts +++ b/tests/wire/objects.test.ts @@ -3,11 +3,19 @@ import * as Lattice from "../../src/api/index"; import { LatticeClient } from "../../src/Client"; import { mockServerPool } from "../mock-server/MockServerPool"; +import { mockOAuth } from "./mockAuth"; describe("ObjectsClient", () => { test("listObjects (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { path_metadatas: [ @@ -52,16 +60,17 @@ describe("ObjectsClient", () => { test("listObjects (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; - server - .mockEndpoint({ once: false }) - .get("/api/v1/objects") - .respondWith() - .statusCode(400) - .jsonBody(rawResponseBody) - .build(); + server.mockEndpoint().get("/api/v1/objects").respondWith().statusCode(400).jsonBody(rawResponseBody).build(); await expect(async () => { return await client.objects.listObjects(); @@ -70,16 +79,17 @@ describe("ObjectsClient", () => { test("listObjects (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; - server - .mockEndpoint({ once: false }) - .get("/api/v1/objects") - .respondWith() - .statusCode(401) - .jsonBody(rawResponseBody) - .build(); + server.mockEndpoint().get("/api/v1/objects").respondWith().statusCode(401).jsonBody(rawResponseBody).build(); await expect(async () => { return await client.objects.listObjects(); @@ -88,16 +98,17 @@ describe("ObjectsClient", () => { test("listObjects (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; - server - .mockEndpoint({ once: false }) - .get("/api/v1/objects") - .respondWith() - .statusCode(500) - .jsonBody(rawResponseBody) - .build(); + server.mockEndpoint().get("/api/v1/objects").respondWith().statusCode(500).jsonBody(rawResponseBody).build(); await expect(async () => { return await client.objects.listObjects(); @@ -106,7 +117,14 @@ describe("ObjectsClient", () => { test("deleteObject (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); server.mockEndpoint().delete("/api/v1/objects/objectPath").respondWith().statusCode(200).build(); @@ -118,7 +136,14 @@ describe("ObjectsClient", () => { test("deleteObject (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -138,7 +163,14 @@ describe("ObjectsClient", () => { test("deleteObject (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -158,7 +190,14 @@ describe("ObjectsClient", () => { test("deleteObject (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -178,7 +217,14 @@ describe("ObjectsClient", () => { test("deleteObject (5)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -198,7 +244,14 @@ describe("ObjectsClient", () => { test("getObjectMetadata (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); server.mockEndpoint().head("/api/v1/objects/objectPath").respondWith().statusCode(200).build(); @@ -210,7 +263,14 @@ describe("ObjectsClient", () => { test("getObjectMetadata (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -230,7 +290,14 @@ describe("ObjectsClient", () => { test("getObjectMetadata (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -250,7 +317,14 @@ describe("ObjectsClient", () => { test("getObjectMetadata (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server diff --git a/tests/wire/tasks.test.ts b/tests/wire/tasks.test.ts index 92d1b31..2d3b712 100644 --- a/tests/wire/tasks.test.ts +++ b/tests/wire/tasks.test.ts @@ -3,11 +3,19 @@ import * as Lattice from "../../src/api/index"; import { LatticeClient } from "../../src/Client"; import { mockServerPool } from "../mock-server/MockServerPool"; +import { mockOAuth } from "./mockAuth"; describe("TasksClient", () => { test("createTask (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { version: { taskId: "taskId", definitionVersion: 1, statusVersion: 1 }, @@ -134,7 +142,14 @@ describe("TasksClient", () => { test("createTask (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -153,7 +168,14 @@ describe("TasksClient", () => { test("createTask (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -172,7 +194,14 @@ describe("TasksClient", () => { test("getTask (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { version: { taskId: "taskId", definitionVersion: 1, statusVersion: 1 }, @@ -300,7 +329,14 @@ describe("TasksClient", () => { test("getTask (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -320,7 +356,14 @@ describe("TasksClient", () => { test("getTask (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -340,7 +383,14 @@ describe("TasksClient", () => { test("getTask (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawResponseBody = { key: "value" }; server @@ -360,7 +410,14 @@ describe("TasksClient", () => { test("updateTaskStatus (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { version: { taskId: "taskId", definitionVersion: 1, statusVersion: 1 }, @@ -489,7 +546,14 @@ describe("TasksClient", () => { test("updateTaskStatus (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -510,7 +574,14 @@ describe("TasksClient", () => { test("updateTaskStatus (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -531,7 +602,14 @@ describe("TasksClient", () => { test("updateTaskStatus (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -552,7 +630,14 @@ describe("TasksClient", () => { test("queryTasks (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { tasks: [ @@ -596,7 +681,14 @@ describe("TasksClient", () => { test("queryTasks (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -615,7 +707,14 @@ describe("TasksClient", () => { test("queryTasks (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -634,7 +733,14 @@ describe("TasksClient", () => { test("queryTasks (4)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -653,7 +759,14 @@ describe("TasksClient", () => { test("listenAsAgent (1)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { executeRequest: { @@ -703,7 +816,14 @@ describe("TasksClient", () => { test("listenAsAgent (2)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server @@ -722,7 +842,14 @@ describe("TasksClient", () => { test("listenAsAgent (3)", async () => { const server = mockServerPool.createServer(); - const client = new LatticeClient({ maxRetries: 0, token: "test", environment: server.baseUrl }); + mockOAuth(server); + + const client = new LatticeClient({ + maxRetries: 0, + clientId: "test_client_id", + clientSecret: "test_client_secret", + environment: server.baseUrl, + }); const rawRequestBody = {}; const rawResponseBody = { key: "value" }; server From 67e9158191eac39bd430b34aae7ddd252949fd4c Mon Sep 17 00:00:00 2001 From: vpuri-anduril Date: Wed, 14 Jan 2026 11:10:47 -0800 Subject: [PATCH 2/3] correct version --- .fern/metadata.json | 2 +- package.json | 2 +- src/BaseClient.ts | 4 ++-- src/version.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.fern/metadata.json b/.fern/metadata.json index ac086cf..b71058e 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -5,5 +5,5 @@ "generatorConfig": { "namespaceExport": "Lattice" }, - "sdkVersion": "5.0.0" + "sdkVersion": "4.1.0" } diff --git a/package.json b/package.json index 08cd7d7..6c895cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@anduril-industries/lattice-sdk", - "version": "5.0.0", + "version": "4.1.0", "private": false, "repository": { "type": "git", diff --git a/src/BaseClient.ts b/src/BaseClient.ts index 236ecf7..692f4a4 100644 --- a/src/BaseClient.ts +++ b/src/BaseClient.ts @@ -51,8 +51,8 @@ export function normalizeClientOptions Date: Wed, 14 Jan 2026 15:02:33 -0800 Subject: [PATCH 3/3] remove contributing.md --- CONTRIBUTING.md | 133 ------------------------------------------------ 1 file changed, 133 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index fe5bc2f..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,133 +0,0 @@ -# Contributing - -Thanks for your interest in contributing to this SDK! This document provides guidelines for contributing to the project. - -## Getting Started - -### Prerequisites - -- Node.js 20 or higher -- pnpm package manager - -### Installation - -Install the project dependencies: - -```bash -pnpm install -``` - -### Building - -Build the project: - -```bash -pnpm build -``` - -### Testing - -Run the test suite: - -```bash -pnpm test -``` - -Run specific test types: -- `pnpm test:unit` - Run unit tests -- `pnpm test:wire` - Run wire/integration tests - -### Linting and Formatting - -Check code style: - -```bash -pnpm run lint -pnpm run format:check -``` - -Fix code style issues: - -```bash -pnpm run lint:fix -pnpm run format:fix -``` - -Or use the combined check command: - -```bash -pnpm run check:fix -``` - -## About Generated Code - -**Important**: Most files in this SDK are automatically generated by [Fern](https://buildwithfern.com) from the API definition. Direct modifications to generated files will be overwritten the next time the SDK is generated. - -### Generated Files - -The following directories contain generated code: -- `src/api/` - API client classes and types -- `src/serialization/` - Serialization/deserialization logic -- Most TypeScript files in `src/` - -### How to Customize - -If you need to customize the SDK, you have two options: - -#### Option 1: Use `.fernignore` - -For custom code that should persist across SDK regenerations: - -1. Create a `.fernignore` file in the project root -2. Add file patterns for files you want to preserve (similar to `.gitignore` syntax) -3. Add your custom code to those files - -Files listed in `.fernignore` will not be overwritten when the SDK is regenerated. - -For more information, see the [Fern documentation on custom code](https://buildwithfern.com/learn/sdks/overview/custom-code). - -#### Option 2: Contribute to the Generator - -If you want to change how code is generated for all users of this SDK: - -1. The TypeScript SDK generator lives in the [Fern repository](https://github.com/fern-api/fern) -2. Generator code is located at `generators/typescript/sdk/` -3. Follow the [Fern contributing guidelines](https://github.com/fern-api/fern/blob/main/CONTRIBUTING.md) -4. Submit a pull request with your changes to the generator - -This approach is best for: -- Bug fixes in generated code -- New features that would benefit all users -- Improvements to code generation patterns - -## Making Changes - -### Workflow - -1. Create a new branch for your changes -2. Make your modifications -3. Run tests to ensure nothing breaks: `pnpm test` -4. Run linting and formatting: `pnpm run check:fix` -5. Build the project: `pnpm build` -6. Commit your changes with a clear commit message -7. Push your branch and create a pull request - -### Commit Messages - -Write clear, descriptive commit messages that explain what changed and why. - -### Code Style - -This project uses automated code formatting and linting. Run `pnpm run check:fix` before committing to ensure your code meets the project's style guidelines. - -## Questions or Issues? - -If you have questions or run into issues: - -1. Check the [Fern documentation](https://buildwithfern.com) -2. Search existing [GitHub issues](https://github.com/fern-api/fern/issues) -3. Open a new issue if your question hasn't been addressed - -## License - -By contributing to this project, you agree that your contributions will be licensed under the same license as the project.