diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 746dabb..a15001b 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/**'
@@ -16,15 +18,15 @@ jobs:
lint:
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
+ runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ 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'
+ node-version: '24'
- name: Bootstrap
run: ./scripts/bootstrap
@@ -35,18 +37,18 @@ jobs:
build:
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
+ runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ 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'
+ node-version: '24'
- name: Bootstrap
run: ./scripts/bootstrap
@@ -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 }}
@@ -71,15 +77,15 @@ jobs:
test:
timeout-minutes: 10
name: test
- runs-on: ${{ github.repository == 'stainless-sdks/unlayer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && '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'
+ node-version: '24'
- name: Bootstrap
run: ./scripts/bootstrap
diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml
index 8d3b32c..17e1064 100644
--- a/.github/workflows/publish-npm.yml
+++ b/.github/workflows/publish-npm.yml
@@ -14,12 +14,12 @@ 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'
+ node-version: '24'
- name: Install dependencies
run: |
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/.stats.yml b/.stats.yml
index 2702d73..5f064af 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: 51
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/unlayer/unlayer-231dfb6902a557101992c19fd91a3cf6d4d187b06c9d6b20f2b70d7df77e664a.yml
+openapi_spec_hash: 487c5e8289dd85c5d412f6635c2bc3fc
+config_hash: 31bbe4c50af7bd9aea5582d9a2ab786d
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..76404ab 100644
--- a/api.md
+++ b/api.md
@@ -1,46 +1,369 @@
-# Convert
+# Blocks
-## FullToSimple
+Types:
+
+- BlockRetrieveResponse
+
+Methods:
+
+- client.blocks.retrieve({ ...params }) -> BlockRetrieveResponse
+
+# Domains
+
+Types:
+
+- DomainCreateResponse
+- DomainRetrieveResponse
+- DomainListResponse
+- DomainDeleteResponse
+
+Methods:
+
+- client.domains.create({ ...params }) -> DomainCreateResponse
+- client.domains.retrieve(id) -> DomainRetrieveResponse
+- client.domains.list() -> DomainListResponse
+- client.domains.delete(id) -> DomainDeleteResponse
+
+## Verify
+
+Types:
+
+- VerifyCreateResponse
+
+Methods:
+
+- client.domains.verify.create(id) -> VerifyCreateResponse
+
+# EditorSessions
+
+Types:
+
+- EditorSessionCreateResponse
+
+Methods:
+
+- client.editorSessions.create({ ...params }) -> EditorSessionCreateResponse
+
+# Emails
+
+Types:
+
+- EmailCreateResponse
+- EmailRetrieveResponse
+- EmailListResponse
+
+Methods:
+
+- client.emails.create({ ...params }) -> EmailCreateResponse
+- client.emails.retrieve(id) -> EmailRetrieveResponse
+- client.emails.list({ ...params }) -> EmailListResponse
+
+## Events
+
+Types:
+
+- EventRetrieveResponse
+
+Methods:
+
+- client.emails.events.retrieve(id) -> EventRetrieveResponse
+
+## Render
+
+Types:
+
+- RenderCreateResponse
+
+Methods:
+
+- client.emails.render.create({ ...params }) -> RenderCreateResponse
+
+## Settings
+
+Types:
+
+- SettingRetrieveResponse
+- SettingUpdateResponse
+
+Methods:
+
+- client.emails.settings.retrieve() -> SettingRetrieveResponse
+- client.emails.settings.update({ ...params }) -> SettingUpdateResponse
+
+## Stats
+
+Types:
+
+- StatRetrieveResponse
+
+Methods:
+
+- client.emails.stats.retrieve({ ...params }) -> StatRetrieveResponse
+
+## Suppressions
+
+Types:
+
+- SuppressionCreateResponse
+- SuppressionRetrieveResponse
+- SuppressionDeleteResponse
+
+Methods:
+
+- client.emails.suppressions.create({ ...params }) -> SuppressionCreateResponse
+- client.emails.suppressions.retrieve({ ...params }) -> SuppressionRetrieveResponse
+- client.emails.suppressions.delete({ ...params }) -> SuppressionDeleteResponse
+
+## SuppressionsCheck
Types:
-- FullToSimpleCreateResponse
+- SuppressionsCheckRetrieveResponse
Methods:
-- client.convert.fullToSimple.create({ ...params }) -> FullToSimpleCreateResponse
+- client.emails.suppressionsCheck.retrieve({ ...params }) -> SuppressionsCheckRetrieveResponse
-## SimpleToFull
+## Template
Types:
-- SimpleToFullCreateResponse
+- TemplateCreateResponse
Methods:
-- client.convert.simpleToFull.create({ ...params }) -> SimpleToFullCreateResponse
+- client.emails.template.create({ ...params }) -> TemplateCreateResponse
+
+# Me
+
+## Subscription
+
+Types:
+
+- SubscriptionRetrieveResponse
+
+Methods:
+
+- client.me.subscription.retrieve({ ...params }) -> SubscriptionRetrieveResponse
# Projects
Types:
-- ProjectRetrieveResponse
+- ProjectRetrieveResponse
+
+Methods:
+
+- client.projects.retrieve(id) -> ProjectRetrieveResponse
+
+## AICredits
+
+Types:
+
+- AICreditRetrieveResponse
+
+Methods:
+
+- client.projects.aiCredits.retrieve(id) -> AICreditRetrieveResponse
+
+## AICreditsSettings
+
+Types:
+
+- AICreditsSettingRetrieveResponse
+- AICreditsSettingUpdateResponse
Methods:
-- client.projects.retrieve(id) -> ProjectRetrieveResponse
+- client.projects.aiCreditsSettings.retrieve(id) -> AICreditsSettingRetrieveResponse
+- client.projects.aiCreditsSettings.update(id, { ...params }) -> AICreditsSettingUpdateResponse
+
+## AICreditsSettingsRotateSecret
+
+Types:
+
+- AICreditsSettingsRotateSecretCreateResponse
+
+Methods:
+
+- client.projects.aiCreditsSettingsRotateSecret.create(id) -> AICreditsSettingsRotateSecretCreateResponse
+
+## AICreditsUsage
+
+Types:
+
+- AICreditsUsageRetrieveResponse
+
+Methods:
+
+- client.projects.aiCreditsUsage.retrieve(id, { ...params }) -> AICreditsUsageRetrieveResponse
+
+## AICreditsWebhooksDeliveries
+
+Types:
+
+- AICreditsWebhooksDeliveryRetrieveResponse
+
+Methods:
+
+- client.projects.aiCreditsWebhooksDeliveries.retrieve(id, { ...params }) -> AICreditsWebhooksDeliveryRetrieveResponse
+
+## AICreditsWebhooksDeliveriesattempts
+
+Types:
+
+- AICreditsWebhooksDeliveriesattemptRetrieveResponse
+
+Methods:
+
+- client.projects.aiCreditsWebhooksDeliveriesattempts.retrieve(deliveryID, { ...params }) -> AICreditsWebhooksDeliveriesattemptRetrieveResponse
+
+## AICreditsWebhooksDeliveriesretry
+
+Types:
+
+- AICreditsWebhooksDeliveriesretryCreateResponse
+
+Methods:
+
+- client.projects.aiCreditsWebhooksDeliveriesretry.create(deliveryID, { ...params }) -> AICreditsWebhooksDeliveriesretryCreateResponse
# Templates
Types:
-- TemplateRetrieveResponse
-- TemplateListResponse
+- TemplateRetrieveResponse
+- TemplateListResponse
+
+Methods:
+
+- client.templates.retrieve(id, { ...params }) -> TemplateRetrieveResponse
+- client.templates.list({ ...params }) -> TemplateListResponsesCursorPage
+
+## ConvertFullToSimple
+
+Types:
+
+- ConvertFullToSimpleCreateResponse
+
+Methods:
+
+- client.templates.convertFullToSimple.create({ ...params }) -> ConvertFullToSimpleCreateResponse
+
+## ConvertSimpleToFull
+
+Types:
+
+- ConvertSimpleToFullCreateResponse
+
+Methods:
+
+- client.templates.convertSimpleToFull.create({ ...params }) -> ConvertSimpleToFullCreateResponse
+
+## ExportHTML
+
+Types:
+
+- ExportHTMLCreateResponse
+
+Methods:
+
+- client.templates.exportHTML.create({ ...params }) -> ExportHTMLCreateResponse
+
+## ExportImage
+
+Types:
+
+- ExportImageCreateResponse
+
+Methods:
+
+- client.templates.exportImage.create({ ...params }) -> ExportImageCreateResponse
+
+## ExportPdf
+
+Types:
+
+- ExportPdfCreateResponse
+
+Methods:
+
+- client.templates.exportPdf.create({ ...params }) -> ExportPdfCreateResponse
+
+## ExportZip
+
+Types:
+
+- ExportZipCreateResponse
+
+Methods:
+
+- client.templates.exportZip.create({ ...params }) -> ExportZipCreateResponse
+
+## Generate
+
+Types:
+
+- GenerateCreateResponse
+
+Methods:
+
+- client.templates.generate.create({ ...params }) -> GenerateCreateResponse
+- client.templates.generate.retrieve() -> void
+
+## Import
+
+Types:
+
+- ImportCreateResponse
+
+Methods:
+
+- client.templates.import.create({ ...params }) -> ImportCreateResponse
+
+## Schema
+
+Methods:
+
+- client.templates.schema.retrieve({ ...params }) -> void
+
+## Validate
+
+Types:
+
+- ValidateCreateResponse
+
+Methods:
+
+- client.templates.validate.create({ ...params }) -> ValidateCreateResponse
+
+# Webhooks
+
+Types:
+
+- WebhookCreateResponse
+- WebhookRetrieveResponse
+- WebhookUpdateResponse
+- WebhookListResponse
+- WebhookDeleteResponse
+
+Methods:
+
+- client.webhooks.create({ ...params }) -> WebhookCreateResponse
+- client.webhooks.retrieve(id) -> WebhookRetrieveResponse
+- client.webhooks.update(id, { ...params }) -> WebhookUpdateResponse
+- client.webhooks.list() -> WebhookListResponse
+- client.webhooks.delete(id) -> WebhookDeleteResponse
+
+## RotateSecret
+
+Types:
+
+- RotateSecretCreateResponse
Methods:
-- client.templates.retrieve(id, { ...params }) -> TemplateRetrieveResponse
-- client.templates.list({ ...params }) -> TemplateListResponsesCursorPage
+- client.webhooks.rotateSecret.create(id) -> RotateSecretCreateResponse
# 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..3544a8f 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
},
"dependencies": {},
"devDependencies": {
- "@arethetypeswrong/cli": "^0.17.0",
+ "@arethetypeswrong/cli": "^0.18.0",
"@swc/core": "^1.3.102",
"@swc/jest": "^0.2.29",
"@types/jest": "^29.4.0",
@@ -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..dd24fe1 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';
@@ -18,7 +19,31 @@ import { AbstractPage, type CursorPageParams, CursorPageResponse } from './core/
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 { BlockRetrieveParams, BlockRetrieveResponse, Blocks } from './resources/blocks';
+import {
+ EditorSessionCreateParams,
+ EditorSessionCreateResponse,
+ EditorSessions,
+} from './resources/editor-sessions';
+import { WorkspaceListResponse, WorkspaceRetrieveResponse, Workspaces } from './resources/workspaces';
+import {
+ DomainCreateParams,
+ DomainCreateResponse,
+ DomainDeleteResponse,
+ DomainListResponse,
+ DomainRetrieveResponse,
+ Domains,
+} from './resources/domains/domains';
+import {
+ EmailCreateParams,
+ EmailCreateResponse,
+ EmailListParams,
+ EmailListResponse,
+ EmailRetrieveResponse,
+ Emails,
+} from './resources/emails/emails';
+import { Me } from './resources/me/me';
+import { ProjectRetrieveResponse, Projects } from './resources/projects/projects';
import {
TemplateListParams,
TemplateListResponse,
@@ -26,9 +51,17 @@ 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 {
+ WebhookCreateParams,
+ WebhookCreateResponse,
+ WebhookDeleteResponse,
+ WebhookListResponse,
+ WebhookRetrieveResponse,
+ WebhookUpdateParams,
+ WebhookUpdateResponse,
+ Webhooks,
+} from './resources/webhooks/webhooks';
import { type Fetch } from './internal/builtin-types';
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
import { FinalRequestOptions, RequestOptions } from './internal/request-options';
@@ -191,6 +224,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 +316,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 +349,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 +684,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 +781,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 +827,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,15 +853,37 @@ export class Unlayer {
static toFile = Uploads.toFile;
- convert: API.Convert = new API.Convert(this);
+ /**
+ * Reusable design blocks — list shared project blocks and end-user saved blocks for backup, migration, and usage reporting.
+ */
+ blocks: API.Blocks = new API.Blocks(this);
+ domains: API.Domains = new API.Domains(this);
+ editorSessions: API.EditorSessions = new API.EditorSessions(this);
+ emails: API.Emails = new API.Emails(this);
+ me: API.Me = new API.Me(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);
+ webhooks: API.Webhooks = new API.Webhooks(this);
+ /**
+ * Workspace access and management.
+ */
workspaces: API.Workspaces = new API.Workspaces(this);
}
-Unlayer.Convert = Convert;
+Unlayer.Blocks = Blocks;
+Unlayer.Domains = Domains;
+Unlayer.EditorSessions = EditorSessions;
+Unlayer.Emails = Emails;
+Unlayer.Me = Me;
Unlayer.Projects = Projects;
Unlayer.Templates = Templates;
+Unlayer.Webhooks = Webhooks;
Unlayer.Workspaces = Workspaces;
export declare namespace Unlayer {
@@ -829,7 +892,37 @@ export declare namespace Unlayer {
export import CursorPage = Pagination.CursorPage;
export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse };
- export { Convert as Convert };
+ export {
+ Blocks as Blocks,
+ type BlockRetrieveResponse as BlockRetrieveResponse,
+ type BlockRetrieveParams as BlockRetrieveParams,
+ };
+
+ export {
+ Domains as Domains,
+ type DomainCreateResponse as DomainCreateResponse,
+ type DomainRetrieveResponse as DomainRetrieveResponse,
+ type DomainListResponse as DomainListResponse,
+ type DomainDeleteResponse as DomainDeleteResponse,
+ type DomainCreateParams as DomainCreateParams,
+ };
+
+ export {
+ EditorSessions as EditorSessions,
+ type EditorSessionCreateResponse as EditorSessionCreateResponse,
+ type EditorSessionCreateParams as EditorSessionCreateParams,
+ };
+
+ export {
+ Emails as Emails,
+ type EmailCreateResponse as EmailCreateResponse,
+ type EmailRetrieveResponse as EmailRetrieveResponse,
+ type EmailListResponse as EmailListResponse,
+ type EmailCreateParams as EmailCreateParams,
+ type EmailListParams as EmailListParams,
+ };
+
+ export { Me as Me };
export { Projects as Projects, type ProjectRetrieveResponse as ProjectRetrieveResponse };
@@ -842,6 +935,17 @@ export declare namespace Unlayer {
type TemplateListParams as TemplateListParams,
};
+ export {
+ Webhooks as Webhooks,
+ type WebhookCreateResponse as WebhookCreateResponse,
+ type WebhookRetrieveResponse as WebhookRetrieveResponse,
+ type WebhookUpdateResponse as WebhookUpdateResponse,
+ type WebhookListResponse as WebhookListResponse,
+ type WebhookDeleteResponse as WebhookDeleteResponse,
+ type WebhookCreateParams as WebhookCreateParams,
+ type WebhookUpdateParams as WebhookUpdateParams,
+ };
+
export {
Workspaces as Workspaces,
type WorkspaceRetrieveResponse as WorkspaceRetrieveResponse,
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/blocks.ts b/src/resources/blocks.ts
new file mode 100644
index 0000000..d007356
--- /dev/null
+++ b/src/resources/blocks.ts
@@ -0,0 +1,143 @@
+// 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';
+
+/**
+ * Reusable design blocks — list shared project blocks and end-user saved blocks for backup, migration, and usage reporting.
+ */
+export class Blocks extends APIResource {
+ /**
+ * List blocks with cursor-based pagination. Returns both shared project blocks and
+ * blocks saved by end-users; each user-saved block carries the userId it was saved
+ * under (null for shared blocks), so usage can be aggregated per end-user without
+ * enumerating user IDs. Returns blocks in descending order by creation.
+ */
+ retrieve(
+ query: BlockRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/blocks', { query, ...options });
+ }
+}
+
+export interface BlockRetrieveResponse {
+ data: Array;
+
+ /**
+ * Whether there are more results after this page
+ */
+ has_more: boolean;
+
+ /**
+ * Cursor for the next page. Null if no more results.
+ */
+ next_cursor?: string | null;
+}
+
+export namespace BlockRetrieveResponse {
+ export interface Data {
+ /**
+ * Block ID
+ */
+ id?: string;
+
+ /**
+ * Block category
+ */
+ category?: string;
+
+ createdAt?: string;
+
+ /**
+ * The block design JSON. Omitted when includeData=false is passed.
+ */
+ data?: { [key: string]: unknown };
+
+ /**
+ * Display mode the block was saved for: email, web, popup, or document
+ */
+ displayMode?: string;
+
+ /**
+ * Whether the block is currently a synced block
+ */
+ isSyncEnabled?: boolean;
+
+ /**
+ * Synced-block ID referenced by designs using this block. Null when the block has
+ * never been synced.
+ */
+ syncId?: string | null;
+
+ /**
+ * Block tags
+ */
+ tags?: Array;
+
+ /**
+ * URL of the auto-generated block thumbnail, if available
+ */
+ thumbnailUrl?: string | null;
+
+ updatedAt?: string;
+
+ /**
+ * End-user ID the block was saved under (the user id your app passes to the
+ * editor). Null for shared project blocks.
+ */
+ userId?: string | null;
+ }
+}
+
+export interface BlockRetrieveParams {
+ /**
+ * Filter by category (case-insensitive search)
+ */
+ category?: string;
+
+ /**
+ * Pagination cursor from previous response
+ */
+ cursor?: string;
+
+ /**
+ * Filter by display mode
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * Include the block design JSON in each item. Pass false for lightweight sweeps
+ * (e.g. usage reports).
+ */
+ includeData?: boolean;
+
+ /**
+ * Number of blocks to return (1-100)
+ */
+ limit?: number;
+
+ /**
+ * The project ID to list blocks for
+ */
+ projectId?: string;
+
+ /**
+ * Filter by block ownership: shared project blocks, end-user saved blocks, or both
+ */
+ scope?: 'all' | 'shared' | 'user';
+
+ /**
+ * Only blocks saved by this end-user (exact match on the user id your app passes
+ * to the editor)
+ */
+ userId?: string;
+}
+
+export declare namespace Blocks {
+ export {
+ type BlockRetrieveResponse as BlockRetrieveResponse,
+ type BlockRetrieveParams as BlockRetrieveParams,
+ };
+}
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/full-to-simple.ts b/src/resources/convert/full-to-simple.ts
deleted file mode 100644
index 44e02b9..0000000
--- a/src/resources/convert/full-to-simple.ts
+++ /dev/null
@@ -1,59 +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 FullToSimple 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 });
- }
-}
-
-export interface FullToSimpleCreateResponse {
- data?: FullToSimpleCreateResponse.Data;
-
- success?: true;
-}
-
-export namespace FullToSimpleCreateResponse {
- export interface Data {
- design?: { [key: string]: unknown };
- }
-}
-
-export interface FullToSimpleCreateParams {
- design: FullToSimpleCreateParams.Design;
-
- displayMode?: 'email' | 'web' | 'popup' | 'document';
-
- /**
- * When true, includes \_conversion metadata in the response. This metadata can be
- * passed to simple-to-full to restore original values without data loss.
- */
- includeConversion?: boolean;
-
- includeDefaultValues?: boolean;
-}
-
-export namespace FullToSimpleCreateParams {
- export interface Design {
- body: { [key: string]: unknown };
-
- counters?: { [key: string]: unknown };
-
- schemaVersion?: number;
-
- [k: string]: unknown;
- }
-}
-
-export declare namespace FullToSimple {
- export {
- type FullToSimpleCreateResponse as FullToSimpleCreateResponse,
- type FullToSimpleCreateParams as FullToSimpleCreateParams,
- };
-}
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/convert.ts b/src/resources/domains.ts
similarity index 72%
rename from src/resources/convert.ts
rename to src/resources/domains.ts
index 1334f91..5c8cf7e 100644
--- a/src/resources/convert.ts
+++ b/src/resources/domains.ts
@@ -1,3 +1,3 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-export * from './convert/index';
+export * from './domains/index';
diff --git a/src/resources/domains/domains.ts b/src/resources/domains/domains.ts
new file mode 100644
index 0000000..bbba212
--- /dev/null
+++ b/src/resources/domains/domains.ts
@@ -0,0 +1,160 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as VerifyAPI from './verify';
+import { Verify, VerifyCreateResponse } from './verify';
+import { APIPromise } from '../../core/api-promise';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Domains extends APIResource {
+ verify: VerifyAPI.Verify = new VerifyAPI.Verify(this._client);
+
+ /**
+ * Register a sender domain shared by every Developer Email API project in the
+ * workspace. Requires a personal access token belonging to a workspace owner or
+ * admin. Verification requires the workspace-specific TXT record and the returned
+ * SES DKIM records.
+ */
+ create(body: DomainCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/v3/domains', { body, ...options });
+ }
+
+ /**
+ * Get the ownership TXT challenge and SES DKIM records for a sender domain shared
+ * by every Developer Email API project in the workspace. Requires a personal
+ * access token belonging to a workspace owner or admin.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/domains/${id}`, options);
+ }
+
+ /**
+ * List sender domains shared by every Developer Email API project in the
+ * workspace. Requires a personal access token belonging to a workspace owner or
+ * admin; project API keys cannot manage domains.
+ */
+ list(options?: RequestOptions): APIPromise {
+ return this._client.get('/v3/domains', options);
+ }
+
+ /**
+ * Delete a sender domain shared by every Developer Email API project in the
+ * workspace. Requires a personal access token belonging to a workspace owner or
+ * admin. The SES identity remains so a later reconciler can clean it up safely.
+ */
+ delete(id: string, options?: RequestOptions): APIPromise {
+ return this._client.delete(path`/v3/domains/${id}`, options);
+ }
+}
+
+export interface DomainCreateResponse {
+ data: DomainCreateResponse.Data;
+}
+
+export namespace DomainCreateResponse {
+ export interface Data {
+ id?: number;
+
+ createdAt?: string;
+
+ dkimTokens?: Array;
+
+ dnsRecords?: Array;
+
+ domain?: string;
+
+ status?: 'pending' | 'verified' | 'failed';
+ }
+
+ export namespace Data {
+ export interface DNSRecord {
+ name?: string;
+
+ purpose?: string;
+
+ type?: string;
+
+ value?: string;
+ }
+ }
+}
+
+export interface DomainRetrieveResponse {
+ data: DomainRetrieveResponse.Data;
+}
+
+export namespace DomainRetrieveResponse {
+ export interface Data {
+ id?: number;
+
+ createdAt?: string;
+
+ dkimTokens?: Array;
+
+ dnsRecords?: Array;
+
+ domain?: string;
+
+ status?: string;
+ }
+
+ export namespace Data {
+ export interface DNSRecord {
+ name?: string;
+
+ purpose?: string;
+
+ type?: string;
+
+ value?: string;
+ }
+ }
+}
+
+export interface DomainListResponse {
+ data: Array;
+}
+
+export namespace DomainListResponse {
+ export interface Data {
+ id?: number;
+
+ createdAt?: string;
+
+ domain?: string;
+
+ status?: 'pending' | 'verified' | 'failed';
+ }
+}
+
+export interface DomainDeleteResponse {
+ data?: DomainDeleteResponse.Data;
+}
+
+export namespace DomainDeleteResponse {
+ export interface Data {
+ success?: boolean;
+ }
+}
+
+export interface DomainCreateParams {
+ /**
+ * Domain name to register, such as example.com.
+ */
+ domain: string;
+}
+
+Domains.Verify = Verify;
+
+export declare namespace Domains {
+ export {
+ type DomainCreateResponse as DomainCreateResponse,
+ type DomainRetrieveResponse as DomainRetrieveResponse,
+ type DomainListResponse as DomainListResponse,
+ type DomainDeleteResponse as DomainDeleteResponse,
+ type DomainCreateParams as DomainCreateParams,
+ };
+
+ export { Verify as Verify, type VerifyCreateResponse as VerifyCreateResponse };
+}
diff --git a/src/resources/domains/index.ts b/src/resources/domains/index.ts
new file mode 100644
index 0000000..fae2293
--- /dev/null
+++ b/src/resources/domains/index.ts
@@ -0,0 +1,11 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export {
+ Domains,
+ type DomainCreateResponse,
+ type DomainRetrieveResponse,
+ type DomainListResponse,
+ type DomainDeleteResponse,
+ type DomainCreateParams,
+} from './domains';
+export { Verify, type VerifyCreateResponse } from './verify';
diff --git a/src/resources/domains/verify.ts b/src/resources/domains/verify.ts
new file mode 100644
index 0000000..c11fe69
--- /dev/null
+++ b/src/resources/domains/verify.ts
@@ -0,0 +1,51 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+export class Verify extends APIResource {
+ /**
+ * Verify the ownership TXT challenge and SES DKIM identity for a sender domain
+ * shared by every Developer Email API project in the workspace. Requires a
+ * personal access token belonging to a workspace owner or admin.
+ */
+ create(id: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/v3/domains/${id}/verify`, options);
+ }
+}
+
+export interface VerifyCreateResponse {
+ data: VerifyCreateResponse.Data;
+}
+
+export namespace VerifyCreateResponse {
+ export interface Data {
+ id?: number;
+
+ dkim?: Data.Dkim;
+
+ domain?: string;
+
+ ownership?: Data.Ownership;
+
+ status?: string;
+ }
+
+ export namespace Data {
+ export interface Dkim {
+ status?: string;
+
+ tokens?: Array;
+ }
+
+ export interface Ownership {
+ verified?: boolean;
+ }
+ }
+}
+
+export declare namespace Verify {
+ export { type VerifyCreateResponse as VerifyCreateResponse };
+}
diff --git a/src/resources/editor-sessions.ts b/src/resources/editor-sessions.ts
new file mode 100644
index 0000000..dd297aa
--- /dev/null
+++ b/src/resources/editor-sessions.ts
@@ -0,0 +1,58 @@
+// 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 EditorSessions extends APIResource {
+ /**
+ * Create an ephemeral, no-DB editor session for a design and return a hosted
+ * editor URL the user can open to edit it in the real Unlayer editor.
+ */
+ create(
+ params: EditorSessionCreateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { projectId, ...body } = params;
+ return this._client.post('/v3/editor-sessions', { query: { projectId }, body, ...options });
+ }
+}
+
+export interface EditorSessionCreateResponse {
+ data?: EditorSessionCreateResponse.Data;
+}
+
+export namespace EditorSessionCreateResponse {
+ export interface Data {
+ token?: string;
+
+ editorUrl?: string;
+
+ expiresAt?: string;
+ }
+}
+
+export interface EditorSessionCreateParams {
+ /**
+ * Body param: Design JSON to load into the editor.
+ */
+ design: { [key: string]: unknown };
+
+ /**
+ * Query param: The project ID (required for PAT auth, auto-resolved for API key
+ * auth)
+ */
+ projectId?: string;
+
+ /**
+ * Body param: Editor display mode. Defaults to email.
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+}
+
+export declare namespace EditorSessions {
+ export {
+ type EditorSessionCreateResponse as EditorSessionCreateResponse,
+ type EditorSessionCreateParams as EditorSessionCreateParams,
+ };
+}
diff --git a/src/resources/emails.ts b/src/resources/emails.ts
new file mode 100644
index 0000000..bd0ec59
--- /dev/null
+++ b/src/resources/emails.ts
@@ -0,0 +1,3 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export * from './emails/index';
diff --git a/src/resources/emails/emails.ts b/src/resources/emails/emails.ts
new file mode 100644
index 0000000..ffecad2
--- /dev/null
+++ b/src/resources/emails/emails.ts
@@ -0,0 +1,414 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as EventsAPI from './events';
+import { EventRetrieveResponse, Events } from './events';
+import * as RenderAPI from './render';
+import { Render, RenderCreateParams, RenderCreateResponse } from './render';
+import * as SettingsAPI from './settings';
+import { SettingRetrieveResponse, SettingUpdateParams, SettingUpdateResponse, Settings } from './settings';
+import * as StatsAPI from './stats';
+import { StatRetrieveParams, StatRetrieveResponse, Stats } from './stats';
+import * as SuppressionsAPI from './suppressions';
+import {
+ SuppressionCreateParams,
+ SuppressionCreateResponse,
+ SuppressionDeleteParams,
+ SuppressionDeleteResponse,
+ SuppressionRetrieveParams,
+ SuppressionRetrieveResponse,
+ Suppressions,
+} from './suppressions';
+import * as SuppressionsCheckAPI from './suppressions-check';
+import {
+ SuppressionsCheck,
+ SuppressionsCheckRetrieveParams,
+ SuppressionsCheckRetrieveResponse,
+} from './suppressions-check';
+import * as TemplateAPI from './template';
+import { Template, TemplateCreateParams, TemplateCreateResponse } from './template';
+import { APIPromise } from '../../core/api-promise';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Emails extends APIResource {
+ events: EventsAPI.Events = new EventsAPI.Events(this._client);
+ render: RenderAPI.Render = new RenderAPI.Render(this._client);
+ settings: SettingsAPI.Settings = new SettingsAPI.Settings(this._client);
+ stats: StatsAPI.Stats = new StatsAPI.Stats(this._client);
+ suppressions: SuppressionsAPI.Suppressions = new SuppressionsAPI.Suppressions(this._client);
+ suppressionsCheck: SuppressionsCheckAPI.SuppressionsCheck = new SuppressionsCheckAPI.SuppressionsCheck(
+ this._client,
+ );
+ template: TemplateAPI.Template = new TemplateAPI.Template(this._client);
+
+ /**
+ * Send a transactional email with raw HTML content. The sender domain must be
+ * verified in the project workspace; verified sender domains are shared by every
+ * Developer Email API project in that workspace.
+ */
+ create(params: EmailCreateParams, options?: RequestOptions): APIPromise {
+ const { 'idempotency-key': idempotencyKey, ...body } = params;
+ return this._client.post('/v3/emails', {
+ body,
+ ...options,
+ headers: buildHeaders([
+ { ...(idempotencyKey != null ? { 'idempotency-key': idempotencyKey } : undefined) },
+ options?.headers,
+ ]),
+ });
+ }
+
+ /**
+ * Retrieve details of a sent email, including its current delivery status, during
+ * the rolling 90-day history window. Expired emails return 404.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/emails/${id}`, options);
+ }
+
+ /**
+ * List emails sent from this project within the rolling 90-day history window.
+ * Without a status filter, results and date bounds use acceptance time. With a
+ * status filter, results and date bounds use the time each email entered that
+ * status.
+ */
+ list(
+ query: EmailListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/emails', { query, ...options });
+ }
+}
+
+/**
+ * Email accepted and queued for delivery
+ */
+export interface EmailCreateResponse {
+ data: EmailCreateResponse.Data;
+}
+
+export namespace EmailCreateResponse {
+ export interface Data {
+ /**
+ * Unique email ID (UUID). Use this with GET /v3/emails/:id to retrieve delivery
+ * status and events.
+ */
+ id?: string;
+
+ /**
+ * When the email was accepted and queued for delivery (ISO-8601).
+ */
+ createdAt?: string;
+
+ /**
+ * The sender address the email was sent from, either a plain email or "Name
+ * " format.
+ */
+ from?: string;
+
+ /**
+ * Usually "queued" for a fresh send. An idempotent replay of a previously accepted
+ * request returns that email's current status instead. Use webhooks or GET
+ * /v3/emails/:id for live delivery status.
+ */
+ status?: 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed';
+
+ /**
+ * The subject line of the email that was sent.
+ */
+ subject?: string;
+
+ /**
+ * The single accepted recipient address.
+ */
+ to?: Array;
+ }
+}
+
+export interface EmailRetrieveResponse {
+ data: EmailRetrieveResponse.Data;
+}
+
+export namespace EmailRetrieveResponse {
+ export interface Data {
+ id?: string;
+
+ bcc?: Array | null;
+
+ cc?: Array | null;
+
+ createdAt?: string;
+
+ failureReason?: string | null;
+
+ from?: string;
+
+ status?: string;
+
+ subject?: string | null;
+
+ tags?: { [key: string]: string } | null;
+
+ to?: unknown;
+ }
+}
+
+export interface EmailListResponse {
+ data: Array;
+
+ /**
+ * Whether there are more results after this page
+ */
+ has_more: boolean;
+
+ /**
+ * Cursor for the next page. Null if no more results.
+ */
+ next_cursor?: string | null;
+}
+
+export namespace EmailListResponse {
+ export interface Data {
+ id?: string;
+
+ createdAt?: string;
+
+ from?: string;
+
+ status?: string;
+
+ /**
+ * When the email entered its current status. For a newly queued email, this equals
+ * createdAt.
+ */
+ statusUpdatedAt?: string;
+
+ subject?: string | null;
+
+ to?: unknown;
+ }
+}
+
+export interface EmailCreateParams {
+ /**
+ * Body param: Sender email address or "Name " format. Domain must be
+ * verified.
+ */
+ from: string;
+
+ /**
+ * Body param: HTML content of the email
+ */
+ html: string;
+
+ /**
+ * Body param: Email subject line
+ */
+ subject: string;
+
+ /**
+ * Body param: Exactly one recipient. Each request creates one independently
+ * tracked delivery.
+ */
+ to: Array;
+
+ /**
+ * Body param: File attachments. Max 10 files per email, max 5 MB total payload
+ * size (including headers and base64 overhead).
+ */
+ attachments?: Array;
+
+ /**
+ * Body param: BCC is not supported by this endpoint.
+ */
+ bcc?: Array;
+
+ /**
+ * Body param: CC is not supported by this endpoint.
+ */
+ cc?: Array;
+
+ /**
+ * Body param: Custom email headers. Up to 9 printable-ASCII X-\* headers are
+ * allowed (e.g. {"X-Entity-Ref-ID": "abc123"}). Header names may contain up to 126
+ * characters and each name plus value may contain up to 996 characters.
+ */
+ headers?: { [key: string]: string };
+
+ /**
+ * Body param: Reply-To email address
+ */
+ replyTo?: string;
+
+ /**
+ * Body param: Key-value tags for categorizing the email (e.g. {"campaign":
+ * "welcome"}). Max 10 tags. Keys (1-64 chars) and values (up to 256 chars) may
+ * only contain letters, numbers, underscores, and hyphens (the Amazon SES
+ * message-tag character set).
+ */
+ tags?: { [key: string]: string };
+
+ /**
+ * Body param: Plain text version of the email. If provided, a
+ * multipart/alternative message is sent.
+ */
+ text?: string;
+
+ /**
+ * Header param: Unique key for idempotent sends (max 255 characters). If provided,
+ * duplicate requests within 24 hours return the cached response.
+ */
+ 'idempotency-key'?: string;
+}
+
+export namespace EmailCreateParams {
+ export interface Attachment {
+ /**
+ * Base64-encoded file content. Whitespace and MIME line wrapping are removed
+ * before validation; invalid base64 is rejected with a 400 error.
+ */
+ content: string;
+
+ /**
+ * MIME type of the attachment. Required; must be one of the allowed types.
+ */
+ contentType:
+ | 'application/pdf'
+ | 'application/zip'
+ | 'application/json'
+ | 'application/xml'
+ | 'application/csv'
+ | 'application/msword'
+ | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ | 'application/vnd.ms-excel'
+ | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ | 'application/vnd.ms-powerpoint'
+ | 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
+ | 'text/plain'
+ | 'text/html'
+ | 'text/csv'
+ | 'text/xml'
+ | 'text/calendar'
+ | 'image/png'
+ | 'image/jpeg'
+ | 'image/gif'
+ | 'image/webp'
+ | 'image/svg+xml'
+ | 'audio/mpeg'
+ | 'audio/wav'
+ | 'video/mp4';
+
+ /**
+ * The filename as it will appear to the recipient. Line breaks are rejected;
+ * quotes are stripped before it is written into the message.
+ */
+ filename: string;
+ }
+}
+
+export interface EmailListParams {
+ /**
+ * Pagination cursor from previous response
+ */
+ cursor?: string;
+
+ /**
+ * Start date (ISO date). Bounds acceptance time normally, or status transition
+ * time when status is supplied.
+ */
+ from?: string;
+
+ /**
+ * Number of emails to return (1-100)
+ */
+ limit?: number;
+
+ /**
+ * Project ID (auto-resolved for API key auth)
+ */
+ projectId?: string;
+
+ /**
+ * Search recipient addresses and subjects by case-sensitive substring
+ */
+ search?: string;
+
+ /**
+ * Filter by email delivery status
+ */
+ status?: 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed';
+
+ /**
+ * Filter by tag in "key=value" format (e.g. "campaign=welcome")
+ */
+ tag?: string;
+
+ /**
+ * End date (ISO date). Bounds acceptance time normally, or status transition time
+ * when status is supplied.
+ */
+ to?: string;
+}
+
+Emails.Events = Events;
+Emails.Render = Render;
+Emails.Settings = Settings;
+Emails.Stats = Stats;
+Emails.Suppressions = Suppressions;
+Emails.SuppressionsCheck = SuppressionsCheck;
+Emails.Template = Template;
+
+export declare namespace Emails {
+ export {
+ type EmailCreateResponse as EmailCreateResponse,
+ type EmailRetrieveResponse as EmailRetrieveResponse,
+ type EmailListResponse as EmailListResponse,
+ type EmailCreateParams as EmailCreateParams,
+ type EmailListParams as EmailListParams,
+ };
+
+ export { Events as Events, type EventRetrieveResponse as EventRetrieveResponse };
+
+ export {
+ Render as Render,
+ type RenderCreateResponse as RenderCreateResponse,
+ type RenderCreateParams as RenderCreateParams,
+ };
+
+ export {
+ Settings as Settings,
+ type SettingRetrieveResponse as SettingRetrieveResponse,
+ type SettingUpdateResponse as SettingUpdateResponse,
+ type SettingUpdateParams as SettingUpdateParams,
+ };
+
+ export {
+ Stats as Stats,
+ type StatRetrieveResponse as StatRetrieveResponse,
+ type StatRetrieveParams as StatRetrieveParams,
+ };
+
+ export {
+ Suppressions as Suppressions,
+ type SuppressionCreateResponse as SuppressionCreateResponse,
+ type SuppressionRetrieveResponse as SuppressionRetrieveResponse,
+ type SuppressionDeleteResponse as SuppressionDeleteResponse,
+ type SuppressionCreateParams as SuppressionCreateParams,
+ type SuppressionRetrieveParams as SuppressionRetrieveParams,
+ type SuppressionDeleteParams as SuppressionDeleteParams,
+ };
+
+ export {
+ SuppressionsCheck as SuppressionsCheck,
+ type SuppressionsCheckRetrieveResponse as SuppressionsCheckRetrieveResponse,
+ type SuppressionsCheckRetrieveParams as SuppressionsCheckRetrieveParams,
+ };
+
+ export {
+ Template as Template,
+ type TemplateCreateResponse as TemplateCreateResponse,
+ type TemplateCreateParams as TemplateCreateParams,
+ };
+}
diff --git a/src/resources/emails/events.ts b/src/resources/emails/events.ts
new file mode 100644
index 0000000..3fe709a
--- /dev/null
+++ b/src/resources/emails/events.ts
@@ -0,0 +1,38 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+export class Events extends APIResource {
+ /**
+ * Retrieve the operational event timeline for a sent email, showing send,
+ * delivery, bounce, and complaint events in chronological order during the rolling
+ * 90-day history window. Expired emails return 404.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/emails/${id}/events`, options);
+ }
+}
+
+export interface EventRetrieveResponse {
+ data: Array;
+}
+
+export namespace EventRetrieveResponse {
+ export interface Data {
+ metadata?: { [key: string]: unknown } | null;
+
+ timestamp?: string;
+
+ /**
+ * Event type (send, delivery, bounce, complaint)
+ */
+ type?: string;
+ }
+}
+
+export declare namespace Events {
+ export { type EventRetrieveResponse as EventRetrieveResponse };
+}
diff --git a/src/resources/emails/index.ts b/src/resources/emails/index.ts
new file mode 100644
index 0000000..c0b2b7a
--- /dev/null
+++ b/src/resources/emails/index.ts
@@ -0,0 +1,34 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export {
+ Emails,
+ type EmailCreateResponse,
+ type EmailRetrieveResponse,
+ type EmailListResponse,
+ type EmailCreateParams,
+ type EmailListParams,
+} from './emails';
+export { Events, type EventRetrieveResponse } from './events';
+export { Render, type RenderCreateResponse, type RenderCreateParams } from './render';
+export {
+ Settings,
+ type SettingRetrieveResponse,
+ type SettingUpdateResponse,
+ type SettingUpdateParams,
+} from './settings';
+export { Stats, type StatRetrieveResponse, type StatRetrieveParams } from './stats';
+export {
+ Suppressions,
+ type SuppressionCreateResponse,
+ type SuppressionRetrieveResponse,
+ type SuppressionDeleteResponse,
+ type SuppressionCreateParams,
+ type SuppressionRetrieveParams,
+ type SuppressionDeleteParams,
+} from './suppressions';
+export {
+ SuppressionsCheck,
+ type SuppressionsCheckRetrieveResponse,
+ type SuppressionsCheckRetrieveParams,
+} from './suppressions-check';
+export { Template, type TemplateCreateResponse, type TemplateCreateParams } from './template';
diff --git a/src/resources/emails/render.ts b/src/resources/emails/render.ts
new file mode 100644
index 0000000..e1ea2c2
--- /dev/null
+++ b/src/resources/emails/render.ts
@@ -0,0 +1,49 @@
+// 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 Render extends APIResource {
+ /**
+ * Render a saved email template with optional merge variables. Returns the final
+ * HTML without sending. Useful for previewing emails before sending.
+ */
+ create(body: RenderCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/v3/emails/render', { body, ...options });
+ }
+}
+
+export interface RenderCreateResponse {
+ data: RenderCreateResponse.Data;
+}
+
+export namespace RenderCreateResponse {
+ export interface Data {
+ /**
+ * Rendered HTML content
+ */
+ html?: string;
+
+ /**
+ * Template name (can be used as default subject)
+ */
+ subject?: string | null;
+ }
+}
+
+export interface RenderCreateParams {
+ /**
+ * Template ID to render
+ */
+ templateId: string;
+
+ /**
+ * Merge variables to substitute. Use {{key}} syntax in your template.
+ */
+ variables?: { [key: string]: string };
+}
+
+export declare namespace Render {
+ export { type RenderCreateResponse as RenderCreateResponse, type RenderCreateParams as RenderCreateParams };
+}
diff --git a/src/resources/emails/settings.ts b/src/resources/emails/settings.ts
new file mode 100644
index 0000000..dd07f31
--- /dev/null
+++ b/src/resources/emails/settings.ts
@@ -0,0 +1,86 @@
+// 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 Settings extends APIResource {
+ /**
+ * Get the email sender settings for this project.
+ */
+ retrieve(options?: RequestOptions): APIPromise {
+ return this._client.get('/v3/emails/settings', options);
+ }
+
+ /**
+ * Update the email sending configuration for this project. Only include the fields
+ * you want to change.
+ */
+ update(
+ body: SettingUpdateParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.patch('/v3/emails/settings', { body, ...options });
+ }
+}
+
+export interface SettingRetrieveResponse {
+ data: SettingRetrieveResponse.Data;
+}
+
+export namespace SettingRetrieveResponse {
+ export interface Data {
+ /**
+ * When the settings row was first created.
+ */
+ createdAt?: string;
+
+ /**
+ * Default sender display name
+ */
+ defaultFromName?: string;
+
+ /**
+ * When the settings were last updated.
+ */
+ updatedAt?: string;
+ }
+}
+
+export interface SettingUpdateResponse {
+ data: SettingUpdateResponse.Data;
+}
+
+export namespace SettingUpdateResponse {
+ export interface Data {
+ /**
+ * When the settings row was first created.
+ */
+ createdAt?: string;
+
+ /**
+ * Default sender display name
+ */
+ defaultFromName?: string;
+
+ /**
+ * When the settings were last updated.
+ */
+ updatedAt?: string;
+ }
+}
+
+export interface SettingUpdateParams {
+ /**
+ * Default sender display name
+ */
+ defaultFromName?: string;
+}
+
+export declare namespace Settings {
+ export {
+ type SettingRetrieveResponse as SettingRetrieveResponse,
+ type SettingUpdateResponse as SettingUpdateResponse,
+ type SettingUpdateParams as SettingUpdateParams,
+ };
+}
diff --git a/src/resources/emails/stats.ts b/src/resources/emails/stats.ts
new file mode 100644
index 0000000..eb0f0e1
--- /dev/null
+++ b/src/resources/emails/stats.ts
@@ -0,0 +1,120 @@
+// 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 Stats extends APIResource {
+ /**
+ * Get aggregated email delivery statistics for a project. Returns totals or daily
+ * breakdown for the specified period. Statistics are asynchronous and may lag by
+ * about one hour.
+ */
+ retrieve(
+ query: StatRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/emails/stats', { query, ...options });
+ }
+}
+
+/**
+ * Email statistics. Shape depends on the `groupBy` query parameter: an aggregated
+ * totals object by default, or a daily breakdown array when groupBy=day.
+ */
+export interface StatRetrieveResponse {
+ /**
+ * Aggregated totals for the requested period (default response).
+ */
+ data: StatRetrieveResponse.UnionMember0 | Array;
+}
+
+export namespace StatRetrieveResponse {
+ /**
+ * Aggregated totals for the requested period (default response).
+ */
+ export interface UnionMember0 {
+ /**
+ * Number of emails that were bounced by the recipient mail server.
+ */
+ bounced?: number;
+
+ /**
+ * Bounced / sent as a percentage (0-100, 2 decimal places).
+ */
+ bounceRate?: number;
+
+ /**
+ * Number of spam complaint events received.
+ */
+ complained?: number;
+
+ /**
+ * Number of successfully delivered emails.
+ */
+ delivered?: number;
+
+ /**
+ * Delivered / sent as a percentage (0-100, 2 decimal places).
+ */
+ deliveryRate?: number;
+
+ /**
+ * The period these stats cover.
+ */
+ period?: '7d' | '30d' | '90d';
+
+ /**
+ * Total emails sent (one per recipient).
+ */
+ sent?: number;
+ }
+
+ export interface UnionMember1 {
+ /**
+ * Emails bounced on this day.
+ */
+ bounced?: number;
+
+ /**
+ * Spam complaints received for this send cohort.
+ */
+ complained?: number;
+
+ /**
+ * The email send-cohort day in YYYY-MM-DD format.
+ */
+ date?: string;
+
+ /**
+ * Emails from this send cohort that were delivered.
+ */
+ delivered?: number;
+
+ /**
+ * Emails sent on this day.
+ */
+ sent?: number;
+ }
+}
+
+export interface StatRetrieveParams {
+ /**
+ * Group results by day for chart data
+ */
+ groupBy?: 'day';
+
+ /**
+ * Time period for stats
+ */
+ period?: '7d' | '30d' | '90d';
+
+ /**
+ * Project ID (auto-resolved for API key auth)
+ */
+ projectId?: string;
+}
+
+export declare namespace Stats {
+ export { type StatRetrieveResponse as StatRetrieveResponse, type StatRetrieveParams as StatRetrieveParams };
+}
diff --git a/src/resources/emails/suppressions-check.ts b/src/resources/emails/suppressions-check.ts
new file mode 100644
index 0000000..22a5cf2
--- /dev/null
+++ b/src/resources/emails/suppressions-check.ts
@@ -0,0 +1,49 @@
+// 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 SuppressionsCheck extends APIResource {
+ /**
+ * Look up a specific email address to see if it is currently on the suppression
+ * list.
+ */
+ retrieve(
+ query: SuppressionsCheckRetrieveParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/emails/suppressions/check', { query, ...options });
+ }
+}
+
+export interface SuppressionsCheckRetrieveResponse {
+ data: SuppressionsCheckRetrieveResponse.Data;
+}
+
+export namespace SuppressionsCheckRetrieveResponse {
+ export interface Data {
+ email?: string;
+
+ suppressed?: boolean;
+ }
+}
+
+export interface SuppressionsCheckRetrieveParams {
+ /**
+ * Email address to check
+ */
+ email: string;
+
+ /**
+ * Project ID (auto-resolved for API key auth)
+ */
+ projectId?: string;
+}
+
+export declare namespace SuppressionsCheck {
+ export {
+ type SuppressionsCheckRetrieveResponse as SuppressionsCheckRetrieveResponse,
+ type SuppressionsCheckRetrieveParams as SuppressionsCheckRetrieveParams,
+ };
+}
diff --git a/src/resources/emails/suppressions.ts b/src/resources/emails/suppressions.ts
new file mode 100644
index 0000000..96a9efc
--- /dev/null
+++ b/src/resources/emails/suppressions.ts
@@ -0,0 +1,126 @@
+// 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 Suppressions extends APIResource {
+ /**
+ * Manually add an email address to the suppression list. Future sends to this
+ * address will be blocked.
+ */
+ create(body: SuppressionCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/v3/emails/suppressions', { body, ...options });
+ }
+
+ /**
+ * List all email addresses suppressed for this project due to bounces, complaints,
+ * or manual suppression. Cursor-paginated.
+ */
+ retrieve(
+ query: SuppressionRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/emails/suppressions', { query, ...options });
+ }
+
+ /**
+ * Remove an email address from the suppression list so it can receive emails
+ * again.
+ */
+ delete(params: SuppressionDeleteParams, options?: RequestOptions): APIPromise {
+ const { email, projectId } = params;
+ return this._client.delete('/v3/emails/suppressions', { query: { email, projectId }, ...options });
+ }
+}
+
+export interface SuppressionCreateResponse {
+ data: SuppressionCreateResponse.Data;
+}
+
+export namespace SuppressionCreateResponse {
+ export interface Data {
+ createdAt?: string;
+
+ email?: string;
+
+ reason?: string;
+ }
+}
+
+export interface SuppressionRetrieveResponse {
+ data: Array;
+
+ has_more: boolean;
+
+ next_cursor?: string | null;
+}
+
+export namespace SuppressionRetrieveResponse {
+ export interface Data {
+ createdAt?: string;
+
+ email?: string;
+
+ reason?: 'hard_bounce' | 'complaint' | 'manual' | 'unsubscribe';
+ }
+}
+
+export interface SuppressionDeleteResponse {
+ data: SuppressionDeleteResponse.Data;
+}
+
+export namespace SuppressionDeleteResponse {
+ export interface Data {
+ email?: string;
+
+ removed?: boolean;
+ }
+}
+
+export interface SuppressionCreateParams {
+ /**
+ * Email address to suppress
+ */
+ email: string;
+}
+
+export interface SuppressionRetrieveParams {
+ /**
+ * Pagination cursor from a previous response. Omit to start from the beginning.
+ */
+ cursor?: string;
+
+ /**
+ * Max number of results (1-200)
+ */
+ limit?: number;
+
+ /**
+ * Project ID (auto-resolved for API key auth)
+ */
+ projectId?: string;
+}
+
+export interface SuppressionDeleteParams {
+ /**
+ * Email address to unsuppress
+ */
+ email: string;
+
+ /**
+ * Project ID (auto-resolved for API key auth)
+ */
+ projectId?: string;
+}
+
+export declare namespace Suppressions {
+ export {
+ type SuppressionCreateResponse as SuppressionCreateResponse,
+ type SuppressionRetrieveResponse as SuppressionRetrieveResponse,
+ type SuppressionDeleteResponse as SuppressionDeleteResponse,
+ type SuppressionCreateParams as SuppressionCreateParams,
+ type SuppressionRetrieveParams as SuppressionRetrieveParams,
+ type SuppressionDeleteParams as SuppressionDeleteParams,
+ };
+}
diff --git a/src/resources/emails/template.ts b/src/resources/emails/template.ts
new file mode 100644
index 0000000..fd8906f
--- /dev/null
+++ b/src/resources/emails/template.ts
@@ -0,0 +1,201 @@
+// 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 Template extends APIResource {
+ /**
+ * Send a transactional email by rendering a saved template with optional merge
+ * variables. The template must have rendered HTML (saved at least once in the
+ * editor). The sender domain must be verified in the project workspace; verified
+ * sender domains are shared by every Developer Email API project in that
+ * workspace.
+ */
+ create(params: TemplateCreateParams, options?: RequestOptions): APIPromise {
+ const { 'idempotency-key': idempotencyKey, ...body } = params;
+ return this._client.post('/v3/emails/template', {
+ body,
+ ...options,
+ headers: buildHeaders([
+ { ...(idempotencyKey != null ? { 'idempotency-key': idempotencyKey } : undefined) },
+ options?.headers,
+ ]),
+ });
+ }
+}
+
+/**
+ * Email accepted and queued for delivery
+ */
+export interface TemplateCreateResponse {
+ data: TemplateCreateResponse.Data;
+}
+
+export namespace TemplateCreateResponse {
+ export interface Data {
+ /**
+ * Unique email ID (UUID). Use this with GET /v3/emails/:id to retrieve delivery
+ * status and events.
+ */
+ id?: string;
+
+ /**
+ * When the email was accepted and queued for delivery (ISO-8601).
+ */
+ createdAt?: string;
+
+ /**
+ * The sender address the email was sent from.
+ */
+ from?: string;
+
+ /**
+ * Usually "queued" for a fresh send. An idempotent replay of a previously accepted
+ * request returns that email's current status instead. Use webhooks or GET
+ * /v3/emails/:id for live delivery status.
+ */
+ status?: 'queued' | 'sending' | 'sent' | 'delivered' | 'bounced' | 'complained' | 'failed';
+
+ /**
+ * The resolved subject line after merge variables were applied.
+ */
+ subject?: string;
+
+ /**
+ * The single accepted recipient address.
+ */
+ to?: Array;
+ }
+}
+
+export interface TemplateCreateParams {
+ /**
+ * Body param: Sender email address or "Name " format. Domain must be
+ * verified.
+ */
+ from: string;
+
+ /**
+ * Body param: Template ID to use for the email body
+ */
+ templateId: string;
+
+ /**
+ * Body param: Exactly one recipient. Each request creates one independently
+ * tracked delivery.
+ */
+ to: Array;
+
+ /**
+ * Body param: File attachments. Max 10 files per email, max 5 MB total payload
+ * size.
+ */
+ attachments?: Array;
+
+ /**
+ * Body param: BCC is not supported by this endpoint.
+ */
+ bcc?: Array;
+
+ /**
+ * Body param: CC is not supported by this endpoint.
+ */
+ cc?: Array;
+
+ /**
+ * Body param: Custom email headers. Up to 9 printable-ASCII X-\* headers are
+ * allowed. Header names may contain up to 126 characters and each name plus value
+ * may contain up to 996 characters.
+ */
+ headers?: { [key: string]: string };
+
+ /**
+ * Body param: Reply-To email address
+ */
+ replyTo?: string;
+
+ /**
+ * Body param: Email subject line. Supports {{variable}} merge syntax. Defaults to
+ * template name if omitted.
+ */
+ subject?: string;
+
+ /**
+ * Body param: Key-value tags for categorizing the email (e.g. {"campaign":
+ * "welcome"}). Max 10 tags. Keys (1-64 chars) and values (up to 256 chars) may
+ * only contain letters, numbers, underscores, and hyphens (the Amazon SES
+ * message-tag character set).
+ */
+ tags?: { [key: string]: string };
+
+ /**
+ * Body param: Plain text version of the email. Supports {{variable}} merge syntax.
+ */
+ text?: string;
+
+ /**
+ * Body param: Merge variables to substitute in the template and subject. Use
+ * {{key}} syntax in your template.
+ */
+ variables?: { [key: string]: string };
+
+ /**
+ * Header param: Unique key for idempotent sends (max 255 characters). Duplicate
+ * requests within 24 hours return the cached response.
+ */
+ 'idempotency-key'?: string;
+}
+
+export namespace TemplateCreateParams {
+ export interface Attachment {
+ /**
+ * Base64-encoded file content. Whitespace and MIME line wrapping are removed
+ * before validation; invalid base64 is rejected with a 400 error.
+ */
+ content: string;
+
+ /**
+ * MIME type of the attachment. Required; must be one of the allowed types.
+ */
+ contentType:
+ | 'application/pdf'
+ | 'application/zip'
+ | 'application/json'
+ | 'application/xml'
+ | 'application/csv'
+ | 'application/msword'
+ | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ | 'application/vnd.ms-excel'
+ | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ | 'application/vnd.ms-powerpoint'
+ | 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
+ | 'text/plain'
+ | 'text/html'
+ | 'text/csv'
+ | 'text/xml'
+ | 'text/calendar'
+ | 'image/png'
+ | 'image/jpeg'
+ | 'image/gif'
+ | 'image/webp'
+ | 'image/svg+xml'
+ | 'audio/mpeg'
+ | 'audio/wav'
+ | 'video/mp4';
+
+ /**
+ * The filename as it will appear to the recipient. Line breaks are rejected;
+ * quotes are stripped before it is written into the message.
+ */
+ filename: string;
+ }
+}
+
+export declare namespace Template {
+ export {
+ type TemplateCreateResponse as TemplateCreateResponse,
+ type TemplateCreateParams as TemplateCreateParams,
+ };
+}
diff --git a/src/resources/index.ts b/src/resources/index.ts
index 303eae0..c40edde 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -1,7 +1,29 @@
// 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 { Blocks, type BlockRetrieveResponse, type BlockRetrieveParams } from './blocks';
+export {
+ Domains,
+ type DomainCreateResponse,
+ type DomainRetrieveResponse,
+ type DomainListResponse,
+ type DomainDeleteResponse,
+ type DomainCreateParams,
+} from './domains/domains';
+export {
+ EditorSessions,
+ type EditorSessionCreateResponse,
+ type EditorSessionCreateParams,
+} from './editor-sessions';
+export {
+ Emails,
+ type EmailCreateResponse,
+ type EmailRetrieveResponse,
+ type EmailListResponse,
+ type EmailCreateParams,
+ type EmailListParams,
+} from './emails/emails';
+export { Me } from './me/me';
+export { Projects, type ProjectRetrieveResponse } from './projects/projects';
export {
Templates,
type TemplateRetrieveResponse,
@@ -9,5 +31,15 @@ export {
type TemplateRetrieveParams,
type TemplateListParams,
type TemplateListResponsesCursorPage,
-} from './templates';
+} from './templates/templates';
+export {
+ Webhooks,
+ type WebhookCreateResponse,
+ type WebhookRetrieveResponse,
+ type WebhookUpdateResponse,
+ type WebhookListResponse,
+ type WebhookDeleteResponse,
+ type WebhookCreateParams,
+ type WebhookUpdateParams,
+} from './webhooks/webhooks';
export { Workspaces, type WorkspaceRetrieveResponse, type WorkspaceListResponse } from './workspaces';
diff --git a/src/resources/me.ts b/src/resources/me.ts
new file mode 100644
index 0000000..54b12df
--- /dev/null
+++ b/src/resources/me.ts
@@ -0,0 +1,3 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export * from './me/index';
diff --git a/src/resources/me/index.ts b/src/resources/me/index.ts
new file mode 100644
index 0000000..f62121d
--- /dev/null
+++ b/src/resources/me/index.ts
@@ -0,0 +1,8 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export { Me } from './me';
+export {
+ Subscription,
+ type SubscriptionRetrieveResponse,
+ type SubscriptionRetrieveParams,
+} from './subscription';
diff --git a/src/resources/me/me.ts b/src/resources/me/me.ts
new file mode 100644
index 0000000..5a001fe
--- /dev/null
+++ b/src/resources/me/me.ts
@@ -0,0 +1,19 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as SubscriptionAPI from './subscription';
+import { Subscription, SubscriptionRetrieveParams, SubscriptionRetrieveResponse } from './subscription';
+
+export class Me extends APIResource {
+ subscription: SubscriptionAPI.Subscription = new SubscriptionAPI.Subscription(this._client);
+}
+
+Me.Subscription = Subscription;
+
+export declare namespace Me {
+ export {
+ Subscription as Subscription,
+ type SubscriptionRetrieveResponse as SubscriptionRetrieveResponse,
+ type SubscriptionRetrieveParams as SubscriptionRetrieveParams,
+ };
+}
diff --git a/src/resources/me/subscription.ts b/src/resources/me/subscription.ts
new file mode 100644
index 0000000..bac4e56
--- /dev/null
+++ b/src/resources/me/subscription.ts
@@ -0,0 +1,67 @@
+// 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 Subscription extends APIResource {
+ /**
+ * Get the current plan, feature availability, and limits for a project. Used to
+ * answer "can I do X" / "what plan do I need" questions with ground-truth data
+ * instead of guessing.
+ */
+ retrieve(
+ query: SubscriptionRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get('/v3/me/subscription', { query, ...options });
+ }
+}
+
+export interface SubscriptionRetrieveResponse {
+ data?: SubscriptionRetrieveResponse.Data;
+}
+
+export namespace SubscriptionRetrieveResponse {
+ export interface Data {
+ expiresAt?: string | null;
+
+ features?: Array;
+
+ limits?: Array;
+
+ planName?: string | null;
+
+ status?: string | null;
+ }
+
+ export namespace Data {
+ export interface Feature {
+ available?: boolean;
+
+ name?: string;
+ }
+
+ export interface Limit {
+ name?: string;
+
+ unit?: string;
+
+ value?: number;
+ }
+ }
+}
+
+export interface SubscriptionRetrieveParams {
+ /**
+ * The project ID (required for PAT auth, auto-resolved for API key auth)
+ */
+ projectId?: string;
+}
+
+export declare namespace Subscription {
+ export {
+ type SubscriptionRetrieveResponse as SubscriptionRetrieveResponse,
+ type SubscriptionRetrieveParams as SubscriptionRetrieveParams,
+ };
+}
diff --git a/src/resources/projects.ts b/src/resources/projects.ts
index 6b97668..f9985fc 100644
--- a/src/resources/projects.ts
+++ b/src/resources/projects.ts
@@ -1,57 +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 { RequestOptions } from '../internal/request-options';
-import { path } from '../internal/utils/path';
-
-export class Projects extends APIResource {
- /**
- * Get project details by ID.
- */
- retrieve(id: string, options?: RequestOptions): APIPromise {
- return this._client.get(path`/v3/projects/${id}`, options);
- }
-}
-
-export interface ProjectRetrieveResponse {
- data?: ProjectRetrieveResponse.Data;
-}
-
-export namespace ProjectRetrieveResponse {
- export interface Data {
- /**
- * The project ID.
- */
- id?: number;
-
- /**
- * When the project was created.
- */
- createdAt?: string;
-
- /**
- * The project name.
- */
- name?: string;
-
- /**
- * The project status.
- */
- status?: string;
-
- workspace?: Data.Workspace;
- }
-
- export namespace Data {
- export interface Workspace {
- id?: number;
-
- name?: string;
- }
- }
-}
-
-export declare namespace Projects {
- export { type ProjectRetrieveResponse as ProjectRetrieveResponse };
-}
+export * from './projects/index';
diff --git a/src/resources/projects/ai-credits-settings-rotate-secret.ts b/src/resources/projects/ai-credits-settings-rotate-secret.ts
new file mode 100644
index 0000000..b23ff6d
--- /dev/null
+++ b/src/resources/projects/ai-credits-settings-rotate-secret.ts
@@ -0,0 +1,31 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsSettingsRotateSecret extends APIResource {
+ /**
+ * Generates a new HMAC signing secret for the project and returns it exactly once.
+ * The previous secret stops working immediately, so update your webhook
+ * verification before rotating. Requires a webhook URL to be configured first.
+ */
+ create(id: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/v3/projects/${id}/ai-credits/settings/rotate-secret`, options);
+ }
+}
+
+export interface AICreditsSettingsRotateSecretCreateResponse {
+ /**
+ * The new HMAC signing secret. Shown only once.
+ */
+ signing_secret?: string;
+}
+
+export declare namespace AICreditsSettingsRotateSecret {
+ export { type AICreditsSettingsRotateSecretCreateResponse as AICreditsSettingsRotateSecretCreateResponse };
+}
diff --git a/src/resources/projects/ai-credits-settings.ts b/src/resources/projects/ai-credits-settings.ts
new file mode 100644
index 0000000..d6bc6ef
--- /dev/null
+++ b/src/resources/projects/ai-credits-settings.ts
@@ -0,0 +1,85 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsSettings extends APIResource {
+ /**
+ * Returns a project's AI credit exhaustion behavior, alert thresholds, and webhook
+ * endpoint. The signing secret is never returned — only whether one exists
+ * (`has_signing_secret`).
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/projects/${id}/ai-credits/settings`, options);
+ }
+
+ /**
+ * Configures AI credit exhaustion behavior, usage alert thresholds, and the
+ * webhook endpoint for a project. The HMAC signing secret is generated the first
+ * time a webhook URL is set and returned exactly once in the response — store it
+ * securely; it is never shown again.
+ */
+ update(
+ id: string,
+ body: AICreditsSettingUpdateParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.put(path`/v3/projects/${id}/ai-credits/settings`, { body, ...options });
+ }
+}
+
+export interface AICreditsSettingRetrieveResponse {
+ exhaustion_behavior?: string;
+
+ has_signing_secret?: boolean;
+
+ threshold_alerts?: Array;
+
+ webhook_url?: string | null;
+}
+
+export interface AICreditsSettingUpdateResponse {
+ exhaustion_behavior?: string;
+
+ has_signing_secret?: boolean;
+
+ /**
+ * The HMAC signing secret. Returned ONLY on the response that first generates it.
+ */
+ signing_secret?: string;
+
+ threshold_alerts?: Array;
+
+ webhook_url?: string | null;
+}
+
+export interface AICreditsSettingUpdateParams {
+ /**
+ * What the editor does when the credit balance is exhausted.
+ */
+ exhaustion_behavior?: 'disable' | 'show_error';
+
+ /**
+ * Usage percentages (1-100) at which a threshold_reached webhook fires, once per
+ * crossing per period.
+ */
+ threshold_alerts?: Array;
+
+ /**
+ * HTTPS endpoint that receives AI credit webhooks.
+ */
+ webhook_url?: string | null;
+}
+
+export declare namespace AICreditsSettings {
+ export {
+ type AICreditsSettingRetrieveResponse as AICreditsSettingRetrieveResponse,
+ type AICreditsSettingUpdateResponse as AICreditsSettingUpdateResponse,
+ type AICreditsSettingUpdateParams as AICreditsSettingUpdateParams,
+ };
+}
diff --git a/src/resources/projects/ai-credits-usage.ts b/src/resources/projects/ai-credits-usage.ts
new file mode 100644
index 0000000..77631f9
--- /dev/null
+++ b/src/resources/projects/ai-credits-usage.ts
@@ -0,0 +1,111 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsUsage extends APIResource {
+ /**
+ * Returns AI credit consumption for the project, broken down by end user and
+ * feature type. Filterable by date range, end user, and feature type. Usage is
+ * updated near real time and grouped by the UTC date when the AI activity
+ * occurred. Recent activity may take a short time to appear. Defaults to the
+ * current billing period. Only credit counts are returned; token counts, model
+ * names, and costs are never exposed. Per-end-user attribution requires the
+ * partner to pass `endUserId` on editor initialization.
+ */
+ retrieve(
+ id: string,
+ query: AICreditsUsageRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get(path`/v3/projects/${id}/ai-credits/usage`, { query, ...options });
+ }
+}
+
+export interface AICreditsUsageRetrieveResponse {
+ breakdown?: Array;
+
+ /**
+ * Number of breakdown rows matching the filter (ignores paging).
+ */
+ total?: number;
+
+ /**
+ * Total AI credits used across the full filtered range (not just the returned
+ * page).
+ */
+ total_credits_used?: number;
+}
+
+export namespace AICreditsUsageRetrieveResponse {
+ export interface Breakdown {
+ /**
+ * AI credits used by this end user and feature type.
+ */
+ credits?: number;
+
+ /**
+ * The end user id, or null for unattributed usage.
+ */
+ end_user_id?: string | null;
+
+ /**
+ * The partner-facing feature type.
+ */
+ feature_type?: 'full_template_gen' | 'block_edit' | 'html_import' | 'image_import' | 'image_generation';
+ }
+}
+
+export interface AICreditsUsageRetrieveParams {
+ /**
+ * End date (inclusive), YYYY-MM-DD.
+ */
+ end?: string;
+
+ /**
+ * Filter to a single end user id.
+ */
+ end_user_id?: string;
+
+ /**
+ * Filter to a single feature type.
+ */
+ feature_type?: 'full_template_gen' | 'block_edit' | 'html_import' | 'image_import' | 'image_generation';
+
+ /**
+ * Max breakdown rows to return (1-1000).
+ */
+ limit?: number;
+
+ /**
+ * Number of breakdown rows to skip (pagination).
+ */
+ offset?: number;
+
+ /**
+ * Sort direction. Defaults to desc (highest credits first).
+ */
+ order?: 'asc' | 'desc';
+
+ /**
+ * Field the breakdown is ordered by. Defaults to credits.
+ */
+ sort?: 'credits' | 'end_user_id' | 'feature_type';
+
+ /**
+ * Start date (inclusive), YYYY-MM-DD.
+ */
+ start?: string;
+}
+
+export declare namespace AICreditsUsage {
+ export {
+ type AICreditsUsageRetrieveResponse as AICreditsUsageRetrieveResponse,
+ type AICreditsUsageRetrieveParams as AICreditsUsageRetrieveParams,
+ };
+}
diff --git a/src/resources/projects/ai-credits-webhooks-deliveries.ts b/src/resources/projects/ai-credits-webhooks-deliveries.ts
new file mode 100644
index 0000000..7202cf1
--- /dev/null
+++ b/src/resources/projects/ai-credits-webhooks-deliveries.ts
@@ -0,0 +1,84 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsWebhooksDeliveries extends APIResource {
+ /**
+ * Returns the webhook delivery history for the project, newest first — the event,
+ * delivery status, attempt count, and last response code for each. Use it to spot
+ * failed deliveries and drive the retry endpoint. Payloads expose credits only.
+ */
+ retrieve(
+ id: string,
+ query: AICreditsWebhooksDeliveryRetrieveParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get(path`/v3/projects/${id}/ai-credits/webhooks/deliveries`, { query, ...options });
+ }
+}
+
+export interface AICreditsWebhooksDeliveryRetrieveResponse {
+ deliveries?: Array;
+
+ /**
+ * Total deliveries matching the filter (ignores limit/offset).
+ */
+ total?: number;
+}
+
+export namespace AICreditsWebhooksDeliveryRetrieveResponse {
+ export interface Delivery {
+ id?: string;
+
+ attempts?: number;
+
+ created_at?: string;
+
+ delivered_at?: string | null;
+
+ end_user_id?: string | null;
+
+ event?: string;
+
+ last_status_code?: number | null;
+
+ payload?: { [key: string]: unknown };
+
+ status?: 'pending' | 'delivered' | 'failed';
+ }
+}
+
+export interface AICreditsWebhooksDeliveryRetrieveParams {
+ /**
+ * Filter to a single event type.
+ */
+ event?: 'ai.credits.usage_recorded' | 'ai.credits.threshold_reached' | 'ai.credits.exhausted';
+
+ /**
+ * Max deliveries to return (1-100).
+ */
+ limit?: number;
+
+ /**
+ * Number of deliveries to skip (pagination).
+ */
+ offset?: number;
+
+ /**
+ * Filter to a single delivery status.
+ */
+ status?: 'pending' | 'delivered' | 'failed';
+}
+
+export declare namespace AICreditsWebhooksDeliveries {
+ export {
+ type AICreditsWebhooksDeliveryRetrieveResponse as AICreditsWebhooksDeliveryRetrieveResponse,
+ type AICreditsWebhooksDeliveryRetrieveParams as AICreditsWebhooksDeliveryRetrieveParams,
+ };
+}
diff --git a/src/resources/projects/ai-credits-webhooks-deliveriesattempts.ts b/src/resources/projects/ai-credits-webhooks-deliveriesattempts.ts
new file mode 100644
index 0000000..7605382
--- /dev/null
+++ b/src/resources/projects/ai-credits-webhooks-deliveriesattempts.ts
@@ -0,0 +1,73 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsWebhooksDeliveriesattempts extends APIResource {
+ /**
+ * Returns the per-attempt history for a single delivery, newest attempt first —
+ * the response code, error, and time of each POST (including automatic retries).
+ * Returns 404 if the delivery is not found for this project.
+ */
+ retrieve(
+ deliveryID: string,
+ params: AICreditsWebhooksDeliveriesattemptRetrieveParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { id, ...query } = params;
+ return this._client.get(path`/v3/projects/${id}/ai-credits/webhooks/deliveries/${deliveryID}/attempts`, {
+ query,
+ ...options,
+ });
+ }
+}
+
+export interface AICreditsWebhooksDeliveriesattemptRetrieveResponse {
+ attempts?: Array;
+
+ /**
+ * Total attempts for the delivery (ignores limit/offset).
+ */
+ total?: number;
+}
+
+export namespace AICreditsWebhooksDeliveriesattemptRetrieveResponse {
+ export interface Attempt {
+ attempt?: number;
+
+ attempted_at?: string;
+
+ error?: string | null;
+
+ status_code?: number | null;
+ }
+}
+
+export interface AICreditsWebhooksDeliveriesattemptRetrieveParams {
+ /**
+ * Path param: The project ID
+ */
+ id: string;
+
+ /**
+ * Query param: Max attempts to return (1-100).
+ */
+ limit?: number;
+
+ /**
+ * Query param: Number of attempts to skip (pagination).
+ */
+ offset?: number;
+}
+
+export declare namespace AICreditsWebhooksDeliveriesattempts {
+ export {
+ type AICreditsWebhooksDeliveriesattemptRetrieveResponse as AICreditsWebhooksDeliveriesattemptRetrieveResponse,
+ type AICreditsWebhooksDeliveriesattemptRetrieveParams as AICreditsWebhooksDeliveriesattemptRetrieveParams,
+ };
+}
diff --git a/src/resources/projects/ai-credits-webhooks-deliveriesretry.ts b/src/resources/projects/ai-credits-webhooks-deliveriesretry.ts
new file mode 100644
index 0000000..931522d
--- /dev/null
+++ b/src/resources/projects/ai-credits-webhooks-deliveriesretry.ts
@@ -0,0 +1,46 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICreditsWebhooksDeliveriesretry extends APIResource {
+ /**
+ * Re-queues a single previously-failed (or pending) webhook delivery for another
+ * attempt. Returns 404 if the delivery is not found for this project, and 409 if
+ * it was already delivered.
+ */
+ create(
+ deliveryID: string,
+ params: AICreditsWebhooksDeliveriesretryCreateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ const { id } = params;
+ return this._client.post(
+ path`/v3/projects/${id}/ai-credits/webhooks/deliveries/${deliveryID}/retry`,
+ options,
+ );
+ }
+}
+
+export interface AICreditsWebhooksDeliveriesretryCreateResponse {
+ status?: 'requeued';
+}
+
+export interface AICreditsWebhooksDeliveriesretryCreateParams {
+ /**
+ * The project ID
+ */
+ id: string;
+}
+
+export declare namespace AICreditsWebhooksDeliveriesretry {
+ export {
+ type AICreditsWebhooksDeliveriesretryCreateResponse as AICreditsWebhooksDeliveriesretryCreateResponse,
+ type AICreditsWebhooksDeliveriesretryCreateParams as AICreditsWebhooksDeliveriesretryCreateParams,
+ };
+}
diff --git a/src/resources/projects/ai-credits.ts b/src/resources/projects/ai-credits.ts
new file mode 100644
index 0000000..1c2d220
--- /dev/null
+++ b/src/resources/projects/ai-credits.ts
@@ -0,0 +1,47 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+/**
+ * AI credit balance, usage breakdown, and webhook/alert settings. Credits are pooled per workspace; settings are per project.
+ */
+export class AICredits extends APIResource {
+ /**
+ * Returns the current AI credit balance for the project. Credits are pooled per
+ * workspace — every project in a workspace shares one balance. Only credit counts
+ * are returned; token counts, model names, and costs are never exposed.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/projects/${id}/ai-credits`, options);
+ }
+}
+
+export interface AICreditRetrieveResponse {
+ /**
+ * AI credits remaining in the current period.
+ */
+ credits_remaining?: number;
+
+ /**
+ * Total AI credits available for the current period.
+ */
+ credits_total?: number;
+
+ /**
+ * AI credits consumed so far in the current period.
+ */
+ credits_used?: number;
+
+ /**
+ * When the current credit period resets, or null if there is no active billing
+ * period — including once a subscription is cancelled or its term has ended.
+ */
+ reset_date?: string | null;
+}
+
+export declare namespace AICredits {
+ export { type AICreditRetrieveResponse as AICreditRetrieveResponse };
+}
diff --git a/src/resources/projects/index.ts b/src/resources/projects/index.ts
new file mode 100644
index 0000000..5a8e575
--- /dev/null
+++ b/src/resources/projects/index.ts
@@ -0,0 +1,34 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export { AICredits, type AICreditRetrieveResponse } from './ai-credits';
+export {
+ AICreditsSettings,
+ type AICreditsSettingRetrieveResponse,
+ type AICreditsSettingUpdateResponse,
+ type AICreditsSettingUpdateParams,
+} from './ai-credits-settings';
+export {
+ AICreditsSettingsRotateSecret,
+ type AICreditsSettingsRotateSecretCreateResponse,
+} from './ai-credits-settings-rotate-secret';
+export {
+ AICreditsUsage,
+ type AICreditsUsageRetrieveResponse,
+ type AICreditsUsageRetrieveParams,
+} from './ai-credits-usage';
+export {
+ AICreditsWebhooksDeliveries,
+ type AICreditsWebhooksDeliveryRetrieveResponse,
+ type AICreditsWebhooksDeliveryRetrieveParams,
+} from './ai-credits-webhooks-deliveries';
+export {
+ AICreditsWebhooksDeliveriesattempts,
+ type AICreditsWebhooksDeliveriesattemptRetrieveResponse,
+ type AICreditsWebhooksDeliveriesattemptRetrieveParams,
+} from './ai-credits-webhooks-deliveriesattempts';
+export {
+ AICreditsWebhooksDeliveriesretry,
+ type AICreditsWebhooksDeliveriesretryCreateResponse,
+ type AICreditsWebhooksDeliveriesretryCreateParams,
+} from './ai-credits-webhooks-deliveriesretry';
+export { Projects, type ProjectRetrieveResponse } from './projects';
diff --git a/src/resources/projects/projects.ts b/src/resources/projects/projects.ts
new file mode 100644
index 0000000..2a5de9e
--- /dev/null
+++ b/src/resources/projects/projects.ts
@@ -0,0 +1,158 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as AICreditsAPI from './ai-credits';
+import { AICreditRetrieveResponse, AICredits } from './ai-credits';
+import * as AICreditsSettingsAPI from './ai-credits-settings';
+import {
+ AICreditsSettingRetrieveResponse,
+ AICreditsSettingUpdateParams,
+ AICreditsSettingUpdateResponse,
+ AICreditsSettings,
+} from './ai-credits-settings';
+import * as AICreditsSettingsRotateSecretAPI from './ai-credits-settings-rotate-secret';
+import {
+ AICreditsSettingsRotateSecret,
+ AICreditsSettingsRotateSecretCreateResponse,
+} from './ai-credits-settings-rotate-secret';
+import * as AICreditsUsageAPI from './ai-credits-usage';
+import {
+ AICreditsUsage,
+ AICreditsUsageRetrieveParams,
+ AICreditsUsageRetrieveResponse,
+} from './ai-credits-usage';
+import * as AICreditsWebhooksDeliveriesAPI from './ai-credits-webhooks-deliveries';
+import {
+ AICreditsWebhooksDeliveries,
+ AICreditsWebhooksDeliveryRetrieveParams,
+ AICreditsWebhooksDeliveryRetrieveResponse,
+} from './ai-credits-webhooks-deliveries';
+import * as AICreditsWebhooksDeliveriesattemptsAPI from './ai-credits-webhooks-deliveriesattempts';
+import {
+ AICreditsWebhooksDeliveriesattemptRetrieveParams,
+ AICreditsWebhooksDeliveriesattemptRetrieveResponse,
+ AICreditsWebhooksDeliveriesattempts,
+} from './ai-credits-webhooks-deliveriesattempts';
+import * as AICreditsWebhooksDeliveriesretryAPI from './ai-credits-webhooks-deliveriesretry';
+import {
+ AICreditsWebhooksDeliveriesretry,
+ AICreditsWebhooksDeliveriesretryCreateParams,
+ AICreditsWebhooksDeliveriesretryCreateResponse,
+} from './ai-credits-webhooks-deliveriesretry';
+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 {
+ aiCredits: AICreditsAPI.AICredits = new AICreditsAPI.AICredits(this._client);
+ aiCreditsSettings: AICreditsSettingsAPI.AICreditsSettings = new AICreditsSettingsAPI.AICreditsSettings(
+ this._client,
+ );
+ aiCreditsSettingsRotateSecret: AICreditsSettingsRotateSecretAPI.AICreditsSettingsRotateSecret =
+ new AICreditsSettingsRotateSecretAPI.AICreditsSettingsRotateSecret(this._client);
+ aiCreditsUsage: AICreditsUsageAPI.AICreditsUsage = new AICreditsUsageAPI.AICreditsUsage(this._client);
+ aiCreditsWebhooksDeliveries: AICreditsWebhooksDeliveriesAPI.AICreditsWebhooksDeliveries =
+ new AICreditsWebhooksDeliveriesAPI.AICreditsWebhooksDeliveries(this._client);
+ aiCreditsWebhooksDeliveriesattempts: AICreditsWebhooksDeliveriesattemptsAPI.AICreditsWebhooksDeliveriesattempts =
+ new AICreditsWebhooksDeliveriesattemptsAPI.AICreditsWebhooksDeliveriesattempts(this._client);
+ aiCreditsWebhooksDeliveriesretry: AICreditsWebhooksDeliveriesretryAPI.AICreditsWebhooksDeliveriesretry =
+ new AICreditsWebhooksDeliveriesretryAPI.AICreditsWebhooksDeliveriesretry(this._client);
+
+ /**
+ * Get project details by ID.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/projects/${id}`, options);
+ }
+}
+
+export interface ProjectRetrieveResponse {
+ data?: ProjectRetrieveResponse.Data;
+}
+
+export namespace ProjectRetrieveResponse {
+ export interface Data {
+ /**
+ * The project ID.
+ */
+ id?: number;
+
+ /**
+ * When the project was created.
+ */
+ createdAt?: string;
+
+ /**
+ * The project name.
+ */
+ name?: string;
+
+ /**
+ * The project status.
+ */
+ status?: string;
+
+ workspace?: Data.Workspace;
+ }
+
+ export namespace Data {
+ export interface Workspace {
+ id?: number;
+
+ name?: string;
+ }
+ }
+}
+
+Projects.AICredits = AICredits;
+Projects.AICreditsSettings = AICreditsSettings;
+Projects.AICreditsSettingsRotateSecret = AICreditsSettingsRotateSecret;
+Projects.AICreditsUsage = AICreditsUsage;
+Projects.AICreditsWebhooksDeliveries = AICreditsWebhooksDeliveries;
+Projects.AICreditsWebhooksDeliveriesattempts = AICreditsWebhooksDeliveriesattempts;
+Projects.AICreditsWebhooksDeliveriesretry = AICreditsWebhooksDeliveriesretry;
+
+export declare namespace Projects {
+ export { type ProjectRetrieveResponse as ProjectRetrieveResponse };
+
+ export { AICredits as AICredits, type AICreditRetrieveResponse as AICreditRetrieveResponse };
+
+ export {
+ AICreditsSettings as AICreditsSettings,
+ type AICreditsSettingRetrieveResponse as AICreditsSettingRetrieveResponse,
+ type AICreditsSettingUpdateResponse as AICreditsSettingUpdateResponse,
+ type AICreditsSettingUpdateParams as AICreditsSettingUpdateParams,
+ };
+
+ export {
+ AICreditsSettingsRotateSecret as AICreditsSettingsRotateSecret,
+ type AICreditsSettingsRotateSecretCreateResponse as AICreditsSettingsRotateSecretCreateResponse,
+ };
+
+ export {
+ AICreditsUsage as AICreditsUsage,
+ type AICreditsUsageRetrieveResponse as AICreditsUsageRetrieveResponse,
+ type AICreditsUsageRetrieveParams as AICreditsUsageRetrieveParams,
+ };
+
+ export {
+ AICreditsWebhooksDeliveries as AICreditsWebhooksDeliveries,
+ type AICreditsWebhooksDeliveryRetrieveResponse as AICreditsWebhooksDeliveryRetrieveResponse,
+ type AICreditsWebhooksDeliveryRetrieveParams as AICreditsWebhooksDeliveryRetrieveParams,
+ };
+
+ export {
+ AICreditsWebhooksDeliveriesattempts as AICreditsWebhooksDeliveriesattempts,
+ type AICreditsWebhooksDeliveriesattemptRetrieveResponse as AICreditsWebhooksDeliveriesattemptRetrieveResponse,
+ type AICreditsWebhooksDeliveriesattemptRetrieveParams as AICreditsWebhooksDeliveriesattemptRetrieveParams,
+ };
+
+ export {
+ AICreditsWebhooksDeliveriesretry as AICreditsWebhooksDeliveriesretry,
+ type AICreditsWebhooksDeliveriesretryCreateResponse as AICreditsWebhooksDeliveriesretryCreateResponse,
+ type AICreditsWebhooksDeliveriesretryCreateParams as AICreditsWebhooksDeliveriesretryCreateParams,
+ };
+}
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/templates/convert-full-to-simple.ts b/src/resources/templates/convert-full-to-simple.ts
new file mode 100644
index 0000000..e5a3c08
--- /dev/null
+++ b/src/resources/templates/convert-full-to-simple.ts
@@ -0,0 +1,71 @@
+// 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 ConvertFullToSimple extends APIResource {
+ /**
+ * Convert design json from Full to Simple schema.
+ */
+ create(
+ body: ConvertFullToSimpleCreateParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post('/v3/templates/convert/full-to-simple', { body, ...options });
+ }
+}
+
+export interface ConvertFullToSimpleCreateResponse {
+ data?: ConvertFullToSimpleCreateResponse.Data;
+
+ success?: true;
+}
+
+export namespace ConvertFullToSimpleCreateResponse {
+ export interface Data {
+ design?: { [key: string]: unknown };
+ }
+}
+
+export interface ConvertFullToSimpleCreateParams {
+ design: ConvertFullToSimpleCreateParams.Design;
+
+ /**
+ * Display mode of the design (email, web, document, popup). Defaults to "email",
+ * matching /v3/templates/validate. Mode-specific repairs apply during conversion
+ * (email caps contentWidth at 900px, for example), so pass the design's actual
+ * mode — a web design converted under the email default can be altered.
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * When true, includes \_conversion metadata in the response. This metadata can be
+ * passed to simple-to-full to restore original values without data loss.
+ */
+ includeConversion?: boolean;
+
+ includeDefaultValues?: boolean;
+}
+
+export namespace ConvertFullToSimpleCreateParams {
+ export interface Design {
+ body: { [key: string]: unknown };
+
+ counters?: { [key: string]: unknown };
+
+ schemaVersion?: number;
+
+ [k: string]: unknown;
+ }
+}
+
+export declare namespace ConvertFullToSimple {
+ export {
+ 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..0e848d5
--- /dev/null
+++ b/src/resources/templates/convert-simple-to-full.ts
@@ -0,0 +1,75 @@
+// 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;
+
+ /**
+ * Display mode of the design (email, web, document, popup). Defaults to "email",
+ * matching /v3/templates/validate. Mode-specific repairs apply during conversion
+ * (email caps contentWidth at 900px, for example), so pass the design's actual
+ * mode — a web design converted under the email default can be altered.
+ */
+ 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/export-html.ts b/src/resources/templates/export-html.ts
new file mode 100644
index 0000000..7803e53
--- /dev/null
+++ b/src/resources/templates/export-html.ts
@@ -0,0 +1,117 @@
+// 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 ExportHTML extends APIResource {
+ /**
+ * Export a design as rendered HTML.
+ */
+ create(params: ExportHTMLCreateParams, options?: RequestOptions): APIPromise {
+ const { projectId, ...body } = params;
+ return this._client.post('/v3/templates/export/html', { query: { projectId }, body, ...options });
+ }
+}
+
+export interface ExportHTMLCreateResponse {
+ data?: ExportHTMLCreateResponse.Data;
+
+ success?: boolean;
+}
+
+export namespace ExportHTMLCreateResponse {
+ export interface Data {
+ amp?: { [key: string]: unknown };
+
+ chunks?: Data.Chunks;
+
+ design?: { [key: string]: unknown };
+
+ html?: string;
+ }
+
+ export namespace Data {
+ export interface Chunks {
+ body?: string;
+
+ css?: string;
+
+ fonts?: Array;
+
+ js?: string;
+
+ tags?: Array;
+ }
+ }
+}
+
+export interface ExportHTMLCreateParams {
+ /**
+ * Body param: Unlayer design JSON
+ */
+ design: unknown;
+
+ /**
+ * Query param: The project ID (required for PAT auth, auto-resolved for API key
+ * auth)
+ */
+ projectId?: string;
+
+ /**
+ * Body param
+ */
+ customJS?: string | Array;
+
+ /**
+ * Body param
+ */
+ designTags?: unknown;
+
+ /**
+ * Body param
+ */
+ designTagsConfig?: unknown;
+
+ /**
+ * Body param
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * Body param
+ */
+ editorVersion?: string;
+
+ /**
+ * Body param
+ */
+ language?: string;
+
+ /**
+ * Body param
+ */
+ languages?: Array;
+
+ /**
+ * Body param
+ */
+ mergeTags?: unknown;
+
+ /**
+ * Body param
+ */
+ mergeTagsSchema?: unknown;
+
+ /**
+ * Body param
+ */
+ safeHtml?: boolean;
+}
+
+export declare namespace ExportHTML {
+ export {
+ type ExportHTMLCreateResponse as ExportHTMLCreateResponse,
+ type ExportHTMLCreateParams as ExportHTMLCreateParams,
+ };
+}
diff --git a/src/resources/templates/export-image.ts b/src/resources/templates/export-image.ts
new file mode 100644
index 0000000..d6b0046
--- /dev/null
+++ b/src/resources/templates/export-image.ts
@@ -0,0 +1,117 @@
+// 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 ExportImage extends APIResource {
+ /**
+ * Export a design as a PNG image.
+ */
+ create(params: ExportImageCreateParams, options?: RequestOptions): APIPromise {
+ const { projectId, ...body } = params;
+ return this._client.post('/v3/templates/export/image', { query: { projectId }, body, ...options });
+ }
+}
+
+export interface ExportImageCreateResponse {
+ data?: ExportImageCreateResponse.Data;
+
+ success?: boolean;
+}
+
+export namespace ExportImageCreateResponse {
+ export interface Data {
+ url?: string;
+ }
+}
+
+export interface ExportImageCreateParams {
+ /**
+ * Body param: Unlayer design JSON
+ */
+ design: unknown;
+
+ /**
+ * Query param: The project ID (required for PAT auth, auto-resolved for API key
+ * auth)
+ */
+ projectId?: string;
+
+ /**
+ * Body param
+ */
+ customJS?: string | Array;
+
+ /**
+ * Body param
+ */
+ designTags?: unknown;
+
+ /**
+ * Body param
+ */
+ designTagsConfig?: unknown;
+
+ /**
+ * Body param
+ */
+ deviceScaleFactor?: number;
+
+ /**
+ * Body param
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * Body param
+ */
+ editorVersion?: string;
+
+ /**
+ * Body param
+ */
+ fullPage?: boolean;
+
+ /**
+ * Body param
+ */
+ height?: number;
+
+ /**
+ * Body param
+ */
+ language?: string;
+
+ /**
+ * Body param
+ */
+ languages?: Array;
+
+ /**
+ * Body param
+ */
+ mergeTags?: unknown;
+
+ /**
+ * Body param
+ */
+ mergeTagsSchema?: unknown;
+
+ /**
+ * Body param
+ */
+ safeHtml?: boolean;
+
+ /**
+ * Body param
+ */
+ width?: number;
+}
+
+export declare namespace ExportImage {
+ export {
+ type ExportImageCreateResponse as ExportImageCreateResponse,
+ type ExportImageCreateParams as ExportImageCreateParams,
+ };
+}
diff --git a/src/resources/templates/export-pdf.ts b/src/resources/templates/export-pdf.ts
new file mode 100644
index 0000000..597d1f7
--- /dev/null
+++ b/src/resources/templates/export-pdf.ts
@@ -0,0 +1,107 @@
+// 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 ExportPdf extends APIResource {
+ /**
+ * Export a design as a PDF document.
+ */
+ create(params: ExportPdfCreateParams, options?: RequestOptions): APIPromise {
+ const { projectId, ...body } = params;
+ return this._client.post('/v3/templates/export/pdf', { query: { projectId }, body, ...options });
+ }
+}
+
+export interface ExportPdfCreateResponse {
+ data?: ExportPdfCreateResponse.Data;
+
+ success?: boolean;
+}
+
+export namespace ExportPdfCreateResponse {
+ export interface Data {
+ url?: string;
+ }
+}
+
+export interface ExportPdfCreateParams {
+ /**
+ * Body param: Unlayer design JSON
+ */
+ design: unknown;
+
+ /**
+ * Query param: The project ID (required for PAT auth, auto-resolved for API key
+ * auth)
+ */
+ projectId?: string;
+
+ /**
+ * Body param
+ */
+ contentWidth?: number | 'full';
+
+ /**
+ * Body param
+ */
+ customJS?: string | Array;
+
+ /**
+ * Body param
+ */
+ designTags?: unknown;
+
+ /**
+ * Body param
+ */
+ designTagsConfig?: unknown;
+
+ /**
+ * Body param
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * Body param
+ */
+ editorVersion?: string;
+
+ /**
+ * Body param
+ */
+ language?: string;
+
+ /**
+ * Body param
+ */
+ languages?: Array;
+
+ /**
+ * Body param
+ */
+ mergeTags?: unknown;
+
+ /**
+ * Body param
+ */
+ mergeTagsSchema?: unknown;
+
+ /**
+ * Body param
+ */
+ pageSize?: 'Letter' | 'Legal' | 'Tabloid' | 'Ledger' | 'A0' | 'A1' | 'A2' | 'A3' | 'A4' | 'A5' | 'A6';
+
+ /**
+ * Body param
+ */
+ safeHtml?: boolean;
+}
+
+export declare namespace ExportPdf {
+ export {
+ type ExportPdfCreateResponse as ExportPdfCreateResponse,
+ type ExportPdfCreateParams as ExportPdfCreateParams,
+ };
+}
diff --git a/src/resources/templates/export-zip.ts b/src/resources/templates/export-zip.ts
new file mode 100644
index 0000000..00f07a6
--- /dev/null
+++ b/src/resources/templates/export-zip.ts
@@ -0,0 +1,97 @@
+// 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 ExportZip extends APIResource {
+ /**
+ * Export a design as a ZIP archive containing HTML and assets.
+ */
+ create(params: ExportZipCreateParams, options?: RequestOptions): APIPromise {
+ const { projectId, ...body } = params;
+ return this._client.post('/v3/templates/export/zip', { query: { projectId }, body, ...options });
+ }
+}
+
+export interface ExportZipCreateResponse {
+ data?: ExportZipCreateResponse.Data;
+
+ success?: boolean;
+}
+
+export namespace ExportZipCreateResponse {
+ export interface Data {
+ url?: string;
+ }
+}
+
+export interface ExportZipCreateParams {
+ /**
+ * Body param: Unlayer design JSON
+ */
+ design: unknown;
+
+ /**
+ * Query param: The project ID (required for PAT auth, auto-resolved for API key
+ * auth)
+ */
+ projectId?: string;
+
+ /**
+ * Body param
+ */
+ customJS?: string | Array;
+
+ /**
+ * Body param
+ */
+ designTags?: unknown;
+
+ /**
+ * Body param
+ */
+ designTagsConfig?: unknown;
+
+ /**
+ * Body param
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * Body param
+ */
+ editorVersion?: string;
+
+ /**
+ * Body param
+ */
+ language?: string;
+
+ /**
+ * Body param
+ */
+ languages?: Array;
+
+ /**
+ * Body param
+ */
+ mergeTags?: unknown;
+
+ /**
+ * Body param
+ */
+ mergeTagsSchema?: unknown;
+
+ /**
+ * Body param
+ */
+ safeHtml?: boolean;
+}
+
+export declare namespace ExportZip {
+ export {
+ type ExportZipCreateResponse as ExportZipCreateResponse,
+ type ExportZipCreateParams as ExportZipCreateParams,
+ };
+}
diff --git a/src/resources/templates/generate.ts b/src/resources/templates/generate.ts
new file mode 100644
index 0000000..d835af5
--- /dev/null
+++ b/src/resources/templates/generate.ts
@@ -0,0 +1,311 @@
+// 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 and billed AI credits for the turn. Estimated provider
+ * cost is included only by builder copilot endpoints in local/dev/QA.
+ */
+ 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-5".
+ */
+ 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 and billed AI credits for the turn. Estimated provider
+ * cost is included only by builder copilot endpoints in local/dev/QA.
+ */
+ export interface Usage {
+ /**
+ * Marked-up integer AI credits used by the complete turn, including failover
+ * attempts.
+ */
+ aiCreditsUsed?: number;
+
+ 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; the newest earlier
+ * `user`/`assistant` turns are forwarded within a 12,000-character aggregate
+ * history budget. 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: Transient-outage fallback controls. Omit to use Unlayer defaults
+ * only when no model is pinned; true always uses Unlayer defaults; false disables
+ * the outage tail; an ordered array replaces the default provider/model strings.
+ */
+ fallbackModels?: boolean | Array;
+
+ /**
+ * Body param: BCP-47 fallback locale for AI status messages.
+ */
+ locale?: string;
+
+ /**
+ * Body param: Preferred AI model in "provider/id" form, e.g.
+ * "anthropic/claude-opus-5". 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 {
+ availableFonts?: Array;
+
+ availableTools?: Array;
+
+ brand?: Context.Brand | null;
+
+ customTools?: Array;
+
+ fullDesign?: { [key: string]: unknown } | null;
+
+ selection?: Context.Selection | null;
+
+ [k: string]: unknown;
+ }
+
+ export namespace Context {
+ export interface AvailableFont {
+ label: string;
+
+ value: string;
+ }
+
+ export interface Brand {
+ colors?: Brand.Colors;
+
+ companyName?: string;
+
+ fonts?: Brand.Fonts;
+
+ guidelines?: string;
+
+ logos?: Brand.Logos;
+
+ productDescription?: string;
+
+ targetAudience?: string;
+
+ voice?: string;
+ }
+
+ export namespace Brand {
+ export interface Colors {
+ accent?: string;
+
+ primary?: string;
+
+ secondary?: string;
+ }
+
+ export interface Fonts {
+ body?: string;
+
+ heading?: string;
+ }
+
+ export interface Logos {
+ primary?: string;
+
+ secondary?: string;
+ }
+ }
+
+ 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..dbffd65
--- /dev/null
+++ b/src/resources/templates/import.ts
@@ -0,0 +1,128 @@
+// 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: Transient-outage fallback controls. Omit to use Unlayer defaults
+ * only when no model is pinned; true always uses Unlayer defaults; false disables
+ * the outage tail; an ordered array replaces the default provider/model strings.
+ */
+ fallbackModels?: boolean | Array;
+
+ /**
+ * Body param: Preferred AI model. Accepts a provider/model string (e.g.
+ * "anthropic/claude-opus-5", "openai/gpt-5.6-luna"), a bare provider ("anthropic",
+ * "openai") which uses that provider's default model, or a bare model id
+ * ("claude-opus-5", "gpt-5.6-luna") with the provider inferred from the name.
+ * Optional — defaults to anthropic/claude-opus-5.
+ */
+ 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..62ba98f
--- /dev/null
+++ b/src/resources/templates/index.ts
@@ -0,0 +1,28 @@
+// 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 { ExportHTML, type ExportHTMLCreateResponse, type ExportHTMLCreateParams } from './export-html';
+export { ExportImage, type ExportImageCreateResponse, type ExportImageCreateParams } from './export-image';
+export { ExportPdf, type ExportPdfCreateResponse, type ExportPdfCreateParams } from './export-pdf';
+export { ExportZip, type ExportZipCreateResponse, type ExportZipCreateParams } from './export-zip';
+export { Generate, type GenerateCreateResponse, type GenerateCreateParams } from './generate';
+export { Import, type ImportCreateResponse, type ImportCreateParams } from './import';
+export { Schema, type SchemaRetrieveParams } from './schema';
+export {
+ Templates,
+ type TemplateRetrieveResponse,
+ type TemplateListResponse,
+ type TemplateRetrieveParams,
+ type TemplateListParams,
+ type TemplateListResponsesCursorPage,
+} from './templates';
+export { Validate, type ValidateCreateResponse, type ValidateCreateParams } from './validate';
diff --git a/src/resources/templates/schema.ts b/src/resources/templates/schema.ts
new file mode 100644
index 0000000..d6d4bce
--- /dev/null
+++ b/src/resources/templates/schema.ts
@@ -0,0 +1,44 @@
+// 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';
+
+/**
+ * Template management — list, retrieve, generate, import, export, and convert designs.
+ */
+export class Schema extends APIResource {
+ /**
+ * Returns the canonical design schema as a standard JSON Schema document — the
+ * exact schema POST /v3/templates/validate checks against, ready to plug into any
+ * JSON Schema validator or editor tooling. Serves the Full schema by default; pass
+ * simple=true for the compact Simple schema. No authentication required. Responses
+ * carry a strong ETag and long-lived cache headers; send If-None-Match to
+ * revalidate for free.
+ */
+ retrieve(query: SchemaRetrieveParams | null | undefined = {}, options?: RequestOptions): APIPromise {
+ return this._client.get('/v3/templates/schema', {
+ query,
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+}
+
+export interface SchemaRetrieveParams {
+ /**
+ * Display mode whose rules the schema describes (email, web, document, popup).
+ * Defaults to "email".
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * When true, returns the Simple schema instead of the Full schema.
+ */
+ simple?: boolean;
+}
+
+export declare namespace Schema {
+ export { type SchemaRetrieveParams as SchemaRetrieveParams };
+}
diff --git a/src/resources/templates/templates.ts b/src/resources/templates/templates.ts
new file mode 100644
index 0000000..45f8f0f
--- /dev/null
+++ b/src/resources/templates/templates.ts
@@ -0,0 +1,221 @@
+// 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 ExportHTMLAPI from './export-html';
+import { ExportHTML, ExportHTMLCreateParams, ExportHTMLCreateResponse } from './export-html';
+import * as ExportImageAPI from './export-image';
+import { ExportImage, ExportImageCreateParams, ExportImageCreateResponse } from './export-image';
+import * as ExportPdfAPI from './export-pdf';
+import { ExportPdf, ExportPdfCreateParams, ExportPdfCreateResponse } from './export-pdf';
+import * as ExportZipAPI from './export-zip';
+import { ExportZip, ExportZipCreateParams, ExportZipCreateResponse } from './export-zip';
+import * as GenerateAPI from './generate';
+import { Generate, GenerateCreateParams, GenerateCreateResponse } from './generate';
+import * as ImportAPI from './import';
+import { Import, ImportCreateParams, ImportCreateResponse } from './import';
+import * as SchemaAPI from './schema';
+import { Schema, SchemaRetrieveParams } from './schema';
+import * as ValidateAPI from './validate';
+import { Validate, ValidateCreateParams, ValidateCreateResponse } from './validate';
+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);
+ exportHTML: ExportHTMLAPI.ExportHTML = new ExportHTMLAPI.ExportHTML(this._client);
+ exportImage: ExportImageAPI.ExportImage = new ExportImageAPI.ExportImage(this._client);
+ exportPdf: ExportPdfAPI.ExportPdf = new ExportPdfAPI.ExportPdf(this._client);
+ exportZip: ExportZipAPI.ExportZip = new ExportZipAPI.ExportZip(this._client);
+ generate: GenerateAPI.Generate = new GenerateAPI.Generate(this._client);
+ import: ImportAPI.Import = new ImportAPI.Import(this._client);
+ schema: SchemaAPI.Schema = new SchemaAPI.Schema(this._client);
+ validate: ValidateAPI.Validate = new ValidateAPI.Validate(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.ExportHTML = ExportHTML;
+Templates.ExportImage = ExportImage;
+Templates.ExportPdf = ExportPdf;
+Templates.ExportZip = ExportZip;
+Templates.Generate = Generate;
+Templates.Import = Import;
+Templates.Schema = Schema;
+Templates.Validate = Validate;
+
+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 {
+ ExportHTML as ExportHTML,
+ type ExportHTMLCreateResponse as ExportHTMLCreateResponse,
+ type ExportHTMLCreateParams as ExportHTMLCreateParams,
+ };
+
+ export {
+ ExportImage as ExportImage,
+ type ExportImageCreateResponse as ExportImageCreateResponse,
+ type ExportImageCreateParams as ExportImageCreateParams,
+ };
+
+ export {
+ ExportPdf as ExportPdf,
+ type ExportPdfCreateResponse as ExportPdfCreateResponse,
+ type ExportPdfCreateParams as ExportPdfCreateParams,
+ };
+
+ export {
+ ExportZip as ExportZip,
+ type ExportZipCreateResponse as ExportZipCreateResponse,
+ type ExportZipCreateParams as ExportZipCreateParams,
+ };
+
+ export {
+ Generate as Generate,
+ type GenerateCreateResponse as GenerateCreateResponse,
+ type GenerateCreateParams as GenerateCreateParams,
+ };
+
+ export {
+ Import as Import,
+ type ImportCreateResponse as ImportCreateResponse,
+ type ImportCreateParams as ImportCreateParams,
+ };
+
+ export { Schema as Schema, type SchemaRetrieveParams as SchemaRetrieveParams };
+
+ export {
+ Validate as Validate,
+ type ValidateCreateResponse as ValidateCreateResponse,
+ type ValidateCreateParams as ValidateCreateParams,
+ };
+}
diff --git a/src/resources/templates/validate.ts b/src/resources/templates/validate.ts
new file mode 100644
index 0000000..66832dc
--- /dev/null
+++ b/src/resources/templates/validate.ts
@@ -0,0 +1,132 @@
+// 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 Validate extends APIResource {
+ /**
+ * Validate a design JSON against the Unlayer design schema. Returns { success:
+ * true, data: { valid: true } } when the payload conforms; otherwise data is {
+ * valid: false, errors: [...] } with descriptive issues. Every checked design gets
+ * HTTP 200 — `data.valid` is the source of truth, not the status code. Only
+ * malformed requests (e.g. a missing design field or an unknown displayMode) fail
+ * request validation with 400 VALIDATION_ERROR.
+ */
+ create(body: ValidateCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/v3/templates/validate', { body, ...options });
+ }
+}
+
+export interface ValidateCreateResponse {
+ data: ValidateCreateResponse.Data;
+
+ success: true;
+}
+
+export namespace ValidateCreateResponse {
+ export interface Data {
+ valid: boolean;
+
+ /**
+ * Total number of issues found; greater than errors.length when the list was
+ * capped.
+ */
+ errorCount?: number;
+
+ /**
+ * Populated when valid is false, capped at 100 entries. Each issue carries the
+ * dotted path to the offending field, a human-readable message, and the underlying
+ * Zod issue code.
+ */
+ errors?: Array;
+
+ /**
+ * Present when the design was upgraded from an older schemaVersion before
+ * validation; carries the original version number.
+ */
+ migratedFrom?: number;
+ }
+
+ export namespace Data {
+ export interface Error {
+ code: string;
+
+ message: string;
+
+ path: string;
+ }
+ }
+}
+
+export interface ValidateCreateParams {
+ /**
+ * The design JSON to validate.
+ */
+ design: { [key: string]: unknown };
+
+ /**
+ * Custom tool declarations, in the same shape passed to unlayer.registerTool. When
+ * provided, blocks matching a declared tool have their values checked against the
+ * tool's declared options (wrong types are reported at their exact path). Blocks
+ * of undeclared tools keep envelope-only validation.
+ */
+ customTools?: Array;
+
+ /**
+ * Display mode for the design (email, web, document, popup). Some validation rules
+ * differ per mode. Defaults to "email" — without a default, options from every
+ * mode would apply at once, the strictest possible check, and real editor-saved
+ * designs could be reported invalid.
+ */
+ displayMode?: 'email' | 'web' | 'popup' | 'document';
+
+ /**
+ * When true (default), a full-form design with an older schemaVersion is upgraded
+ * to the current schema before validating — matching how the editor and the
+ * convert endpoints treat stored designs. Designs without a schemaVersion predate
+ * versioning and are fully migrated the same way. Set to false to check strict
+ * conformance with the current schema version. Designs with a newer schemaVersion
+ * than this API knows are validated as-if-current.
+ */
+ migrate?: boolean;
+
+ /**
+ * Which form of the schema to validate against. Defaults to "full".
+ */
+ schema?: 'full' | 'simple';
+}
+
+export namespace ValidateCreateParams {
+ export interface CustomTool {
+ options: { [key: string]: CustomTool.Options };
+
+ slug: string;
+
+ label?: string;
+
+ supportedDisplayModes?: Array<'email' | 'web' | 'popup' | 'document'>;
+
+ type?: string;
+
+ values?: { [key: string]: unknown };
+
+ [k: string]: unknown;
+ }
+
+ export namespace CustomTool {
+ export interface Options {
+ options?: unknown;
+ }
+ }
+}
+
+export declare namespace Validate {
+ export {
+ type ValidateCreateResponse as ValidateCreateResponse,
+ type ValidateCreateParams as ValidateCreateParams,
+ };
+}
diff --git a/src/resources/webhooks.ts b/src/resources/webhooks.ts
new file mode 100644
index 0000000..8aad965
--- /dev/null
+++ b/src/resources/webhooks.ts
@@ -0,0 +1,3 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export * from './webhooks/index';
diff --git a/src/resources/webhooks/index.ts b/src/resources/webhooks/index.ts
new file mode 100644
index 0000000..cb1800e
--- /dev/null
+++ b/src/resources/webhooks/index.ts
@@ -0,0 +1,13 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export { RotateSecret, type RotateSecretCreateResponse } from './rotate-secret';
+export {
+ Webhooks,
+ type WebhookCreateResponse,
+ type WebhookRetrieveResponse,
+ type WebhookUpdateResponse,
+ type WebhookListResponse,
+ type WebhookDeleteResponse,
+ type WebhookCreateParams,
+ type WebhookUpdateParams,
+} from './webhooks';
diff --git a/src/resources/webhooks/rotate-secret.ts b/src/resources/webhooks/rotate-secret.ts
new file mode 100644
index 0000000..f8342ff
--- /dev/null
+++ b/src/resources/webhooks/rotate-secret.ts
@@ -0,0 +1,37 @@
+// 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';
+import { path } from '../../internal/utils/path';
+
+export class RotateSecret extends APIResource {
+ /**
+ * Generate a new signing secret for a webhook. The new secret is returned once —
+ * store it securely. The old secret is invalidated immediately.
+ */
+ create(id: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/v3/webhooks/${id}/rotate-secret`, options);
+ }
+}
+
+export interface RotateSecretCreateResponse {
+ data: RotateSecretCreateResponse.Data;
+}
+
+export namespace RotateSecretCreateResponse {
+ export interface Data {
+ id?: number;
+
+ /**
+ * New signing secret — only returned once. Store it securely.
+ */
+ secret?: string;
+
+ updatedAt?: string;
+ }
+}
+
+export declare namespace RotateSecret {
+ export { type RotateSecretCreateResponse as RotateSecretCreateResponse };
+}
diff --git a/src/resources/webhooks/webhooks.ts b/src/resources/webhooks/webhooks.ts
new file mode 100644
index 0000000..87b2e95
--- /dev/null
+++ b/src/resources/webhooks/webhooks.ts
@@ -0,0 +1,255 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as RotateSecretAPI from './rotate-secret';
+import { RotateSecret, RotateSecretCreateResponse } from './rotate-secret';
+import { APIPromise } from '../../core/api-promise';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Webhooks extends APIResource {
+ rotateSecret: RotateSecretAPI.RotateSecret = new RotateSecretAPI.RotateSecret(this._client);
+
+ /**
+ * Create a new webhook endpoint. A signing secret is auto-generated and returned
+ * once. Use it to verify webhook signatures.
+ */
+ create(body: WebhookCreateParams, options?: RequestOptions): APIPromise {
+ return this._client.post('/v3/webhooks', { body, ...options });
+ }
+
+ /**
+ * Get details of a specific webhook endpoint.
+ */
+ retrieve(id: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/v3/webhooks/${id}`, options);
+ }
+
+ /**
+ * Update a webhook endpoint URL, events, or active status.
+ */
+ update(
+ id: string,
+ body: WebhookUpdateParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.patch(path`/v3/webhooks/${id}`, { body, ...options });
+ }
+
+ /**
+ * List all webhook endpoints configured for a project.
+ */
+ list(options?: RequestOptions): APIPromise {
+ return this._client.get('/v3/webhooks', options);
+ }
+
+ /**
+ * Delete a webhook endpoint. It will no longer receive events.
+ */
+ delete(id: string, options?: RequestOptions): APIPromise {
+ return this._client.delete(path`/v3/webhooks/${id}`, options);
+ }
+}
+
+export interface WebhookCreateResponse {
+ data: WebhookCreateResponse.Data;
+}
+
+export namespace WebhookCreateResponse {
+ export interface Data {
+ /**
+ * Webhook ID
+ */
+ id?: number;
+
+ /**
+ * Whether the webhook is actively receiving events
+ */
+ active?: boolean;
+
+ /**
+ * When the webhook was created
+ */
+ createdAt?: string;
+
+ /**
+ * Event types this webhook is subscribed to
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+
+ /**
+ * Signing secret — only returned on creation. Store it securely; you will not be
+ * able to retrieve it again.
+ */
+ secret?: string;
+
+ /**
+ * The HTTPS URL receiving webhook events
+ */
+ url?: string;
+ }
+}
+
+export interface WebhookRetrieveResponse {
+ data: WebhookRetrieveResponse.Data;
+}
+
+export namespace WebhookRetrieveResponse {
+ export interface Data {
+ /**
+ * Webhook ID
+ */
+ id?: number;
+
+ /**
+ * Whether the webhook is actively receiving events
+ */
+ active?: boolean;
+
+ /**
+ * When the webhook was created
+ */
+ createdAt?: string;
+
+ /**
+ * Event types this webhook is subscribed to
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+
+ /**
+ * When the webhook was last updated
+ */
+ updatedAt?: string;
+
+ /**
+ * The HTTPS URL receiving webhook events
+ */
+ url?: string;
+ }
+}
+
+export interface WebhookUpdateResponse {
+ data: WebhookUpdateResponse.Data;
+}
+
+export namespace WebhookUpdateResponse {
+ export interface Data {
+ /**
+ * Webhook ID
+ */
+ id?: number;
+
+ /**
+ * Whether the webhook is actively receiving events
+ */
+ active?: boolean;
+
+ /**
+ * Event types this webhook is subscribed to
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+
+ /**
+ * When the webhook was last updated
+ */
+ updatedAt?: string;
+
+ /**
+ * The HTTPS URL receiving webhook events
+ */
+ url?: string;
+ }
+}
+
+export interface WebhookListResponse {
+ data: Array;
+}
+
+export namespace WebhookListResponse {
+ export interface Data {
+ /**
+ * Webhook ID
+ */
+ id?: number;
+
+ /**
+ * Whether the webhook is actively receiving events
+ */
+ active?: boolean;
+
+ /**
+ * When the webhook was created
+ */
+ createdAt?: string;
+
+ /**
+ * Event types this webhook is subscribed to
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+
+ /**
+ * The HTTPS URL receiving webhook events
+ */
+ url?: string;
+ }
+}
+
+export interface WebhookDeleteResponse {
+ data?: WebhookDeleteResponse.Data;
+}
+
+export namespace WebhookDeleteResponse {
+ export interface Data {
+ success?: boolean;
+ }
+}
+
+export interface WebhookCreateParams {
+ /**
+ * The HTTPS URL to receive webhook events
+ */
+ url: string;
+
+ /**
+ * Whether the webhook is active
+ */
+ active?: boolean;
+
+ /**
+ * Event types to subscribe to. If omitted or empty, all events are sent.
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+}
+
+export interface WebhookUpdateParams {
+ /**
+ * Whether the webhook is actively receiving events
+ */
+ active?: boolean;
+
+ /**
+ * Event types to subscribe to. If omitted or empty, all events are sent.
+ */
+ events?: Array<'email.sent' | 'email.delivered' | 'email.bounced' | 'email.complained'>;
+
+ /**
+ * The HTTPS URL to receive webhook events
+ */
+ url?: string;
+}
+
+Webhooks.RotateSecret = RotateSecret;
+
+export declare namespace Webhooks {
+ export {
+ type WebhookCreateResponse as WebhookCreateResponse,
+ type WebhookRetrieveResponse as WebhookRetrieveResponse,
+ type WebhookUpdateResponse as WebhookUpdateResponse,
+ type WebhookListResponse as WebhookListResponse,
+ type WebhookDeleteResponse as WebhookDeleteResponse,
+ type WebhookCreateParams as WebhookCreateParams,
+ type WebhookUpdateParams as WebhookUpdateParams,
+ };
+
+ export { RotateSecret as RotateSecret, type RotateSecretCreateResponse as RotateSecretCreateResponse };
+}
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/tests/api-resources/blocks.test.ts b/tests/api-resources/blocks.test.ts
new file mode 100644
index 0000000..6520e67
--- /dev/null
+++ b/tests/api-resources/blocks.test.ts
@@ -0,0 +1,40 @@
+// 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 blocks', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.blocks.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);
+ });
+
+ test('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.blocks.retrieve(
+ {
+ category: 'category',
+ cursor: 'cursor',
+ displayMode: 'email',
+ includeData: true,
+ limit: 1,
+ projectId: 'projectId',
+ scope: 'all',
+ userId: 'userId',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/domains/domains.test.ts b/tests/api-resources/domains/domains.test.ts
new file mode 100644
index 0000000..c12a1c0
--- /dev/null
+++ b/tests/api-resources/domains/domains.test.ts
@@ -0,0 +1,58 @@
+// 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 domains', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.domains.create({ domain: 'domain' });
+ 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.domains.create({ domain: 'domain' });
+ });
+
+ test('retrieve', async () => {
+ const responsePromise = client.domains.retrieve('id');
+ 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('list', async () => {
+ const responsePromise = client.domains.list();
+ 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('delete', async () => {
+ const responsePromise = client.domains.delete('id');
+ 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/domains/verify.test.ts b/tests/api-resources/domains/verify.test.ts
new file mode 100644
index 0000000..c42c251
--- /dev/null
+++ b/tests/api-resources/domains/verify.test.ts
@@ -0,0 +1,21 @@
+// 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 verify', () => {
+ test('create', async () => {
+ const responsePromise = client.domains.verify.create('id');
+ 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/editor-sessions.test.ts b/tests/api-resources/editor-sessions.test.ts
new file mode 100644
index 0000000..aaea1a4
--- /dev/null
+++ b/tests/api-resources/editor-sessions.test.ts
@@ -0,0 +1,29 @@
+// 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 editorSessions', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.editorSessions.create({ design: { foo: 'bar' } });
+ 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.editorSessions.create({
+ design: { foo: 'bar' },
+ projectId: 'projectId',
+ displayMode: 'email',
+ });
+ });
+});
diff --git a/tests/api-resources/emails/emails.test.ts b/tests/api-resources/emails/emails.test.ts
new file mode 100644
index 0000000..cc81582
--- /dev/null
+++ b/tests/api-resources/emails/emails.test.ts
@@ -0,0 +1,90 @@
+// 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 emails', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.emails.create({
+ from: 'from',
+ html: 'html',
+ subject: 'subject',
+ to: ['dev@stainless.com'],
+ });
+ 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.emails.create({
+ from: 'from',
+ html: 'html',
+ subject: 'subject',
+ to: ['dev@stainless.com'],
+ attachments: [
+ {
+ content: 'content',
+ contentType: 'application/pdf',
+ filename: 'filename',
+ },
+ ],
+ bcc: [],
+ cc: [],
+ headers: { foo: 'J!Q0Ok0bzJb7' },
+ replyTo: 'dev@stainless.com',
+ tags: { foo: '_1' },
+ text: 'text',
+ 'idempotency-key': 'idempotency-key',
+ });
+ });
+
+ test('retrieve', async () => {
+ const responsePromise = client.emails.retrieve('id');
+ 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('list', async () => {
+ const responsePromise = client.emails.list();
+ 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('list: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.emails.list(
+ {
+ cursor: 'cursor',
+ from: '2019-12-27',
+ limit: 1,
+ projectId: 'projectId',
+ search: 'search',
+ status: 'queued',
+ tag: 'tag',
+ to: '2019-12-27',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/emails/events.test.ts b/tests/api-resources/emails/events.test.ts
new file mode 100644
index 0000000..43c7b86
--- /dev/null
+++ b/tests/api-resources/emails/events.test.ts
@@ -0,0 +1,21 @@
+// 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 events', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.emails.events.retrieve('id');
+ 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/emails/render.test.ts b/tests/api-resources/emails/render.test.ts
new file mode 100644
index 0000000..0cbf3fe
--- /dev/null
+++ b/tests/api-resources/emails/render.test.ts
@@ -0,0 +1,28 @@
+// 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 render', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.emails.render.create({ templateId: '496' });
+ 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.emails.render.create({
+ templateId: '496',
+ variables: { foo: 'string' },
+ });
+ });
+});
diff --git a/tests/api-resources/emails/settings.test.ts b/tests/api-resources/emails/settings.test.ts
new file mode 100644
index 0000000..dade53f
--- /dev/null
+++ b/tests/api-resources/emails/settings.test.ts
@@ -0,0 +1,42 @@
+// 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 settings', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.emails.settings.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);
+ });
+
+ test('update', async () => {
+ const responsePromise = client.emails.settings.update();
+ 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('update: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.emails.settings.update(
+ { defaultFromName: 'defaultFromName' },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/emails/stats.test.ts b/tests/api-resources/emails/stats.test.ts
new file mode 100644
index 0000000..8b6d7ab
--- /dev/null
+++ b/tests/api-resources/emails/stats.test.ts
@@ -0,0 +1,35 @@
+// 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 stats', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.emails.stats.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);
+ });
+
+ test('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.emails.stats.retrieve(
+ {
+ groupBy: 'day',
+ period: '7d',
+ projectId: 'projectId',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/emails/suppressions-check.test.ts b/tests/api-resources/emails/suppressions-check.test.ts
new file mode 100644
index 0000000..26871b3
--- /dev/null
+++ b/tests/api-resources/emails/suppressions-check.test.ts
@@ -0,0 +1,28 @@
+// 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 suppressionsCheck', () => {
+ test('retrieve: only required params', async () => {
+ const responsePromise = client.emails.suppressionsCheck.retrieve({ email: 'email' });
+ 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('retrieve: required and optional params', async () => {
+ const response = await client.emails.suppressionsCheck.retrieve({
+ email: 'email',
+ projectId: 'projectId',
+ });
+ });
+});
diff --git a/tests/api-resources/emails/suppressions.test.ts b/tests/api-resources/emails/suppressions.test.ts
new file mode 100644
index 0000000..c3f8f9c
--- /dev/null
+++ b/tests/api-resources/emails/suppressions.test.ts
@@ -0,0 +1,65 @@
+// 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 suppressions', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.emails.suppressions.create({ email: 'dev@stainless.com' });
+ 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.emails.suppressions.create({ email: 'dev@stainless.com' });
+ });
+
+ test('retrieve', async () => {
+ const responsePromise = client.emails.suppressions.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);
+ });
+
+ test('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.emails.suppressions.retrieve(
+ {
+ cursor: 'cursor',
+ limit: 1,
+ projectId: 'projectId',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+
+ test('delete: only required params', async () => {
+ const responsePromise = client.emails.suppressions.delete({ email: 'email' });
+ 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('delete: required and optional params', async () => {
+ const response = await client.emails.suppressions.delete({ email: 'email', projectId: 'projectId' });
+ });
+});
diff --git a/tests/api-resources/emails/template.test.ts b/tests/api-resources/emails/template.test.ts
new file mode 100644
index 0000000..2558da4
--- /dev/null
+++ b/tests/api-resources/emails/template.test.ts
@@ -0,0 +1,49 @@
+// 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 template', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.emails.template.create({
+ from: 'from',
+ templateId: '496',
+ to: ['dev@stainless.com'],
+ });
+ 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.emails.template.create({
+ from: 'from',
+ templateId: '496',
+ to: ['dev@stainless.com'],
+ attachments: [
+ {
+ content: 'content',
+ contentType: 'application/pdf',
+ filename: 'filename',
+ },
+ ],
+ bcc: [],
+ cc: [],
+ headers: { foo: 'J!Q0Ok0bzJb7' },
+ replyTo: 'dev@stainless.com',
+ subject: 'subject',
+ tags: { foo: '_1' },
+ text: 'text',
+ variables: { foo: 'string' },
+ 'idempotency-key': 'idempotency-key',
+ });
+ });
+});
diff --git a/tests/api-resources/me/subscription.test.ts b/tests/api-resources/me/subscription.test.ts
new file mode 100644
index 0000000..6898f7c
--- /dev/null
+++ b/tests/api-resources/me/subscription.test.ts
@@ -0,0 +1,28 @@
+// 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 subscription', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.me.subscription.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);
+ });
+
+ test('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.me.subscription.retrieve({ projectId: 'projectId' }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits-settings-rotate-secret.test.ts b/tests/api-resources/projects/ai-credits-settings-rotate-secret.test.ts
new file mode 100644
index 0000000..bff10b9
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-settings-rotate-secret.test.ts
@@ -0,0 +1,21 @@
+// 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 aiCreditsSettingsRotateSecret', () => {
+ test('create', async () => {
+ const responsePromise = client.projects.aiCreditsSettingsRotateSecret.create('id');
+ 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/projects/ai-credits-settings.test.ts b/tests/api-resources/projects/ai-credits-settings.test.ts
new file mode 100644
index 0000000..a23a269
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-settings.test.ts
@@ -0,0 +1,47 @@
+// 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 aiCreditsSettings', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.projects.aiCreditsSettings.retrieve('id');
+ 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('update', async () => {
+ const responsePromise = client.projects.aiCreditsSettings.update('id');
+ 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('update: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.projects.aiCreditsSettings.update(
+ 'id',
+ {
+ exhaustion_behavior: 'disable',
+ threshold_alerts: [1],
+ webhook_url: 'https://example.com',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits-usage.test.ts b/tests/api-resources/projects/ai-credits-usage.test.ts
new file mode 100644
index 0000000..58cde36
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-usage.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 aiCreditsUsage', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.projects.aiCreditsUsage.retrieve('id');
+ 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('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.projects.aiCreditsUsage.retrieve(
+ 'id',
+ {
+ end: '7321-69-10',
+ end_user_id: 'end_user_id',
+ feature_type: 'full_template_gen',
+ limit: 1,
+ offset: 0,
+ order: 'asc',
+ sort: 'credits',
+ start: '7321-69-10',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits-webhooks-deliveries.test.ts b/tests/api-resources/projects/ai-credits-webhooks-deliveries.test.ts
new file mode 100644
index 0000000..17178f1
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-webhooks-deliveries.test.ts
@@ -0,0 +1,37 @@
+// 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 aiCreditsWebhooksDeliveries', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.projects.aiCreditsWebhooksDeliveries.retrieve('id');
+ 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('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.projects.aiCreditsWebhooksDeliveries.retrieve(
+ 'id',
+ {
+ event: 'ai.credits.usage_recorded',
+ limit: 1,
+ offset: 0,
+ status: 'pending',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits-webhooks-deliveriesattempts.test.ts b/tests/api-resources/projects/ai-credits-webhooks-deliveriesattempts.test.ts
new file mode 100644
index 0000000..bacd5f8
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-webhooks-deliveriesattempts.test.ts
@@ -0,0 +1,31 @@
+// 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 aiCreditsWebhooksDeliveriesattempts', () => {
+ test('retrieve: only required params', async () => {
+ const responsePromise = client.projects.aiCreditsWebhooksDeliveriesattempts.retrieve('deliveryId', {
+ id: 'id',
+ });
+ 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('retrieve: required and optional params', async () => {
+ const response = await client.projects.aiCreditsWebhooksDeliveriesattempts.retrieve('deliveryId', {
+ id: 'id',
+ limit: 1,
+ offset: 0,
+ });
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits-webhooks-deliveriesretry.test.ts b/tests/api-resources/projects/ai-credits-webhooks-deliveriesretry.test.ts
new file mode 100644
index 0000000..2c1e805
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits-webhooks-deliveriesretry.test.ts
@@ -0,0 +1,29 @@
+// 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 aiCreditsWebhooksDeliveriesretry', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.projects.aiCreditsWebhooksDeliveriesretry.create('deliveryId', {
+ id: 'id',
+ });
+ 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.projects.aiCreditsWebhooksDeliveriesretry.create('deliveryId', {
+ id: 'id',
+ });
+ });
+});
diff --git a/tests/api-resources/projects/ai-credits.test.ts b/tests/api-resources/projects/ai-credits.test.ts
new file mode 100644
index 0000000..377cc15
--- /dev/null
+++ b/tests/api-resources/projects/ai-credits.test.ts
@@ -0,0 +1,21 @@
+// 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 aiCredits', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.projects.aiCredits.retrieve('id');
+ 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/projects.test.ts b/tests/api-resources/projects/projects.test.ts
similarity index 100%
rename from tests/api-resources/projects.test.ts
rename to tests/api-resources/projects/projects.test.ts
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/export-html.test.ts b/tests/api-resources/templates/export-html.test.ts
new file mode 100644
index 0000000..f12a201
--- /dev/null
+++ b/tests/api-resources/templates/export-html.test.ts
@@ -0,0 +1,38 @@
+// 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 exportHTML', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.templates.exportHTML.create({ design: {} });
+ 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.exportHTML.create({
+ design: {},
+ projectId: 'projectId',
+ customJS: 'string',
+ designTags: {},
+ designTagsConfig: {},
+ displayMode: 'email',
+ editorVersion: 'editorVersion',
+ language: 'language',
+ languages: ['string'],
+ mergeTags: {},
+ mergeTagsSchema: {},
+ safeHtml: true,
+ });
+ });
+});
diff --git a/tests/api-resources/templates/export-image.test.ts b/tests/api-resources/templates/export-image.test.ts
new file mode 100644
index 0000000..69dbd4d
--- /dev/null
+++ b/tests/api-resources/templates/export-image.test.ts
@@ -0,0 +1,42 @@
+// 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 exportImage', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.templates.exportImage.create({ design: {} });
+ 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.exportImage.create({
+ design: {},
+ projectId: 'projectId',
+ customJS: 'string',
+ designTags: {},
+ designTagsConfig: {},
+ deviceScaleFactor: 0,
+ displayMode: 'email',
+ editorVersion: 'editorVersion',
+ fullPage: true,
+ height: 0,
+ language: 'language',
+ languages: ['string'],
+ mergeTags: {},
+ mergeTagsSchema: {},
+ safeHtml: true,
+ width: 0,
+ });
+ });
+});
diff --git a/tests/api-resources/templates/export-pdf.test.ts b/tests/api-resources/templates/export-pdf.test.ts
new file mode 100644
index 0000000..8415fd7
--- /dev/null
+++ b/tests/api-resources/templates/export-pdf.test.ts
@@ -0,0 +1,40 @@
+// 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 exportPdf', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.templates.exportPdf.create({ design: {} });
+ 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.exportPdf.create({
+ design: {},
+ projectId: 'projectId',
+ contentWidth: 'full',
+ customJS: 'string',
+ designTags: {},
+ designTagsConfig: {},
+ displayMode: 'email',
+ editorVersion: 'editorVersion',
+ language: 'language',
+ languages: ['string'],
+ mergeTags: {},
+ mergeTagsSchema: {},
+ pageSize: 'Letter',
+ safeHtml: true,
+ });
+ });
+});
diff --git a/tests/api-resources/templates/export-zip.test.ts b/tests/api-resources/templates/export-zip.test.ts
new file mode 100644
index 0000000..3f4366c
--- /dev/null
+++ b/tests/api-resources/templates/export-zip.test.ts
@@ -0,0 +1,38 @@
+// 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 exportZip', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.templates.exportZip.create({ design: {} });
+ 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.exportZip.create({
+ design: {},
+ projectId: 'projectId',
+ customJS: 'string',
+ designTags: {},
+ designTagsConfig: {},
+ displayMode: 'email',
+ editorVersion: 'editorVersion',
+ language: 'language',
+ languages: ['string'],
+ mergeTags: {},
+ mergeTagsSchema: {},
+ safeHtml: true,
+ });
+ });
+});
diff --git a/tests/api-resources/templates/generate.test.ts b/tests/api-resources/templates/generate.test.ts
new file mode 100644
index 0000000..476e271
--- /dev/null
+++ b/tests/api-resources/templates/generate.test.ts
@@ -0,0 +1,94 @@
+// 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: {
+ availableFonts: [{ label: 'x', value: 'x' }],
+ availableTools: ['string'],
+ brand: {
+ colors: {
+ accent: 'accent',
+ primary: 'primary',
+ secondary: 'secondary',
+ },
+ companyName: 'companyName',
+ fonts: { body: 'body', heading: 'heading' },
+ guidelines: 'guidelines',
+ logos: { primary: 'https://example.com', secondary: 'https://example.com' },
+ productDescription: 'productDescription',
+ targetAudience: 'targetAudience',
+ voice: 'voice',
+ },
+ customTools: [
+ {
+ options: { foo: 'bar' },
+ slug: 'slug',
+ },
+ ],
+ fullDesign: { foo: 'bar' },
+ selection: {
+ id: 'string',
+ collection: 'pages',
+ value: 'value',
+ },
+ },
+ conversationId: 'conversationId',
+ fallbackModels: true,
+ 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..2101af0
--- /dev/null
+++ b/tests/api-resources/templates/import.test.ts
@@ -0,0 +1,42 @@
+// 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',
+ fallbackModels: true,
+ model: 'model',
+ });
+ });
+});
diff --git a/tests/api-resources/templates/schema.test.ts b/tests/api-resources/templates/schema.test.ts
new file mode 100644
index 0000000..5241672
--- /dev/null
+++ b/tests/api-resources/templates/schema.test.ts
@@ -0,0 +1,31 @@
+// 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 schema', () => {
+ test('retrieve', async () => {
+ const responsePromise = client.templates.schema.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);
+ });
+
+ test('retrieve: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.templates.schema.retrieve(
+ { displayMode: 'email', simple: true },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+});
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/api-resources/templates/validate.test.ts b/tests/api-resources/templates/validate.test.ts
new file mode 100644
index 0000000..70d9bbb
--- /dev/null
+++ b/tests/api-resources/templates/validate.test.ts
@@ -0,0 +1,40 @@
+// 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 validate', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.templates.validate.create({ design: { foo: 'bar' } });
+ 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.validate.create({
+ design: { foo: 'bar' },
+ customTools: [
+ {
+ options: { foo: { options: {} } },
+ slug: 'slug',
+ label: 'label',
+ supportedDisplayModes: ['email'],
+ type: 'type',
+ values: { foo: 'bar' },
+ },
+ ],
+ displayMode: 'email',
+ migrate: true,
+ schema: 'full',
+ });
+ });
+});
diff --git a/tests/api-resources/webhooks/rotate-secret.test.ts b/tests/api-resources/webhooks/rotate-secret.test.ts
new file mode 100644
index 0000000..f1f7557
--- /dev/null
+++ b/tests/api-resources/webhooks/rotate-secret.test.ts
@@ -0,0 +1,21 @@
+// 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 rotateSecret', () => {
+ test('create', async () => {
+ const responsePromise = client.webhooks.rotateSecret.create('id');
+ 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/webhooks/webhooks.test.ts b/tests/api-resources/webhooks/webhooks.test.ts
new file mode 100644
index 0000000..6505153
--- /dev/null
+++ b/tests/api-resources/webhooks/webhooks.test.ts
@@ -0,0 +1,88 @@
+// 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 webhooks', () => {
+ test('create: only required params', async () => {
+ const responsePromise = client.webhooks.create({ url: 'https://example.com' });
+ 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.webhooks.create({
+ url: 'https://example.com',
+ active: true,
+ events: ['email.sent'],
+ });
+ });
+
+ test('retrieve', async () => {
+ const responsePromise = client.webhooks.retrieve('id');
+ 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('update', async () => {
+ const responsePromise = client.webhooks.update('id');
+ 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('update: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.webhooks.update(
+ 'id',
+ {
+ active: true,
+ events: ['email.sent'],
+ url: 'https://example.com',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Unlayer.NotFoundError);
+ });
+
+ test('list', async () => {
+ const responsePromise = client.webhooks.list();
+ 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('delete', async () => {
+ const responsePromise = client.webhooks.delete('id');
+ 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/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..f16b683 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12,12 +12,12 @@
resolved "https://registry.yarnpkg.com/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz#ba9494f85eb83017c5c855763969caf1d0adea00"
integrity sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==
-"@arethetypeswrong/cli@^0.17.0":
- version "0.17.0"
- resolved "https://registry.yarnpkg.com/@arethetypeswrong/cli/-/cli-0.17.0.tgz#f97f10926b3f9f9eb5117550242d2e06c25cadac"
- integrity sha512-xSMW7bfzVWpYw5JFgZqBXqr6PdR0/REmn3DkxCES5N0JTcB0CVgbIynJCvKBFmXaPc3hzmmTrb7+yPDRoOSZdA==
+"@arethetypeswrong/cli@^0.18.0":
+ version "0.18.4"
+ resolved "https://registry.yarnpkg.com/@arethetypeswrong/cli/-/cli-0.18.4.tgz#c31f54f3b0d0e0f3256ab3edb6530beeb5e64b4b"
+ integrity sha512-kNWo6LTzGAuLYPpJ7Sgo63whSUeeSuKMlYx6IBgzs4ONEG807gW4hSSENvpeCHzO2H2wIzG5EFl0OKBbqGBAyA==
dependencies:
- "@arethetypeswrong/core" "0.17.0"
+ "@arethetypeswrong/core" "0.18.4"
chalk "^4.1.2"
cli-table3 "^0.6.3"
commander "^10.0.1"
@@ -25,15 +25,16 @@
marked-terminal "^7.1.0"
semver "^7.5.4"
-"@arethetypeswrong/core@0.17.0":
- version "0.17.0"
- resolved "https://registry.yarnpkg.com/@arethetypeswrong/core/-/core-0.17.0.tgz#abb3b5f425056d37193644c2a2de4aecf866b76b"
- integrity sha512-FHyhFizXNetigTVsIhqXKGYLpazPS5YNojEPpZEUcBPt9wVvoEbNIvG+hybuBR+pjlRcbyuqhukHZm1fr+bDgA==
+"@arethetypeswrong/core@0.18.4":
+ version "0.18.4"
+ resolved "https://registry.yarnpkg.com/@arethetypeswrong/core/-/core-0.18.4.tgz#24edea3d651dea7d32bf6f1cc9ee9a00db39de49"
+ integrity sha512-M5F0ePyN6h2Z6XxRiyIPqjGbltotXLjR0CKA0uKspsDu0QmgTNYvRb4RSQPMUs2ZXZHCCYpbaZbFbYOXLxCjUA==
dependencies:
"@andrewbranch/untar.js" "^1.0.3"
+ "@loaderkit/resolve" "^1.0.2"
cjs-module-lexer "^1.2.3"
- fflate "^0.8.2"
- lru-cache "^10.4.3"
+ fflate "^0.8.3"
+ lru-cache "^11.0.1"
semver "^7.5.4"
typescript "5.6.1-rc"
validate-npm-package-name "^5.0.0"
@@ -306,6 +307,11 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+"@braidai/lang@^1.0.0":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@braidai/lang/-/lang-1.1.2.tgz#65bc2bc1db6d00e153b95ac7006f4573e289e9be"
+ integrity sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==
+
"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
@@ -688,6 +694,13 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
+"@loaderkit/resolve@^1.0.2":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@loaderkit/resolve/-/resolve-1.0.6.tgz#8d45341e688faecc25b3ae919c0f45d94c4e26c9"
+ integrity sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==
+ dependencies:
+ "@braidai/lang" "^1.0.0"
+
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -709,11 +722,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 +1227,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.4"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.4.tgz#589dab11c0018d0366be64cd8bf12c8dbecc8326"
+ integrity sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==
dependencies:
balanced-match "^1.0.0"
@@ -1395,11 +1395,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 +1523,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 +1674,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"
@@ -1727,10 +1709,10 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
-fflate@^0.8.2:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
- integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
+fflate@^0.8.3:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.3.tgz#bc27d8eb30343d4d512abb03480202ce65d825fc"
+ integrity sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==
file-entry-cache@^8.0.0:
version "8.0.0"
@@ -2521,10 +2503,10 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lru-cache@^10.4.3:
- version "10.4.3"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
- integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
+lru-cache@^11.0.1:
+ version "11.5.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.2.tgz#00e16665c90c620fba14a3c368732a976493f760"
+ integrity sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==
lru-cache@^5.1.1:
version "5.1.1"
@@ -2600,26 +2582,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==
+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 "^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==
- dependencies:
- brace-expansion "^2.0.1"
+ brace-expansion "^2.0.2"
minimist@^1.2.6:
version "1.2.6"
@@ -2868,13 +2836,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 +3132,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 +3205,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"