diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 746dabb..05b5c45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' @@ -17,12 +19,12 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/unlayer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' @@ -36,15 +38,15 @@ jobs: timeout-minutes: 5 name: build runs-on: ${{ github.repository == 'stainless-sdks/unlayer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') permissions: contents: read id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' @@ -55,14 +57,18 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/unlayer-typescript' + if: |- + github.repository == 'stainless-sdks/unlayer-typescript' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/unlayer-typescript' + if: |- + github.repository == 'stainless-sdks/unlayer-typescript' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} @@ -74,10 +80,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/unlayer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 8d3b32c..59442f8 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 with: node-version: '20' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 71339c4..4b829da 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,11 +12,10 @@ jobs: if: github.repository == 'unlayer/unlayer-typescript' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | bash ./bin/check-release-environment env: NPM_TOKEN: ${{ secrets.UNLAYER_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/.gitignore b/.gitignore index 2412bb7..c85fe68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log node_modules yarn-error.log codegen.log diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 466df71..2be9c43 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + ".": "0.2.0" } diff --git a/.stats.yml b/.stats.yml index 2702d73..eb0d57f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/unlayer%2Funlayer-48f00d1c04c23fb4d1cb7cf4af4f56b0c920d758c1f06e06e5373e5b15e9c27d.yml -openapi_spec_hash: 6ee2a94bb9840aceb4a6161c724ce46c -config_hash: 249869757b6eb98ae3d58f2a47ce21e2 +configured_endpoints: 10 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/unlayer/unlayer-35699cec89167aa9ce539f8008695911611f8bdf923234ed701ee3dbc0c5bcd2.yml +openapi_spec_hash: 2ec4eef9500ac0007e1740f431835931 +config_hash: 20e7fbba9d423291aaf676f6a629dcaf diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c2610..6b6aa64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,57 @@ # Changelog +## 0.2.0 (2026-06-17) + +Full Changelog: [v0.1.0...v0.2.0](https://github.com/unlayer/unlayer-typescript/compare/v0.1.0...v0.2.0) + +### Features + +* **api:** api update ([83ea993](https://github.com/unlayer/unlayer-typescript/commit/83ea9936cd068e51773fc25d5b87beb8caa673d0)) +* **api:** api update ([2096590](https://github.com/unlayer/unlayer-typescript/commit/2096590a872261e1d9dfe6b1f70f513cb25d78cd)) +* **api:** api update ([58c42c3](https://github.com/unlayer/unlayer-typescript/commit/58c42c366680e518d1d9fa45e67ee1c915ebb5c7)) +* **api:** api update ([6f63cba](https://github.com/unlayer/unlayer-typescript/commit/6f63cba6c4e4158a76951f682b5391bac71e74ee)) + + +### Bug Fixes + +* **client:** preserve URL params already embedded in path ([aa35c3f](https://github.com/unlayer/unlayer-typescript/commit/aa35c3f9daed566ab225bb5460667b55accfdec3)) +* **client:** send content-type header for requests with an omitted optional body ([8716a27](https://github.com/unlayer/unlayer-typescript/commit/8716a278e99b36d3492f4086b50945300df6ce10)) + + +### Chores + +* **ci:** skip lint on metadata-only changes ([2ff6735](https://github.com/unlayer/unlayer-typescript/commit/2ff6735db5aee19634ac92a8f5903a2496b5d9fd)) +* **ci:** skip uploading artifacts on stainless-internal branches ([5ba5d28](https://github.com/unlayer/unlayer-typescript/commit/5ba5d2871132cd901801f72d9d82ae8a0d03adc1)) +* **internal:** codegen related update ([ebe2eb7](https://github.com/unlayer/unlayer-typescript/commit/ebe2eb769f8ec18596f18a547efb5c750dc53230)) +* **internal:** codegen related update ([b70eaba](https://github.com/unlayer/unlayer-typescript/commit/b70eaba3b4daf2159bd9107c932954631ff5d3ca)) +* **internal:** codegen related update ([5df33b9](https://github.com/unlayer/unlayer-typescript/commit/5df33b94a8781fe7de5c54c232cc3dd556d80a6b)) +* **internal:** codegen related update ([bbe3564](https://github.com/unlayer/unlayer-typescript/commit/bbe35648d10ca91c0d625385894e1dbeb6337bca)) +* **internal:** codegen related update ([c58eac2](https://github.com/unlayer/unlayer-typescript/commit/c58eac28e0d8a7c42225766239777c882f238632)) +* **internal:** codegen related update ([740e1ae](https://github.com/unlayer/unlayer-typescript/commit/740e1ae35ac61a36d7f1e109456844432d2bd6c6)) +* **internal:** codegen related update ([7ce40c6](https://github.com/unlayer/unlayer-typescript/commit/7ce40c6dd2c9ff9f0442e6f89b60ca47c19a9351)) +* **internal:** codegen related update ([6dc4c88](https://github.com/unlayer/unlayer-typescript/commit/6dc4c8844896dcc94667c0b7ff0d0ea37e886e1a)) +* **internal:** codegen related update ([5d0b8ca](https://github.com/unlayer/unlayer-typescript/commit/5d0b8cae4d04648e5904edde4c4be65d2f22b144)) +* **internal:** codegen related update ([c6204bd](https://github.com/unlayer/unlayer-typescript/commit/c6204bdf620e82a1b0de3859c74a0b04ddb220be)) +* **internal:** more robust bootstrap script ([3c105aa](https://github.com/unlayer/unlayer-typescript/commit/3c105aadb230acbf26379b4e7ac258f7c1cf8637)) +* **internal:** move stringifyQuery implementation to internal function ([a382843](https://github.com/unlayer/unlayer-typescript/commit/a3828431e022b0c294eea5dd6d3dfec91dc50f3c)) +* **internal:** tweak CI branches ([37047f6](https://github.com/unlayer/unlayer-typescript/commit/37047f64ad65e540363a5888057fb2031797fa89)) +* **internal:** update dependencies to address dependabot vulnerabilities ([cd210f0](https://github.com/unlayer/unlayer-typescript/commit/cd210f0014bf4c6f91f96b0458b97b28b9b02004)) +* **internal:** update gitignore ([3f8fe21](https://github.com/unlayer/unlayer-typescript/commit/3f8fe21e12dd47a7ec5381b1d01c4b3319d48f0d)) +* **internal:** update multipart form array serialization ([eb9810b](https://github.com/unlayer/unlayer-typescript/commit/eb9810b160faa0c0eb5607a900d0bc3efe80c837)) +* **test:** do not count install time for mock server timeout ([3f4f137](https://github.com/unlayer/unlayer-typescript/commit/3f4f1372bc0146d0abd93d289d1edf1a4c6ce864)) +* **tests:** bump steady to v0.19.4 ([bce44ad](https://github.com/unlayer/unlayer-typescript/commit/bce44adfdaa4fca510a83d182fc9b4788ad454c1)) +* **tests:** bump steady to v0.19.5 ([1ecdf4a](https://github.com/unlayer/unlayer-typescript/commit/1ecdf4a084af6afb151688f3d9ae50ed99d978cb)) +* **tests:** bump steady to v0.19.6 ([13a8f4a](https://github.com/unlayer/unlayer-typescript/commit/13a8f4ab35b1f6487aaf4b2ae1f9fcc771df00f8)) +* **tests:** bump steady to v0.19.7 ([3944238](https://github.com/unlayer/unlayer-typescript/commit/39442381621c93dbeed18b939de999606bcdf3f2)) +* **tests:** bump steady to v0.20.1 ([f058a02](https://github.com/unlayer/unlayer-typescript/commit/f058a02837772b49e641ab186988c76aa4445695)) +* **tests:** bump steady to v0.20.2 ([e312dc6](https://github.com/unlayer/unlayer-typescript/commit/e312dc60c1bf68b3faa91d94feee712f2ab22b60)) +* **tests:** bump steady to v0.22.1 ([005c463](https://github.com/unlayer/unlayer-typescript/commit/005c46350d8b94a4273e5f2490c6f450a7eb8459)) + + +### Refactors + +* **tests:** switch from prism to steady ([3b6f5e4](https://github.com/unlayer/unlayer-typescript/commit/3b6f5e4fe8b7e7df20f500d9191075331c56310e)) + ## 0.1.0 (2026-02-24) Full Changelog: [v0.0.1...v0.1.0](https://github.com/unlayer/unlayer-typescript/compare/v0.0.1...v0.1.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 051f357..6069b57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,7 @@ $ pnpm link --global @unlayer/sdk ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. ```sh $ ./scripts/mock diff --git a/api.md b/api.md index 6cee992..9e7e057 100644 --- a/api.md +++ b/api.md @@ -1,46 +1,65 @@ -# Convert +# Projects + +Types: -## FullToSimple +- ProjectRetrieveResponse + +Methods: + +- client.projects.retrieve(id) -> ProjectRetrieveResponse + +# Templates Types: -- FullToSimpleCreateResponse +- TemplateRetrieveResponse +- TemplateListResponse Methods: -- client.convert.fullToSimple.create({ ...params }) -> FullToSimpleCreateResponse +- client.templates.retrieve(id, { ...params }) -> TemplateRetrieveResponse +- client.templates.list({ ...params }) -> TemplateListResponsesCursorPage -## SimpleToFull +## ConvertFullToSimple Types: -- SimpleToFullCreateResponse +- ConvertFullToSimpleCreateResponse Methods: -- client.convert.simpleToFull.create({ ...params }) -> SimpleToFullCreateResponse +- client.templates.convertFullToSimple.create({ ...params }) -> ConvertFullToSimpleCreateResponse -# Projects +## ConvertSimpleToFull Types: -- ProjectRetrieveResponse +- ConvertSimpleToFullCreateResponse Methods: -- client.projects.retrieve(id) -> ProjectRetrieveResponse +- client.templates.convertSimpleToFull.create({ ...params }) -> ConvertSimpleToFullCreateResponse -# Templates +## Generate + +Types: + +- GenerateCreateResponse + +Methods: + +- client.templates.generate.create({ ...params }) -> GenerateCreateResponse +- client.templates.generate.retrieve() -> void + +## Import Types: -- TemplateRetrieveResponse -- TemplateListResponse +- ImportCreateResponse Methods: -- client.templates.retrieve(id, { ...params }) -> TemplateRetrieveResponse -- client.templates.list({ ...params }) -> TemplateListResponsesCursorPage +- client.templates.import.create({ ...params }) -> ImportCreateResponse # Workspaces diff --git a/eslint.config.mjs b/eslint.config.mjs index e0dbbf8..493d7dc 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,11 +13,9 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, - prettier, }, rules: { 'no-unused-vars': 'off', - 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index af883de..b720396 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@unlayer/sdk", - "version": "0.1.0", + "version": "0.2.0", "description": "The official TypeScript library for the Unlayer API", "author": "Unlayer ", "types": "dist/index.d.ts", @@ -36,7 +36,6 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", - "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "iconv-lite": "^0.6.3", "jest": "^29.4.0", @@ -44,12 +43,23 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "tslib": "^2.8.1", "typescript": "5.8.3", "typescript-eslint": "8.31.1" }, + "overrides": { + "minimatch": "^9.0.5" + }, + "pnpm": { + "overrides": { + "minimatch": "^9.0.5" + } + }, + "resolutions": { + "minimatch": "^9.0.5" + }, "exports": { ".": { "import": "./dist/index.mjs", diff --git a/scripts/bootstrap b/scripts/bootstrap index a8b69ff..2e315f5 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { echo -n "==> Install Homebrew dependencies? (y/N): " read -r response diff --git a/scripts/fast-format b/scripts/fast-format index 53721ac..f1873ae 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -31,10 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then fi echo "==> Running prettier --write" -# format things eslint didn't -PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" -if ! [ -z "$PRETTIER_FILES" ]; then - echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ - '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +if ! [ -z "$FILE_LIST" ]; then + cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown fi diff --git a/scripts/format b/scripts/format index 7a75640..b1b2c17 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -# format things eslint didn't -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a..1f53254 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/.bin/prettier --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/scripts/mock b/scripts/mock index 0b28f6e..feebe5e 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,23 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stdy/cli@0.22.1 -- steady --version - # Wait for server to come online + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=0 + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Steady server to start" + cat .stdy.log + exit 1 + fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 7bce051..19b8d0c 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index deae575..a8cdeb7 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -23,12 +23,19 @@ async function postprocess() { // strip out lib="dom", types="node", and types="react" references; these // are needed at build time, but would pollute the user's TS environment - const transformed = code.replace( + let transformed = code.replace( /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); + // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same + // line as the type declaration, which doesn't work. So we convert to // @ts-ignore + // on its own line to properly suppresses errors. + if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) { + transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n'); + } + if (transformed !== code) { console.error(`wrote ${path.relative(process.cwd(), file)}`); await fs.promises.writeFile(file, transformed, 'utf8'); diff --git a/src/client.ts b/src/client.ts index 889cbc0..ad86390 100644 --- a/src/client.ts +++ b/src/client.ts @@ -11,6 +11,7 @@ import type { APIResponseProps } from './internal/parse'; import { getPlatformHeaders } from './internal/detect-platform'; import * as Shims from './internal/shims'; import * as Opts from './internal/request-options'; +import { stringifyQuery } from './internal/utils/query'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Pagination from './core/pagination'; @@ -19,6 +20,7 @@ import * as Uploads from './core/uploads'; import * as API from './resources/index'; import { APIPromise } from './core/api-promise'; import { ProjectRetrieveResponse, Projects } from './resources/projects'; +import { WorkspaceListResponse, WorkspaceRetrieveResponse, Workspaces } from './resources/workspaces'; import { TemplateListParams, TemplateListResponse, @@ -26,9 +28,7 @@ import { TemplateRetrieveParams, TemplateRetrieveResponse, Templates, -} from './resources/templates'; -import { WorkspaceListResponse, WorkspaceRetrieveResponse, Workspaces } from './resources/workspaces'; -import { Convert } from './resources/convert/convert'; +} from './resources/templates/templates'; import { type Fetch } from './internal/builtin-types'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; import { FinalRequestOptions, RequestOptions } from './internal/request-options'; @@ -191,6 +191,18 @@ export class Unlayer { this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; + const customHeadersEnv = readEnv('UNLAYER_CUSTOM_HEADERS'); + if (customHeadersEnv) { + const parsed: Record = {}; + for (const line of customHeadersEnv.split('\n')) { + const colon = line.indexOf(':'); + if (colon >= 0) { + parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim(); + } + } + options.defaultHeaders = { ...parsed, ...options.defaultHeaders }; + } + this._options = options; this.apiKey = apiKey; @@ -271,21 +283,8 @@ export class Unlayer { /** * Basic re-implementation of `qs.stringify` for primitive types. */ - protected stringifyQuery(query: Record): string { - return Object.entries(query) - .filter(([_, value]) => typeof value !== 'undefined') - .map(([key, value]) => { - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; - } - if (value === null) { - return `${encodeURIComponent(key)}=`; - } - throw new Errors.UnlayerError( - `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, - ); - }) - .join('&'); + protected stringifyQuery(query: object | Record): string { + return stringifyQuery(query); } private getUserAgent(): string { @@ -317,12 +316,13 @@ export class Unlayer { : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); const defaultQuery = this.defaultQuery(); - if (!isEmptyObj(defaultQuery)) { - query = { ...defaultQuery, ...query }; + const pathQuery = Object.fromEntries(url.searchParams); + if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) { + query = { ...pathQuery, ...defaultQuery, ...query }; } if (typeof query === 'object' && query && !Array.isArray(query)) { - url.search = this.stringifyQuery(query as Record); + url.search = this.stringifyQuery(query); } return url.toString(); @@ -651,9 +651,9 @@ export class Unlayer { } } - // If the API asks us to wait a certain amount of time (and it's a reasonable amount), - // just do what it says, but otherwise calculate a default - if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) { + // If the API asks us to wait a certain amount of time, just do what it + // says, but otherwise calculate a default + if (timeoutMillis === undefined) { const maxRetries = options.maxRetries ?? this.maxRetries; timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); } @@ -748,11 +748,19 @@ export class Unlayer { return () => controller.abort(); } - private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { + private buildBody({ options }: { options: FinalRequestOptions }): { bodyHeaders: HeadersLike; body: BodyInit | undefined; } { + const { body, headers: rawHeaders } = options; if (!body) { + // A resource method always passes a `body` key when its operation defines a + // request body, even if the caller omitted an optional body param. Keep the + // content-type for those, and only elide it for operations with no body at + // all (e.g. GET/DELETE). + if (body == null && 'body' in options) { + return this.#encoder({ body, headers: buildHeaders([rawHeaders]) }); + } return { bodyHeaders: undefined, body: undefined }; } const headers = buildHeaders([rawHeaders]); @@ -786,7 +794,7 @@ export class Unlayer { ) { return { bodyHeaders: { 'content-type': 'application/x-www-form-urlencoded' }, - body: this.stringifyQuery(body as Record), + body: this.stringifyQuery(body), }; } else { return this.#encoder({ body, headers }); @@ -812,13 +820,20 @@ export class Unlayer { static toFile = Uploads.toFile; - convert: API.Convert = new API.Convert(this); + /** + * Project details and configuration. + */ projects: API.Projects = new API.Projects(this); + /** + * Template management — list, retrieve, generate, import, export, and convert designs. + */ templates: API.Templates = new API.Templates(this); + /** + * Workspace access and management. + */ workspaces: API.Workspaces = new API.Workspaces(this); } -Unlayer.Convert = Convert; Unlayer.Projects = Projects; Unlayer.Templates = Templates; Unlayer.Workspaces = Workspaces; @@ -829,8 +844,6 @@ export declare namespace Unlayer { export import CursorPage = Pagination.CursorPage; export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse }; - export { Convert as Convert }; - export { Projects as Projects, type ProjectRetrieveResponse as ProjectRetrieveResponse }; export { diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc..a050513 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -40,7 +40,6 @@ type OverloadedParameters = : T extends (...args: infer A) => unknown ? A : never; -/* eslint-disable */ /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -63,19 +62,18 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ type RequestInits = | NotAny diff --git a/src/internal/utils.ts b/src/internal/utils.ts index 3cbfacc..c591353 100644 --- a/src/internal/utils.ts +++ b/src/internal/utils.ts @@ -6,3 +6,4 @@ export * from './utils/env'; export * from './utils/log'; export * from './utils/uuid'; export * from './utils/sleep'; +export * from './utils/query'; diff --git a/src/internal/utils/env.ts b/src/internal/utils/env.ts index 2d84800..cc5fa0f 100644 --- a/src/internal/utils/env.ts +++ b/src/internal/utils/env.ts @@ -9,10 +9,10 @@ */ export const readEnv = (env: string): string | undefined => { if (typeof (globalThis as any).process !== 'undefined') { - return (globalThis as any).process.env?.[env]?.trim() ?? undefined; + return (globalThis as any).process.env?.[env]?.trim() || undefined; } if (typeof (globalThis as any).Deno !== 'undefined') { - return (globalThis as any).Deno.env?.get?.(env)?.trim(); + return (globalThis as any).Deno.env?.get?.(env)?.trim() || undefined; } return undefined; }; diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index 1726922..a2a0730 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -107,6 +107,8 @@ export const formatRequestDetails = (details: { name, ( name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? diff --git a/src/internal/utils/query.ts b/src/internal/utils/query.ts new file mode 100644 index 0000000..bd0eb5e --- /dev/null +++ b/src/internal/utils/query.ts @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { UnlayerError } from '../../core/error'; + +/** + * Basic re-implementation of `qs.stringify` for primitive types. + */ +export function stringifyQuery(query: object | Record) { + return Object.entries(query) + .filter(([_, value]) => typeof value !== 'undefined') + .map(([key, value]) => { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + } + if (value === null) { + return `${encodeURIComponent(key)}=`; + } + throw new UnlayerError( + `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, + ); + }) + .join('&'); +} diff --git a/src/resources/convert.ts b/src/resources/convert.ts deleted file mode 100644 index 1334f91..0000000 --- a/src/resources/convert.ts +++ /dev/null @@ -1,3 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -export * from './convert/index'; diff --git a/src/resources/convert/convert.ts b/src/resources/convert/convert.ts deleted file mode 100644 index d7930c4..0000000 --- a/src/resources/convert/convert.ts +++ /dev/null @@ -1,29 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../../core/resource'; -import * as FullToSimpleAPI from './full-to-simple'; -import { FullToSimple, FullToSimpleCreateParams, FullToSimpleCreateResponse } from './full-to-simple'; -import * as SimpleToFullAPI from './simple-to-full'; -import { SimpleToFull, SimpleToFullCreateParams, SimpleToFullCreateResponse } from './simple-to-full'; - -export class Convert extends APIResource { - fullToSimple: FullToSimpleAPI.FullToSimple = new FullToSimpleAPI.FullToSimple(this._client); - simpleToFull: SimpleToFullAPI.SimpleToFull = new SimpleToFullAPI.SimpleToFull(this._client); -} - -Convert.FullToSimple = FullToSimple; -Convert.SimpleToFull = SimpleToFull; - -export declare namespace Convert { - export { - FullToSimple as FullToSimple, - type FullToSimpleCreateResponse as FullToSimpleCreateResponse, - type FullToSimpleCreateParams as FullToSimpleCreateParams, - }; - - export { - SimpleToFull as SimpleToFull, - type SimpleToFullCreateResponse as SimpleToFullCreateResponse, - type SimpleToFullCreateParams as SimpleToFullCreateParams, - }; -} diff --git a/src/resources/convert/index.ts b/src/resources/convert/index.ts deleted file mode 100644 index 833a9fc..0000000 --- a/src/resources/convert/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -export { Convert } from './convert'; -export { - FullToSimple, - type FullToSimpleCreateResponse, - type FullToSimpleCreateParams, -} from './full-to-simple'; -export { - SimpleToFull, - type SimpleToFullCreateResponse, - type SimpleToFullCreateParams, -} from './simple-to-full'; diff --git a/src/resources/convert/simple-to-full.ts b/src/resources/convert/simple-to-full.ts deleted file mode 100644 index c1051de..0000000 --- a/src/resources/convert/simple-to-full.ts +++ /dev/null @@ -1,63 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../../core/resource'; -import { APIPromise } from '../../core/api-promise'; -import { RequestOptions } from '../../internal/request-options'; - -export class SimpleToFull extends APIResource { - /** - * Convert design json from Simple to Full schema. - */ - create(body: SimpleToFullCreateParams, options?: RequestOptions): APIPromise { - return this._client.post('/v3/convert/simple-to-full', { body, ...options }); - } -} - -export interface SimpleToFullCreateResponse { - data?: SimpleToFullCreateResponse.Data; - - success?: true; -} - -export namespace SimpleToFullCreateResponse { - export interface Data { - design?: { [key: string]: unknown }; - } -} - -export interface SimpleToFullCreateParams { - design: SimpleToFullCreateParams.Design; - - displayMode?: 'email' | 'web' | 'popup' | 'document'; - - includeDefaultValues?: boolean; -} - -export namespace SimpleToFullCreateParams { - export interface Design { - body: { [key: string]: unknown }; - - _conversion?: Design._Conversion; - - counters?: { [key: string]: unknown }; - - schemaVersion?: number; - - [k: string]: unknown; - } - - export namespace Design { - export interface _Conversion { - data?: string; - - version?: number; - } - } -} - -export declare namespace SimpleToFull { - export { - type SimpleToFullCreateResponse as SimpleToFullCreateResponse, - type SimpleToFullCreateParams as SimpleToFullCreateParams, - }; -} diff --git a/src/resources/index.ts b/src/resources/index.ts index 303eae0..6ca716c 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,6 +1,5 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { Convert } from './convert/convert'; export { Projects, type ProjectRetrieveResponse } from './projects'; export { Templates, @@ -9,5 +8,5 @@ export { type TemplateRetrieveParams, type TemplateListParams, type TemplateListResponsesCursorPage, -} from './templates'; +} from './templates/templates'; export { Workspaces, type WorkspaceRetrieveResponse, type WorkspaceListResponse } from './workspaces'; diff --git a/src/resources/projects.ts b/src/resources/projects.ts index 6b97668..0d15122 100644 --- a/src/resources/projects.ts +++ b/src/resources/projects.ts @@ -5,6 +5,9 @@ import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Project details and configuration. + */ export class Projects extends APIResource { /** * Get project details by ID. diff --git a/src/resources/templates.ts b/src/resources/templates.ts index 38eef4b..cf710e0 100644 --- a/src/resources/templates.ts +++ b/src/resources/templates.ts @@ -1,110 +1,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../core/resource'; -import { APIPromise } from '../core/api-promise'; -import { CursorPage, type CursorPageParams, PagePromise } from '../core/pagination'; -import { RequestOptions } from '../internal/request-options'; -import { path } from '../internal/utils/path'; - -export class Templates extends APIResource { - /** - * Get template by ID. - */ - retrieve( - id: string, - query: TemplateRetrieveParams | null | undefined = {}, - options?: RequestOptions, - ): APIPromise { - return this._client.get(path`/v3/templates/${id}`, { query, ...options }); - } - - /** - * List templates with cursor-based pagination. Returns templates in descending - * order by update time. - */ - list( - query: TemplateListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/v3/templates', CursorPage, { query, ...options }); - } -} - -export type TemplateListResponsesCursorPage = CursorPage; - -export interface TemplateRetrieveResponse { - data?: TemplateRetrieveResponse.Data; -} - -export namespace TemplateRetrieveResponse { - export interface Data { - id?: string; - - createdAt?: string; - - design?: { [key: string]: unknown }; - - displayMode?: 'email' | 'web' | 'document'; - - html?: string | null; - - name?: string; - - updatedAt?: string; - } -} - -export interface TemplateListResponse { - /** - * Template ID - */ - id?: string; - - createdAt?: string; - - /** - * Template type/display mode - */ - displayMode?: 'email' | 'web' | 'document'; - - /** - * Template name - */ - name?: string; - - updatedAt?: string; -} - -export interface TemplateRetrieveParams { - /** - * The project ID (required for PAT auth, auto-resolved for API key auth) - */ - projectId?: string; -} - -export interface TemplateListParams extends CursorPageParams { - /** - * Filter by template type - */ - displayMode?: 'email' | 'web' | 'document'; - - /** - * Filter by name (case-insensitive search) - */ - name?: string; - - /** - * The project ID to list templates for - */ - projectId?: string; -} - -export declare namespace Templates { - export { - type TemplateRetrieveResponse as TemplateRetrieveResponse, - type TemplateListResponse as TemplateListResponse, - type TemplateListResponsesCursorPage as TemplateListResponsesCursorPage, - type TemplateRetrieveParams as TemplateRetrieveParams, - type TemplateListParams as TemplateListParams, - }; -} +export * from './templates/index'; diff --git a/src/resources/convert/full-to-simple.ts b/src/resources/templates/convert-full-to-simple.ts similarity index 50% rename from src/resources/convert/full-to-simple.ts rename to src/resources/templates/convert-full-to-simple.ts index 44e02b9..c8b3e8c 100644 --- a/src/resources/convert/full-to-simple.ts +++ b/src/resources/templates/convert-full-to-simple.ts @@ -4,29 +4,35 @@ import { APIResource } from '../../core/resource'; import { APIPromise } from '../../core/api-promise'; import { RequestOptions } from '../../internal/request-options'; -export class FullToSimple extends APIResource { +/** + * Template management — list, retrieve, generate, import, export, and convert designs. + */ +export class ConvertFullToSimple extends APIResource { /** * Convert design json from Full to Simple schema. */ - create(body: FullToSimpleCreateParams, options?: RequestOptions): APIPromise { - return this._client.post('/v3/convert/full-to-simple', { body, ...options }); + create( + body: ConvertFullToSimpleCreateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v3/templates/convert/full-to-simple', { body, ...options }); } } -export interface FullToSimpleCreateResponse { - data?: FullToSimpleCreateResponse.Data; +export interface ConvertFullToSimpleCreateResponse { + data?: ConvertFullToSimpleCreateResponse.Data; success?: true; } -export namespace FullToSimpleCreateResponse { +export namespace ConvertFullToSimpleCreateResponse { export interface Data { design?: { [key: string]: unknown }; } } -export interface FullToSimpleCreateParams { - design: FullToSimpleCreateParams.Design; +export interface ConvertFullToSimpleCreateParams { + design: ConvertFullToSimpleCreateParams.Design; displayMode?: 'email' | 'web' | 'popup' | 'document'; @@ -39,7 +45,7 @@ export interface FullToSimpleCreateParams { includeDefaultValues?: boolean; } -export namespace FullToSimpleCreateParams { +export namespace ConvertFullToSimpleCreateParams { export interface Design { body: { [key: string]: unknown }; @@ -51,9 +57,9 @@ export namespace FullToSimpleCreateParams { } } -export declare namespace FullToSimple { +export declare namespace ConvertFullToSimple { export { - type FullToSimpleCreateResponse as FullToSimpleCreateResponse, - type FullToSimpleCreateParams as FullToSimpleCreateParams, + type ConvertFullToSimpleCreateResponse as ConvertFullToSimpleCreateResponse, + type ConvertFullToSimpleCreateParams as ConvertFullToSimpleCreateParams, }; } diff --git a/src/resources/templates/convert-simple-to-full.ts b/src/resources/templates/convert-simple-to-full.ts new file mode 100644 index 0000000..c1c0af0 --- /dev/null +++ b/src/resources/templates/convert-simple-to-full.ts @@ -0,0 +1,69 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; + +/** + * Template management — list, retrieve, generate, import, export, and convert designs. + */ +export class ConvertSimpleToFull extends APIResource { + /** + * Convert design json from Simple to Full schema. + */ + create( + body: ConvertSimpleToFullCreateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v3/templates/convert/simple-to-full', { body, ...options }); + } +} + +export interface ConvertSimpleToFullCreateResponse { + data?: ConvertSimpleToFullCreateResponse.Data; + + success?: true; +} + +export namespace ConvertSimpleToFullCreateResponse { + export interface Data { + design?: { [key: string]: unknown }; + } +} + +export interface ConvertSimpleToFullCreateParams { + design: ConvertSimpleToFullCreateParams.Design; + + displayMode?: 'email' | 'web' | 'popup' | 'document'; + + includeDefaultValues?: boolean; +} + +export namespace ConvertSimpleToFullCreateParams { + export interface Design { + body: { [key: string]: unknown }; + + _conversion?: Design._Conversion; + + counters?: { [key: string]: unknown }; + + schemaVersion?: number; + + [k: string]: unknown; + } + + export namespace Design { + export interface _Conversion { + data?: string; + + version?: number; + } + } +} + +export declare namespace ConvertSimpleToFull { + export { + type ConvertSimpleToFullCreateResponse as ConvertSimpleToFullCreateResponse, + type ConvertSimpleToFullCreateParams as ConvertSimpleToFullCreateParams, + }; +} diff --git a/src/resources/templates/generate.ts b/src/resources/templates/generate.ts new file mode 100644 index 0000000..a5b06ca --- /dev/null +++ b/src/resources/templates/generate.ts @@ -0,0 +1,248 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; + +export class Generate extends APIResource { + /** + * Generate or modify an Unlayer design using AI. Send the conversation as + * `messages` (today only the last user message is consumed; earlier turns are + * accepted as chat history) and describe the target with `output.kind` + + * `output.displayMode`. Pass the current canvas state in `context` (full design + * JSON + selection pointer) to modify an existing design. Only `anthropic` and + * `openai` models are supported. To import existing HTML or an image instead, use + * POST /v3/templates/import. + */ + create(params: GenerateCreateParams, options?: RequestOptions): APIPromise { + const { projectId, ...body } = params; + return this._client.post('/v3/templates/generate', { query: { projectId }, body, ...options }); + } + + retrieve(options?: RequestOptions): APIPromise { + return this._client.get('/v3/templates/generate', { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } +} + +/** + * The generated (or modified) design plus model metadata and optional usage + * metadata. + */ +export interface GenerateCreateResponse { + /** + * Provider response id for the generation turn. + */ + id?: string; + + /** + * The provider + model that actually produced the output (may differ from the + * requested model after failover). + */ + model?: GenerateCreateResponse.Model; + + /** + * The generated output for the requested block. + */ + output?: GenerateCreateResponse.Output; + + /** + * Aggregate token usage for the turn when exposed by the caller. Builder copilot + * endpoints expose it only in local/dev/QA and omit it in staging/production. + */ + usage?: GenerateCreateResponse.Usage; +} + +export namespace GenerateCreateResponse { + /** + * The provider + model that actually produced the output (may differ from the + * requested model after failover). + */ + export interface Model { + /** + * Resolved model id, e.g. "claude-opus-4-7". + */ + id?: string; + + /** + * e.g. "anthropic", "openai". + */ + provider?: string; + } + + /** + * The generated output for the requested block. + */ + export interface Output { + /** + * The generated design JSON, scoped to the requested kind (the full design for + * template/page/body; the row/column/content/element for narrower kinds). + */ + data?: { [key: string]: unknown }; + + /** + * Echoes the requested `output.kind`. + */ + kind?: string; + } + + /** + * Aggregate token usage for the turn when exposed by the caller. Builder copilot + * endpoints expose it only in local/dev/QA and omit it in staging/production. + */ + export interface Usage { + cachedInputTokens?: number; + + estimatedCostMicroUsd?: number; + + inputTokens?: number; + + outputTokens?: number; + + reasoningTokens?: number; + + totalTokens?: number; + } +} + +export interface GenerateCreateParams { + /** + * Body param: Conversation messages in chronological order, capped at 10 messages. + * The last `user` message is the prompt for this turn; any earlier + * `user`/`assistant` text turns are forwarded to the model as prior chat context. + * A `user` message may carry a predefined prompt action via `metadata.action.id` + * (e.g. SPELLING, REPHRASE). + */ + messages: Array; + + /** + * Body param + */ + output: GenerateCreateParams.Output; + + /** + * Query param: The project ID (required for PAT auth, auto-resolved for API key + * auth) + */ + projectId?: string; + + /** + * Body param + */ + context?: GenerateCreateParams.Context; + + /** + * Body param: Reserved for future server-side conversation memory. + */ + conversationId?: string; + + /** + * Body param: BCP-47 fallback locale for AI status messages. + */ + locale?: string; + + /** + * Body param: AI model in "provider/id" form, e.g. "anthropic/claude-opus-4-7". + * Optional — server resolves a default per output kind. + */ + model?: string; +} + +export namespace GenerateCreateParams { + export interface Message { + content: Array; + + role: 'user' | 'assistant' | 'system'; + + metadata?: Message.Metadata; + } + + export namespace Message { + export interface Content { + type: 'text' | 'image' | 'file'; + + file?: Content.File; + + /** + * URL or data URL of the image + */ + image?: string; + + text?: string; + } + + export namespace Content { + export interface File { + url: string; + + mediaType?: string; + + [k: string]: unknown; + } + } + + export interface Metadata { + action?: Metadata.Action; + + [k: string]: unknown; + } + + export namespace Metadata { + export interface Action { + id: string; + + [k: string]: unknown; + } + } + } + + export interface Output { + displayMode: 'email' | 'web' | 'popup' | 'document'; + + kind: 'template' | 'page' | 'body' | 'header' | 'footer' | 'row' | 'column' | 'content' | 'text'; + + schemaVersion?: number; + } + + export interface Context { + availableTools?: Array; + + customTools?: Array; + + fullDesign?: { [key: string]: unknown } | null; + + selection?: Context.Selection | null; + + [k: string]: unknown; + } + + export namespace Context { + export interface CustomTool { + options: { [key: string]: unknown }; + + slug: string; + + [k: string]: unknown; + } + + export interface Selection { + id: string | number; + + collection: 'pages' | 'bodies' | 'rows' | 'columns' | 'contents' | 'headers' | 'footers'; + + value?: string; + + [k: string]: unknown; + } + } +} + +export declare namespace Generate { + export { + type GenerateCreateResponse as GenerateCreateResponse, + type GenerateCreateParams as GenerateCreateParams, + }; +} diff --git a/src/resources/templates/import.ts b/src/resources/templates/import.ts new file mode 100644 index 0000000..1060f2c --- /dev/null +++ b/src/resources/templates/import.ts @@ -0,0 +1,121 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; + +/** + * Template management — list, retrieve, generate, import, export, and convert designs. + */ +export class Import extends APIResource { + /** + * Import an existing template from HTML or an image (URL or base64) and return the + * resulting Unlayer design JSON. No template DB entry is created. + */ + create(params: ImportCreateParams, options?: RequestOptions): APIPromise { + const { projectId, ...body } = params; + return this._client.post('/v3/templates/import', { query: { projectId }, body, ...options }); + } +} + +/** + * Successfully imported template + */ +export interface ImportCreateResponse { + id?: string; + + model?: string; + + output?: ImportCreateResponse.Output; + + provider?: string; + + usage?: ImportCreateResponse.Usage; +} + +export namespace ImportCreateResponse { + export interface Output { + blockType?: string; + + /** + * Imported design data + */ + data?: { [key: string]: unknown }; + + type?: string; + } + + export interface Usage { + cachedInputTokens?: number; + + inputTokens?: number; + + outputTokens?: number; + + reasoningTokens?: number; + + totalTokens?: number; + } +} + +export interface ImportCreateParams { + /** + * Body param: Display mode for the imported design + */ + displayMode: 'email' | 'web' | 'popup' | 'document'; + + /** + * Body param: Array of input parts. Must contain exactly one "html" or "image" + * part; may also contain one or more "text" parts with optional instructions. + */ + input: Array; + + /** + * Query param: The project ID (required for PAT auth, auto-resolved for API key + * auth) + */ + projectId?: string; + + /** + * Body param: AI model to use. Accepts a provider/model string (e.g. + * "anthropic/claude-opus-4-7", "openai/gpt-5.5"), a bare provider ("anthropic", + * "openai") which uses that provider's default model, or a bare model id + * ("claude-opus-4-7", "gpt-5.5") with the provider inferred from the name. + * Optional — defaults to anthropic/claude-opus-4-7. + */ + model?: string; +} + +export namespace ImportCreateParams { + export interface Input { + /** + * The type of input part. "html" or "image" carries the source content; "text" + * carries optional instructions to apply during import. + */ + type: 'html' | 'image' | 'text'; + + /** + * Base64 image data URL, e.g. "data:image/png;base64,…" (for type: "image") + */ + data?: string; + + /** + * HTML string to import (for type: "html") + */ + html?: string; + + /** + * Optional natural-language instructions to apply during import (for type: "text") + */ + text?: string; + + /** + * Image URL to import (for type: "image") + */ + url?: string; + } +} + +export declare namespace Import { + export { type ImportCreateResponse as ImportCreateResponse, type ImportCreateParams as ImportCreateParams }; +} diff --git a/src/resources/templates/index.ts b/src/resources/templates/index.ts new file mode 100644 index 0000000..b4f6e4e --- /dev/null +++ b/src/resources/templates/index.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + ConvertFullToSimple, + type ConvertFullToSimpleCreateResponse, + type ConvertFullToSimpleCreateParams, +} from './convert-full-to-simple'; +export { + ConvertSimpleToFull, + type ConvertSimpleToFullCreateResponse, + type ConvertSimpleToFullCreateParams, +} from './convert-simple-to-full'; +export { Generate, type GenerateCreateResponse, type GenerateCreateParams } from './generate'; +export { Import, type ImportCreateResponse, type ImportCreateParams } from './import'; +export { + Templates, + type TemplateRetrieveResponse, + type TemplateListResponse, + type TemplateRetrieveParams, + type TemplateListParams, + type TemplateListResponsesCursorPage, +} from './templates'; diff --git a/src/resources/templates/templates.ts b/src/resources/templates/templates.ts new file mode 100644 index 0000000..fd15c00 --- /dev/null +++ b/src/resources/templates/templates.ts @@ -0,0 +1,165 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as ConvertFullToSimpleAPI from './convert-full-to-simple'; +import { + ConvertFullToSimple, + ConvertFullToSimpleCreateParams, + ConvertFullToSimpleCreateResponse, +} from './convert-full-to-simple'; +import * as ConvertSimpleToFullAPI from './convert-simple-to-full'; +import { + ConvertSimpleToFull, + ConvertSimpleToFullCreateParams, + ConvertSimpleToFullCreateResponse, +} from './convert-simple-to-full'; +import * as GenerateAPI from './generate'; +import { Generate, GenerateCreateParams, GenerateCreateResponse } from './generate'; +import * as ImportAPI from './import'; +import { Import, ImportCreateParams, ImportCreateResponse } from './import'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +/** + * Template management — list, retrieve, generate, import, export, and convert designs. + */ +export class Templates extends APIResource { + convertFullToSimple: ConvertFullToSimpleAPI.ConvertFullToSimple = + new ConvertFullToSimpleAPI.ConvertFullToSimple(this._client); + convertSimpleToFull: ConvertSimpleToFullAPI.ConvertSimpleToFull = + new ConvertSimpleToFullAPI.ConvertSimpleToFull(this._client); + generate: GenerateAPI.Generate = new GenerateAPI.Generate(this._client); + import: ImportAPI.Import = new ImportAPI.Import(this._client); + + /** + * Get template by ID. + */ + retrieve( + id: string, + query: TemplateRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/v3/templates/${id}`, { query, ...options }); + } + + /** + * List templates with cursor-based pagination. Returns templates in descending + * order by update time. + */ + list( + query: TemplateListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/v3/templates', CursorPage, { query, ...options }); + } +} + +export type TemplateListResponsesCursorPage = CursorPage; + +export interface TemplateRetrieveResponse { + data?: TemplateRetrieveResponse.Data; +} + +export namespace TemplateRetrieveResponse { + export interface Data { + id?: string; + + createdAt?: string; + + design?: { [key: string]: unknown }; + + displayMode?: 'email' | 'web' | 'document'; + + html?: string | null; + + name?: string; + + updatedAt?: string; + } +} + +export interface TemplateListResponse { + /** + * Template ID + */ + id?: string; + + createdAt?: string; + + /** + * Template type/display mode + */ + displayMode?: 'email' | 'web' | 'document'; + + /** + * Template name + */ + name?: string; + + updatedAt?: string; +} + +export interface TemplateRetrieveParams { + /** + * The project ID (required for PAT auth, auto-resolved for API key auth) + */ + projectId?: string; +} + +export interface TemplateListParams extends CursorPageParams { + /** + * Filter by template type + */ + displayMode?: 'email' | 'web' | 'document'; + + /** + * Filter by name (case-insensitive search) + */ + name?: string; + + /** + * The project ID to list templates for + */ + projectId?: string; +} + +Templates.ConvertFullToSimple = ConvertFullToSimple; +Templates.ConvertSimpleToFull = ConvertSimpleToFull; +Templates.Generate = Generate; +Templates.Import = Import; + +export declare namespace Templates { + export { + type TemplateRetrieveResponse as TemplateRetrieveResponse, + type TemplateListResponse as TemplateListResponse, + type TemplateListResponsesCursorPage as TemplateListResponsesCursorPage, + type TemplateRetrieveParams as TemplateRetrieveParams, + type TemplateListParams as TemplateListParams, + }; + + export { + ConvertFullToSimple as ConvertFullToSimple, + type ConvertFullToSimpleCreateResponse as ConvertFullToSimpleCreateResponse, + type ConvertFullToSimpleCreateParams as ConvertFullToSimpleCreateParams, + }; + + export { + ConvertSimpleToFull as ConvertSimpleToFull, + type ConvertSimpleToFullCreateResponse as ConvertSimpleToFullCreateResponse, + type ConvertSimpleToFullCreateParams as ConvertSimpleToFullCreateParams, + }; + + export { + Generate as Generate, + type GenerateCreateResponse as GenerateCreateResponse, + type GenerateCreateParams as GenerateCreateParams, + }; + + export { + Import as Import, + type ImportCreateResponse as ImportCreateResponse, + type ImportCreateParams as ImportCreateParams, + }; +} diff --git a/src/resources/workspaces.ts b/src/resources/workspaces.ts index e51624e..4b338e1 100644 --- a/src/resources/workspaces.ts +++ b/src/resources/workspaces.ts @@ -5,6 +5,9 @@ import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Workspace access and management. + */ export class Workspaces extends APIResource { /** * Get a specific workspace by ID with its projects. Requires a Personal Access diff --git a/src/version.ts b/src/version.ts index 1baa228..bade2ff 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.0'; // x-release-please-version +export const VERSION = '0.2.0'; // x-release-please-version diff --git a/tests/api-resources/convert/full-to-simple.test.ts b/tests/api-resources/templates/convert-full-to-simple.test.ts similarity index 80% rename from tests/api-resources/convert/full-to-simple.test.ts rename to tests/api-resources/templates/convert-full-to-simple.test.ts index 831b256..4936e57 100644 --- a/tests/api-resources/convert/full-to-simple.test.ts +++ b/tests/api-resources/templates/convert-full-to-simple.test.ts @@ -7,9 +7,9 @@ const client = new Unlayer({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', }); -describe('resource fullToSimple', () => { +describe('resource convertFullToSimple', () => { test('create: only required params', async () => { - const responsePromise = client.convert.fullToSimple.create({ design: { body: { foo: 'bar' } } }); + const responsePromise = client.templates.convertFullToSimple.create({ design: { body: { foo: 'bar' } } }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -20,7 +20,7 @@ describe('resource fullToSimple', () => { }); test('create: required and optional params', async () => { - const response = await client.convert.fullToSimple.create({ + const response = await client.templates.convertFullToSimple.create({ design: { body: { foo: 'bar' }, counters: { foo: 'bar' }, diff --git a/tests/api-resources/convert/simple-to-full.test.ts b/tests/api-resources/templates/convert-simple-to-full.test.ts similarity index 81% rename from tests/api-resources/convert/simple-to-full.test.ts rename to tests/api-resources/templates/convert-simple-to-full.test.ts index a5f33bd..4c80e0d 100644 --- a/tests/api-resources/convert/simple-to-full.test.ts +++ b/tests/api-resources/templates/convert-simple-to-full.test.ts @@ -7,9 +7,9 @@ const client = new Unlayer({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', }); -describe('resource simpleToFull', () => { +describe('resource convertSimpleToFull', () => { test('create: only required params', async () => { - const responsePromise = client.convert.simpleToFull.create({ design: { body: { foo: 'bar' } } }); + const responsePromise = client.templates.convertSimpleToFull.create({ design: { body: { foo: 'bar' } } }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -20,7 +20,7 @@ describe('resource simpleToFull', () => { }); test('create: required and optional params', async () => { - const response = await client.convert.simpleToFull.create({ + const response = await client.templates.convertSimpleToFull.create({ design: { body: { foo: 'bar' }, _conversion: { data: 'data', version: 0 }, diff --git a/tests/api-resources/templates/generate.test.ts b/tests/api-resources/templates/generate.test.ts new file mode 100644 index 0000000..c6526f4 --- /dev/null +++ b/tests/api-resources/templates/generate.test.ts @@ -0,0 +1,78 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Unlayer from '@unlayer/sdk'; + +const client = new Unlayer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource generate', () => { + test('create: only required params', async () => { + const responsePromise = client.templates.generate.create({ + messages: [{ content: [{ type: 'text' }], role: 'user' }], + output: { displayMode: 'email', kind: 'template' }, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('create: required and optional params', async () => { + const response = await client.templates.generate.create({ + messages: [ + { + content: [ + { + type: 'text', + file: { url: 'url', mediaType: 'mediaType' }, + image: 'image', + text: 'text', + }, + ], + role: 'user', + metadata: { action: { id: 'id' } }, + }, + ], + output: { + displayMode: 'email', + kind: 'template', + schemaVersion: 0, + }, + projectId: 'projectId', + context: { + availableTools: ['string'], + customTools: [ + { + options: { foo: 'bar' }, + slug: 'slug', + }, + ], + fullDesign: { foo: 'bar' }, + selection: { + id: 'string', + collection: 'pages', + value: 'value', + }, + }, + conversationId: 'conversationId', + locale: 'locale', + model: 'model', + }); + }); + + test('retrieve', async () => { + const responsePromise = client.templates.generate.retrieve(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/templates/import.test.ts b/tests/api-resources/templates/import.test.ts new file mode 100644 index 0000000..6f66884 --- /dev/null +++ b/tests/api-resources/templates/import.test.ts @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Unlayer from '@unlayer/sdk'; + +const client = new Unlayer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource import', () => { + test('create: only required params', async () => { + const responsePromise = client.templates.import.create({ + displayMode: 'email', + input: [{ type: 'html' }], + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('create: required and optional params', async () => { + const response = await client.templates.import.create({ + displayMode: 'email', + input: [ + { + type: 'html', + data: 'data', + html: 'html', + text: 'text', + url: 'url', + }, + ], + projectId: 'projectId', + model: 'model', + }); + }); +}); diff --git a/tests/api-resources/templates.test.ts b/tests/api-resources/templates/templates.test.ts similarity index 100% rename from tests/api-resources/templates.test.ts rename to tests/api-resources/templates/templates.test.ts diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 4f47883..37eca7e 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -1,8 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { Unlayer } from '@unlayer/sdk'; - -const { stringifyQuery } = Unlayer.prototype as any; +import { stringifyQuery } from '@unlayer/sdk/internal/utils/query'; describe(stringifyQuery, () => { for (const [input, expected] of [ @@ -15,7 +13,7 @@ describe(stringifyQuery, () => { 'e=f', )}=${encodeURIComponent('g&h')}`, ], - ]) { + ] as const) { it(`${JSON.stringify(input)} -> ${expected}`, () => { expect(stringifyQuery(input)).toEqual(expected); }); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 7765432..a29d9c2 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import type { ResponseLike } from '@unlayer/sdk/internal/to-file'; import { toFile } from '@unlayer/sdk/core/uploads'; -import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; diff --git a/yarn.lock b/yarn.lock index fc9f262..06fc108 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/core@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" - integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1219,18 +1214,10 @@ baseline-browser-mapping@^2.9.0: resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz#3b6af0bc032445bca04de58caa9a87cfe921cbb3" integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== -brace-expansion@^1.1.7: - version "1.1.12" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" - integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" - integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== +brace-expansion@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8" + integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA== dependencies: balanced-match "^1.0.0" @@ -1395,11 +1382,6 @@ commander@^10.0.1: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -1528,14 +1510,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" - integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" - eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1687,11 +1661,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2600,26 +2569,12 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2, minimatch@^5.0.1, minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e" + integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^2.0.2" minimist@^1.2.6: version "1.2.6" @@ -2868,13 +2823,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3171,13 +3119,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== - dependencies: - "@pkgr/core" "^0.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -3251,9 +3192,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2"